diff --git a/README.netmap.md b/README.netmap.md index 8fd98af59..ef2edae85 100644 --- a/README.netmap.md +++ b/README.netmap.md @@ -8,9 +8,9 @@ information on netmap. Netmap is available by default on FreeBSD on many architectures, including amd64 and arm64, and is easy to add to the kernel config on architectures where -it is not built by default. While netmap has been ported to Linux, ZMap's -netmap mode currently only supports FreeBSD and will require porting to build -and run on Linux. +it is not built by default. On Linux, netmap itself and netmap-aware drivers +can be installed by following the instructions in +[netmap/LINUX/README.md](https://github.com/luigirizzo/netmap/blob/master/LINUX/README.md). ### Prerequisites diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e77ef9075..e6b52a5f6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,6 +124,13 @@ if(WITH_PFRING) elseif(WITH_NETMAP) set(SOURCES ${SOURCES} socket-netmap.c send-netmap.c) set(ZTESTSOURCES ${ZTESTSOURCES} socket-netmap.c send-netmap.c) + if(APPLE OR BSD) + set(SOURCES ${SOURCES} if-netmap-bsd.c) + set(ZTESTSOURCES ${ZTESTSOURCES} if-netmap-bsd.c) + else() + set(SOURCES ${SOURCES} if-netmap-linux.c) + set(ZTESTSOURCES ${ZTESTSOURCES} if-netmap-linux.c) + endif() elseif (APPLE OR BSD) set(SOURCES ${SOURCES} socket-bsd.c send-bsd.c) set(ZTESTSOURCES ${ZTESTSOURCES} socket-bsd.c send-bsd.c) diff --git a/src/if-netmap-bsd.c b/src/if-netmap-bsd.c new file mode 100644 index 000000000..278cbc45c --- /dev/null +++ b/src/if-netmap-bsd.c @@ -0,0 +1,141 @@ +/* + * ZMap Copyright 2013 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +#ifndef __FreeBSD__ +#error "NETMAP requires FreeBSD or Linux" +#endif + +#include "if-netmap.h" + +#include "../lib/includes.h" +#include "../lib/logger.h" + +#include +#include +#include +#include +#include +#include +#include + +static void +fetch_if_data(struct if_data *ifd, char const *ifname, int fd) +{ + struct ifreq ifr; + bzero(&ifr, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + ifr.ifr_data = (caddr_t)ifd; + if (ioctl(fd, SIOCGIFDATA, &ifr) == -1) { + log_fatal("if-netmap-bsd", "unable to retrieve if_data: %d: %s", + errno, strerror(errno)); + } +} + +void +if_wait_for_phy_reset(char const *ifname, int fd) +{ + struct if_data ifd; + bzero(&ifd, sizeof(ifd)); + for (size_t i = 0; i < 40 /* 10s */; i++) { + fetch_if_data(&ifd, ifname, fd); + if (ifd.ifi_link_state == LINK_STATE_UP) { + return; + } + usleep(250000); + } + log_fatal("if-netmap-bsd", "timeout waiting for PHY reset to complete"); +} + +size_t +if_get_data_link_size(char const *ifname, int fd) +{ + struct if_data ifd; + bzero(&ifd, sizeof(ifd)); + fetch_if_data(&ifd, ifname, fd); + + switch (ifd.ifi_type) { + case IFT_ETHER: + log_debug("if-netmap-bsd", "IFT_ETHER"); + return sizeof(struct ether_header); + default: + log_fatal("if-netmap-bsd", "Unsupported if type %u", ifd.ifi_type); + } +} + +// Notes on if counters: +// On interfaces without hardware counters (HWSTATS), ipackets misses +// packets that we do not forward to the host ring pair. +// oqdrops counts packets the host OS could not send due to netmap mode. + +struct if_stats_ctx { + char *ifname; // owned + int fd; // borrowed + bool hwstats; + uint64_t ifi_ipackets; + uint64_t ifi_iqdrops; + uint64_t ifi_ierrors; + uint64_t ifi_oerrors; +}; + +if_stats_ctx_t * +if_stats_init(char const *ifname, int fd) +{ + if_stats_ctx_t *ctx = malloc(sizeof(struct if_stats_ctx)); + bzero(ctx, sizeof(struct if_stats_ctx)); + + ctx->ifname = strdup(ifname); + ctx->fd = fd; + + struct if_data ifd; + bzero(&ifd, sizeof(ifd)); + fetch_if_data(&ifd, ctx->ifname, ctx->fd); + + ctx->hwstats = (ifd.ifi_hwassist & IFCAP_HWSTATS) != 0; + if (ctx->hwstats) { + ctx->ifi_ipackets = ifd.ifi_ipackets; + } else { + ctx->ifi_ipackets = 0; + } + ctx->ifi_iqdrops = ifd.ifi_iqdrops; + ctx->ifi_ierrors = ifd.ifi_ierrors; + ctx->ifi_oerrors = ifd.ifi_oerrors; + return ctx; +} + +void +if_stats_fini(if_stats_ctx_t *ctx) +{ + free(ctx->ifname); + free(ctx); +} + +bool +if_stats_have_recv_ctr(if_stats_ctx_t *ctx) +{ + return ctx->hwstats; +} + +int +if_stats_get(if_stats_ctx_t *ctx, uint32_t *ps_recv, uint32_t *ps_drop, uint32_t *ps_ifdrop) +{ + struct if_data ifd; + bzero(&ifd, sizeof(ifd)); + fetch_if_data(&ifd, ctx->ifname, ctx->fd); + + if (ctx->hwstats) { + *ps_recv = (uint32_t)(ifd.ifi_ipackets - ctx->ifi_ipackets); + } + *ps_drop = (uint32_t)(ifd.ifi_iqdrops - ctx->ifi_iqdrops); + *ps_ifdrop = (uint32_t)(ifd.ifi_ierrors - ctx->ifi_ierrors + + ifd.ifi_oerrors - ctx->ifi_oerrors); + return 0; +} + + + + diff --git a/src/if-netmap-linux.c b/src/if-netmap-linux.c new file mode 100644 index 000000000..4af87f169 --- /dev/null +++ b/src/if-netmap-linux.c @@ -0,0 +1,223 @@ +/* + * ZMap Copyright 2013 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +#include "if-netmap.h" + +#include "../lib/includes.h" +#include "../lib/logger.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int +nlrt_socket(void) +{ + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd == -1) { + log_fatal("if-netmap-linux", "socket(NETLINK_ROUTE): %d: %s", errno, strerror(errno)); + } + + int one = 1; + (void)setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &one, sizeof(one)); + + struct sockaddr_nl sanl; + memset(&sanl, 0, sizeof(sanl)); + sanl.nl_family = AF_NETLINK; + + if (bind(fd, (struct sockaddr *)&sanl, sizeof(sanl)) == -1) { + log_fatal("if-netmap-linux", "bind(AF_NETLINK): %d: %s", errno, strerror(errno)); + } + + return fd; +} + +static void +fetch_stats64(struct rtnl_link_stats64 *rtlstats64, char const *ifname, int nlrtfd) +{ + struct { + struct nlmsghdr nlh; + struct if_stats_msg ifsm; + } nlreq; + memset(&nlreq, 0, sizeof(nlreq)); + nlreq.nlh.nlmsg_len = sizeof(nlreq); + nlreq.nlh.nlmsg_type = RTM_GETSTATS; + nlreq.nlh.nlmsg_flags = NLM_F_REQUEST; + nlreq.ifsm.ifindex = if_nametoindex(ifname); + nlreq.ifsm.filter_mask = IFLA_STATS_LINK_64; + + struct iovec iov[2]; + memset(&iov[0], 0, sizeof(iov[0])); + iov[0].iov_base = (void *)&nlreq; + iov[0].iov_len = sizeof(nlreq); + + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov[0]; + msg.msg_iovlen = 1; + + if (sendmsg(nlrtfd, &msg, 0) == -1) { + log_fatal("if-netmap-linux", "sendmsg(RTM_GETSTATS): %d: %s", errno, strerror(errno)); + } + + struct nlresp { + struct nlmsghdr nlh; + union { + struct { + struct rtmsg rth; + struct rtnl_link_stats64 rtlstats64; + } ans; + struct { + struct nlmsgerr nlerr; + } err; + }; + } nlresp; + _Static_assert(sizeof(nlresp.ans) >= sizeof(nlresp.err)); + static const size_t ans_size = offsetof(struct nlresp, ans) + sizeof(nlresp.ans); + static const size_t err_size = offsetof(struct nlresp, err) + sizeof(nlresp.err); + + memset(iov, 0, sizeof(iov)); + iov[0].iov_base = (void *)&nlresp; + iov[0].iov_len = offsetof(struct nlresp, ans.rtlstats64); + iov[1].iov_base = (void *)rtlstats64; // caller-provided + iov[1].iov_len = sizeof(struct rtnl_link_stats64); + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + + ssize_t n = recvmsg(nlrtfd, &msg, 0); + if (n == -1) { + log_fatal("if-netmap-linux", "recvmsg(RTM_GETSTATS): %d: %s", errno, strerror(errno)); + } + if ((size_t)n < err_size) { + log_fatal("if-netmap-linux", "received %zu expected %zu or larger", (size_t)n, err_size); + } + + if (nlresp.nlh.nlmsg_type == NLMSG_ERROR) { + // copy second iov into ans in first iov to get contiguous struct nlmsgerr + nlresp.ans.rtlstats64 = *rtlstats64; + assert(nlresp.err.nlerr.error < 0); + errno = -nlresp.err.nlerr.error; + log_fatal("if-netmap-linux", "received NLMSG_ERROR: %d: %s", errno, strerror(errno)); + } + if (nlresp.nlh.nlmsg_type != RTM_NEWSTATS) { + log_fatal("if-netmap-linux", "received unexpected nlmsg_type %u", nlresp.nlh.nlmsg_type); + } + if ((size_t)n != ans_size) { + log_fatal("if-netmap-linux", "received %zu expected %zu", (size_t)n, ans_size); + } +} + +void +if_wait_for_phy_reset(char const *ifname, int fd) +{ + // clobber deliberately + fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (fd == -1) { + log_fatal("if-netmap-linux", "socket(AF_INET): %d: %s", errno, strerror(errno)); + } + + for (size_t i = 0; i < 40 /* 10s */; i++) { + struct ifreq ifr; + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + struct ethtool_value etv; + etv.cmd = ETHTOOL_GLINK; + ifr.ifr_data = (void *)&etv; + if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) { + log_fatal("if-netmap-linux", "ioctl(SIOCETHTOOL): %d: %s", errno, strerror(errno)); + } + if (etv.data != 0 /* carrier */) { + close(fd); + return; + } + usleep(250000); + } + log_fatal("if-netmap-linux", "timeout waiting for PHY reset to complete"); +} + +size_t +if_get_data_link_size(UNUSED char const *ifname, UNUSED int fd) +{ + // Assuming Ethernet is not entirely unreasonable, as that's + // the only thing we support on the send path anyway. + // TODO figure out actual link type or link header size + return sizeof(struct ether_header); +} + +struct if_stats_ctx { + char *ifname; // owned + int nlrtfd; // owned + // uint64_t rx_packets; + uint64_t rx_dropped; + uint64_t rx_errors; + uint64_t tx_errors; +}; + +if_stats_ctx_t * +if_stats_init(char const *ifname, UNUSED int fd) +{ + if_stats_ctx_t *ctx = malloc(sizeof(struct if_stats_ctx)); + memset(ctx, 0, sizeof(struct if_stats_ctx)); + + ctx->ifname = strdup(ifname); + ctx->nlrtfd = nlrt_socket(); + + struct rtnl_link_stats64 rtlstats64; + memset(&rtlstats64, 0, sizeof(rtlstats64)); + fetch_stats64(&rtlstats64, ctx->ifname, ctx->nlrtfd); + + //ctx->rx_packets = rtlstats64.rx_packets; + ctx->rx_dropped = rtlstats64.rx_dropped; + ctx->rx_errors = rtlstats64.rx_errors; + ctx->tx_errors = rtlstats64.tx_errors; + return ctx; +} + +void +if_stats_fini(if_stats_ctx_t *ctx) +{ + free(ctx->ifname); + close(ctx->nlrtfd); + free(ctx); +} + +bool +if_stats_have_recv_ctr(UNUSED if_stats_ctx_t *ctx) +{ + return false; +} + +int +if_stats_get(if_stats_ctx_t *ctx, UNUSED uint32_t *ps_recv, uint32_t *ps_drop, uint32_t *ps_ifdrop) +{ + struct rtnl_link_stats64 rtlstats64; + memset(&rtlstats64, 0, sizeof(rtlstats64)); + fetch_stats64(&rtlstats64, ctx->ifname, ctx->nlrtfd); + + //*ps_recv = (uint32_t)(rtlstats64.rx_packets - ctx->rx_packets); + *ps_drop = (uint32_t)(rtlstats64.rx_dropped - ctx->rx_dropped); + *ps_ifdrop = (uint32_t)(rtlstats64.rx_errors - ctx->rx_errors + + rtlstats64.tx_errors - ctx->tx_errors); + return 0; +} diff --git a/src/if-netmap.h b/src/if-netmap.h new file mode 100644 index 000000000..fc200e24b --- /dev/null +++ b/src/if-netmap.h @@ -0,0 +1,57 @@ +/* + * ZMap Copyright 2013 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +#ifndef ZMAP_IF_NETMAP_H +#define ZMAP_IF_NETMAP_H + +// Platform-specific functionality required for NETMAP. + +#include +#include +#include + +// Wait until a NICs PHY has reset and the interface is ready for sending +// packets again. Must be called after the reset has begun. Upon return, the +// interface is ready for sending packets. Exits on timeout. +// +// *ifname* is the name of the interface. +// *fd* is the file descriptor to the main netmap socket. +void if_wait_for_phy_reset(char const *ifname, int fd); + +// Get the size of the link layer header for the interface. +// +// *ifname* is the name of the interface. +// *fd* is the file descriptor to the main netmap socket. +size_t if_get_data_link_size(char const *ifname, int fd); + +// Opaque context for the if_stats_* set of functions. +struct if_stats_ctx; +typedef struct if_stats_ctx if_stats_ctx_t; + +// Initialise interface statistics. +// +// *ifname* is the name of the interface. +// *fd* is the file descriptor to the netmap socket used for recv. +if_stats_ctx_t * if_stats_init(char const *ifname, int fd); + +// Returns true if the count of received packets is available +// through if_stats_get(), false otherwise. If this returns +// false, the caller will need to count received packets. +bool if_stats_have_recv_ctr(if_stats_ctx_t *ctx); + +// Get recv, drop and ifdrop counters. +// Some interfaces do not report any received packets while in +// netmap mode. In that case, *ps_recv* will not be set. +// Check if_stats_have_recv_ctr() for whether the interface +// supports received packet count in netmap mode. +int if_stats_get(if_stats_ctx_t *ctx, uint32_t *ps_recv, uint32_t *ps_drop, uint32_t *ps_ifdrop); + +// Clean up and invalidate the if_stats_* context. +void if_stats_fini(if_stats_ctx_t *ctx); + +#endif /* ZMAP_IF_NETMAP_H */ diff --git a/src/recv-netmap.c b/src/recv-netmap.c index d4b097bce..830bb0f18 100644 --- a/src/recv-netmap.c +++ b/src/recv-netmap.c @@ -6,8 +6,8 @@ * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ -#ifndef __FreeBSD__ -#error "NETMAP is only currently supported on FreeBSD" +#if !(defined(__FreeBSD__) || defined(__linux__)) +#error "NETMAP requires FreeBSD or Linux" #endif #include "recv.h" @@ -16,12 +16,13 @@ #include "send.h" #include "send-internal.h" #include "probe_modules/packet.h" +#include "if-netmap.h" +#include "state.h" #include "../lib/includes.h" #include "../lib/logger.h" #include -#include #include #include #include @@ -32,94 +33,13 @@ #include #include -#include "state.h" - -static void -fetch_if_data(struct if_data *ifd) -{ - struct ifreq ifr; - bzero(&ifr, sizeof(ifr)); - strlcpy(ifr.ifr_name, zconf.iface, sizeof(ifr.ifr_name)); - ifr.ifr_data = (caddr_t)ifd; - if (ioctl(zconf.nm.nm_fd, SIOCGIFDATA, &ifr) == -1) { - log_fatal("recv-netmap", "unable to retrieve if_data: %d: %s", - errno, strerror(errno)); - } -} - -static size_t -data_link_size_from_if_type(unsigned char if_type) -{ - switch (if_type) { - case IFT_ETHER: - log_debug("recv-netmap", "IFT_ETHER"); - return sizeof(struct ether_header); - case IFT_LOOP: - log_debug("recv-netmap", "IFT_LOOP"); - return 4; - default: - log_fatal("recv-netmap", "Unknown if_type: %u", if_type); - } -} - -static size_t -fetch_data_link_size(void) -{ - struct if_data ifd; - bzero(&ifd, sizeof(ifd)); - fetch_if_data(&ifd); - return data_link_size_from_if_type(ifd.ifi_type); -} - -static struct { - bool initialized; - bool hwstats; - uint64_t ifi_ipackets; - uint64_t ifi_iqdrops; - uint64_t ifi_ierrors; - uint64_t ifi_oerrors; -} stats; - -static int -fetch_stats(uint32_t *ps_recv, uint32_t *ps_drop, uint32_t *ps_ifdrop) -{ - // Notes on if counters: - // On interfaces without hardware counters (HWSTATS), ipackets misses - // packets that we do not forward to the host ring pair. - // oqdrops counts packets the host OS could not send due to netmap mode. - struct if_data ifd; - bzero(&ifd, sizeof(ifd)); - fetch_if_data(&ifd); - - if (!stats.initialized) { - assert(!ps_recv && !ps_drop && !ps_ifdrop); - stats.initialized = true; - stats.hwstats = (ifd.ifi_hwassist & IFCAP_HWSTATS) != 0; - if (stats.hwstats) { - stats.ifi_ipackets = ifd.ifi_ipackets; - } else { - stats.ifi_ipackets = 0; - } - stats.ifi_iqdrops = ifd.ifi_iqdrops; - stats.ifi_ierrors = ifd.ifi_ierrors; - stats.ifi_oerrors = ifd.ifi_oerrors; - } else { - if (stats.hwstats) { - *ps_recv = (uint32_t)(ifd.ifi_ipackets - stats.ifi_ipackets); - } else { - *ps_recv = (uint32_t)stats.ifi_ipackets; - } - *ps_drop = (uint32_t)(ifd.ifi_iqdrops - stats.ifi_iqdrops); - *ps_ifdrop = (uint32_t)(ifd.ifi_ierrors - stats.ifi_ierrors + - ifd.ifi_oerrors - stats.ifi_oerrors); - } - return 0; -} - static struct pollfd fds; static struct netmap_if *nm_if; static bool *in_multi_seg_packet; static void (*handle_packet_func)(uint32_t buflen, const uint8_t *bytes, const struct timespec ts); +static if_stats_ctx_t *stats_ctx; +static bool need_recv_counter; +static uint64_t recv_counter; static void handle_packet_wait_ping(uint32_t buflen, const uint8_t *bytes, UNUSED const struct timespec ts) @@ -260,7 +180,7 @@ void recv_init(void) in_multi_seg_packet[ri] = false; } - zconf.data_link_size = fetch_data_link_size(); + zconf.data_link_size = if_get_data_link_size(zconf.iface, zconf.nm.nm_fd); log_debug("recv-netmap", "data_link_size %d", zconf.data_link_size); if (zconf.nm.wait_ping_dstip != 0) { @@ -270,27 +190,43 @@ void recv_init(void) handle_packet_func = handle_packet; } - if (fetch_stats(NULL, NULL, NULL) == -1) { - log_fatal("recv-netmap", "Failed to fetch initial interface counters"); + stats_ctx = if_stats_init(zconf.iface, zconf.nm.nm_fd); + assert(stats_ctx); + need_recv_counter = !if_stats_have_recv_ctr(stats_ctx); + if (need_recv_counter) { + recv_counter = 0; } } -void recv_cleanup(void) +void +recv_cleanup(void) { + if_stats_fini(stats_ctx); + stats_ctx = NULL; free(in_multi_seg_packet); in_multi_seg_packet = NULL; nm_if = NULL; } -void recv_packets(void) +void +recv_packets(void) { - int ret = poll(&fds, 1, 100 /* ms */); - if (ret == 0) { - return; - } - else if (ret == -1) { - log_error("recv-netmap", "poll(POLLIN) failed: %d: %s", errno, strerror(errno)); - return; + // On Linux, EINTR seems to happen here once at startup. + // Haven't seen any EINTR on FreeBSD. Retry is not wrong + // and making the total delay longer should not hurt. + // We may want to look into the root cause some time tho. + for (ssize_t retry = 5; retry >= 0; retry--) { + int ret = poll(&fds, 1, 100 /* ms */); + if (ret > 0) { + break; + } else if (ret == 0) { + return; + } else if (errno != EINTR || retry == 0) { + log_error("recv-netmap", "poll(POLLIN) failed: %d: %s", errno, strerror(errno)); + return; + } else { + log_debug("recv-netmap", "poll(POLLIN) failed: %d: %s (retrying)", errno, strerror(errno)); + } } for (unsigned int ri = 0; ri < nm_if->ni_rx_rings; ri++) { @@ -337,8 +273,8 @@ void recv_packets(void) struct timespec ts; ts.tv_sec = rxring->ts.tv_sec; ts.tv_nsec = rxring->ts.tv_usec * 1000; - if (!stats.hwstats) { - stats.ifi_ipackets++; + if (need_recv_counter) { + recv_counter++; } handle_packet_func(slot->len, (uint8_t *)buf, ts); } @@ -361,12 +297,15 @@ void recv_packets(void) int recv_update_stats(void) { - if (!stats.initialized) { + if (!stats_ctx) { return EXIT_FAILURE; } - if (fetch_stats(&zrecv.pcap_recv, &zrecv.pcap_drop, &zrecv.pcap_ifdrop) == -1) { + if (if_stats_get(stats_ctx, &zrecv.pcap_recv, &zrecv.pcap_drop, &zrecv.pcap_ifdrop) == -1) { return EXIT_FAILURE; } + if (need_recv_counter) { + zrecv.pcap_recv = (uint32_t)recv_counter; + } return EXIT_SUCCESS; } diff --git a/src/send-netmap.c b/src/send-netmap.c index 409e9253a..b101ad9a6 100644 --- a/src/send-netmap.c +++ b/src/send-netmap.c @@ -6,8 +6,8 @@ * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ -#ifndef __FreeBSD__ -#error "NETMAP is only currently supported on FreeBSD" +#if !(defined(__FreeBSD__) || defined(__linux__)) +#error "NETMAP requires FreeBSD or Linux" #endif #include "send.h" diff --git a/src/socket-netmap.c b/src/socket-netmap.c index ae62993df..85c48212c 100644 --- a/src/socket-netmap.c +++ b/src/socket-netmap.c @@ -6,8 +6,8 @@ * of the License at http://www.apache.org/licenses/LICENSE-2.0 */ -#ifndef __FreeBSD__ -#error "NETMAP is only currently supported on FreeBSD" +#if !(defined(__FreeBSD__) || defined(__linux__)) +#error "NETMAP requires FreeBSD or Linux" #endif #include "socket.h" @@ -38,12 +38,12 @@ sock_t get_socket(uint32_t id) } struct nmreq_register nmrreg; - bzero(&nmrreg, sizeof(nmrreg)); + memset(&nmrreg, 0, sizeof(nmrreg)); nmrreg.nr_ringid = sock.nm.tx_ring_idx; nmrreg.nr_mode = NR_REG_ONE_NIC; nmrreg.nr_flags = NR_TX_RINGS_ONLY | NR_NO_TX_POLL; struct nmreq_header nmrhdr; - bzero(&nmrhdr, sizeof(nmrhdr)); + memset(&nmrhdr, 0, sizeof(nmrhdr)); nmrhdr.nr_version = NETMAP_API; nmrhdr.nr_reqtype = NETMAP_REQ_REGISTER; strlcpy(nmrhdr.nr_name, zconf.iface, sizeof(nmrhdr.nr_name)); diff --git a/src/zmap.c b/src/zmap.c index 167cd98fe..4f0fca402 100644 --- a/src/zmap.c +++ b/src/zmap.c @@ -60,9 +60,10 @@ static int32_t distrib_func(pfring_zc_pkt_buff *pkt, pfring_zc_queue *in_queue, #endif #ifdef NETMAP -#ifndef __FreeBSD__ -#error "NETMAP is only currently supported on FreeBSD" +#if !(defined(__FreeBSD__) || defined(__linux__)) +#error "NETMAP requires FreeBSD or Linux" #endif +#include "if-netmap.h" #include #include #include @@ -985,11 +986,11 @@ int main(int argc, char *argv[]) } struct nmreq_register nmrreg; - bzero(&nmrreg, sizeof(nmrreg)); + memset(&nmrreg, 0, sizeof(nmrreg)); nmrreg.nr_mode = NR_REG_ALL_NIC; nmrreg.nr_flags = NR_NO_TX_POLL; struct nmreq_header nmrhdr; - bzero(&nmrhdr, sizeof(nmrhdr)); + memset(&nmrhdr, 0, sizeof(nmrhdr)); nmrhdr.nr_version = NETMAP_API; nmrhdr.nr_reqtype = NETMAP_REQ_REGISTER; strlcpy(nmrhdr.nr_name, zconf.iface, sizeof(nmrhdr.nr_name)); @@ -1026,26 +1027,8 @@ int main(int argc, char *argv[]) // on physical NICs can take multiple seconds to complete. // To avoid dropping packets while the reset is ongoing, // wait for the interface to come back up here. - log_debug("zmap", "waiting max 10s for PHY reset to complete"); - struct if_data ifd; - bzero(&ifd, sizeof(ifd)); - struct ifreq ifr; - bzero(&ifr, sizeof(ifr)); - strlcpy(ifr.ifr_name, zconf.iface, sizeof(ifr.ifr_name)); - ifr.ifr_data = (caddr_t)&ifd; - for (size_t i = 0; i < 40; i++) { - if (ioctl(zconf.nm.nm_fd, SIOCGIFDATA, &ifr) == -1) { - log_fatal("zmap", "unable to retrieve if_data: %d: %s", - errno, strerror(errno)); - } - if (ifd.ifi_link_state == LINK_STATE_UP) { - break; - } - usleep(250000); - } - if (ifd.ifi_link_state != LINK_STATE_UP) { - log_fatal("zmap", "timeout waiting for PHY reset to complete"); - } + log_debug("zmap", "waiting for PHY reset to complete"); + if_wait_for_phy_reset(zconf.iface, zconf.nm.nm_fd); log_debug("zmap", "PHY reset is complete, link state is up"); if (args.netmap_wait_ping_arg != NULL) {