<commit_before>#include <fcntl.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <unistd.h>
#include <xmmintrin.h>

#ifdef __linux__
#include <netinet/ether.h>
#else
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <sys/types.h>
#endif

#include "arp.h"
#include "plat.h"
#include "util.h"
#include "version.h"
#include "warpcore_internal.h"

/// The backend name.
///
static char backend_name[] = "netmap";


/// Initialize the warpcore netmap backend for engine @p w. This switches the
/// interface to netmap mode, maps the underlying buffers into memory and locks
/// it there, and sets up the extra buffers.
///
/// @param      w       Warpcore engine.
/// @param[in]  ifname  The OS name of the interface (e.g., "eth0").
///
void backend_init(struct warpcore * w, const char * const ifname)
{
    // open /dev/netmap
    assert((w->fd = open("/dev/netmap", O_RDWR)) != -1,
           "cannot open /dev/netmap");

    // switch interface to netmap mode
    strncpy(w->req.nr_name, ifname, sizeof w->req.nr_name);
    w->req.nr_name[sizeof w->req.nr_name - 1] = '\0';
    w->req.nr_version = NETMAP_API;
    w->req.nr_ringid &= ~NETMAP_RING_MASK;
    // don't always transmit on poll
    w->req.nr_ringid |= NETMAP_NO_TX_POLL;
    w->req.nr_flags = NR_REG_ALL_NIC;
    w->req.nr_arg3 = NUM_BUFS; // request extra buffers
    assert(ioctl(w->fd, NIOCREGIF, &w->req) != -1,
           "%s: cannot put interface into netmap mode", ifname);

    // mmap the buffer region
    // TODO: see TODO in nm_open() in netmap_user.h
    const int flags = PLAT_MMFLAGS;
    assert((w->mem = mmap(0, w->req.nr_memsize, PROT_WRITE | PROT_READ,
                          MAP_SHARED | flags, w->fd, 0)) != MAP_FAILED,
           "cannot mmap netmap memory");

    // direct pointer to the netmap interface struct for convenience
    w->nif = NETMAP_IF(w->mem, w->req.nr_offset);

#ifndef NDEBUG
    // print some info about our rings
    for (uint32_t ri = 0; ri < w->nif->ni_tx_rings; ri++) {
        const struct netmap_ring * const r = NETMAP_TXRING(w->nif, ri);
        warn(info, "tx ring %d has %d slots (%d-%d)", ri, r->num_slots,
             r->slot[0].buf_idx, r->slot[r->num_slots - 1].buf_idx);
    }
    for (uint32_t ri = 0; ri < w->nif->ni_rx_rings; ri++) {
        const struct netmap_ring * const r = NETMAP_RXRING(w->nif, ri);
        warn(info, "rx ring %d has %d slots (%d-%d)", ri, r->num_slots,
             r->slot[0].buf_idx, r->slot[r->num_slots - 1].buf_idx);
    }
#endif

    // save the indices of the extra buffers in the warpcore structure
    STAILQ_INIT(&w->iov);
    for (uint32_t n = 0, i = w->nif->ni_bufs_head; n < w->req.nr_arg3; n++) {
        struct w_iov * const v = calloc(1, sizeof(struct w_iov));
        assert(v != 0, "cannot allocate w_iov");
        v->buf = IDX2BUF(w, i);
        v->idx = i;
        STAILQ_INSERT_HEAD(&w->iov, v, next);
        i = *(uint32_t *)v->buf;
    }

    if (w->req.nr_arg3 != NUM_BUFS)
        die("can only allocate %d/%d extra buffers", w->req.nr_arg3, NUM_BUFS);
    else
        warn(notice, "allocated %d extra buffers", w->req.nr_arg3);

    // lock memory
    assert(mlockall(MCL_CURRENT | MCL_FUTURE) != -1, "mlockall");

    w->backend = backend_name;
}


/// Helper function for w_cleanup() that links together extra bufs allocated by
/// netmap in the strange format it requires to free them correctly.
///
/// @param[in]  w     Warpcore engine.
/// @param[in]  v     w_iov chain to link together for netmap.
///
/// @return     Last element of the linked w_iov chain.
///
static const struct w_iov * __attribute__((nonnull))
w_chain_extra_bufs(const struct warpcore * const w, const struct w_iov * v)
{
    const struct w_iov * n;
    do {
        n = STAILQ_NEXT(v, next);
        uint32_t * const buf = (void *)IDX2BUF(w, v->idx);
        if (n) {
            *buf = n->idx;
            v = n;
        } else
            *buf = 0;
    } while (n);

    // return the last list element
    return v;
}


/// Shut a warpcore netmap engine down cleanly. This function pushes out all
/// buffers already placed into TX rings, and returns all w_iov structures
/// associated with all w_sock structures of the engine to netmap.
///
/// @param      w     Warpcore engine.
///
void __attribute__((nonnull)) backend_cleanup(struct warpcore * const w)
{
    // clean out all the tx rings
    for (uint32_t i = 0; i < w->nif->ni_rx_rings; i++) {
        struct netmap_ring * const txr = NETMAP_TXRING(w->nif, w->cur_txr);
        while (nm_tx_pending(txr)) {
            warn(info, "tx pending on ring %u", w->cur_txr);
            w_kick_tx(w);
            usleep(1); // wait 1 tick
        }
    }

    // re-construct the extra bufs list, so netmap can free the memory
    const struct w_iov * last = w_chain_extra_bufs(w, STAILQ_FIRST(&w->iov));
    struct w_sock * s;
    SLIST_FOREACH (s, &w->sock, next) {
        if (!STAILQ_EMPTY(&s->iv)) {
            const struct w_iov * const l =
                w_chain_extra_bufs(w, STAILQ_FIRST(&s->iv));
            *(uint32_t *)(last->buf) = STAILQ_FIRST(&s->iv)->idx;
            last = l;
        }
        if (!STAILQ_EMPTY(&s->ov)) {
            const struct w_iov * const lov =
                w_chain_extra_bufs(w, STAILQ_FIRST(&s->ov));
            *(uint32_t *)(last->buf) = STAILQ_FIRST(&s->ov)->idx;
            last = lov;
        }
        *(uint32_t *)(last->buf) = 0;
    }
    w->nif->ni_bufs_head = STAILQ_FIRST(&w->iov)->idx;

    assert(munmap(w->mem, w->req.nr_memsize) != -1,
           "cannot munmap netmap memory");
<commit_msg>Don't clear out rings at exit, serves no purpose<commit_after>#include <fcntl.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <unistd.h>
#include <xmmintrin.h>

#ifdef __linux__
#include <netinet/ether.h>
#else
#include <net/ethernet.h>
#include <net/if_dl.h>
#include <sys/types.h>
#endif

#include "arp.h"
#include "plat.h"
#include "util.h"
#include "version.h"
#include "warpcore_internal.h"

/// The backend name.
///
static char backend_name[] = "netmap";


/// Initialize the warpcore netmap backend for engine @p w. This switches the
/// interface to netmap mode, maps the underlying buffers into memory and locks
/// it there, and sets up the extra buffers.
///
/// @param      w       Warpcore engine.
/// @param[in]  ifname  The OS name of the interface (e.g., "eth0").
///
void backend_init(struct warpcore * w, const char * const ifname)
{
    // open /dev/netmap
    assert((w->fd = open("/dev/netmap", O_RDWR)) != -1,
           "cannot open /dev/netmap");

    // switch interface to netmap mode
    strncpy(w->req.nr_name, ifname, sizeof w->req.nr_name);
    w->req.nr_name[sizeof w->req.nr_name - 1] = '\0';
    w->req.nr_version = NETMAP_API;
    w->req.nr_ringid &= ~NETMAP_RING_MASK;
    // don't always transmit on poll
    w->req.nr_ringid |= NETMAP_NO_TX_POLL;
    w->req.nr_flags = NR_REG_ALL_NIC;
    w->req.nr_arg3 = NUM_BUFS; // request extra buffers
    assert(ioctl(w->fd, NIOCREGIF, &w->req) != -1,
           "%s: cannot put interface into netmap mode", ifname);

    // mmap the buffer region
    // TODO: see TODO in nm_open() in netmap_user.h
    const int flags = PLAT_MMFLAGS;
    assert((w->mem = mmap(0, w->req.nr_memsize, PROT_WRITE | PROT_READ,
                          MAP_SHARED | flags, w->fd, 0)) != MAP_FAILED,
           "cannot mmap netmap memory");

    // direct pointer to the netmap interface struct for convenience
    w->nif = NETMAP_IF(w->mem, w->req.nr_offset);

#ifndef NDEBUG
    // print some info about our rings
    for (uint32_t ri = 0; ri < w->nif->ni_tx_rings; ri++) {
        const struct netmap_ring * const r = NETMAP_TXRING(w->nif, ri);
        warn(info, "tx ring %d has %d slots (%d-%d)", ri, r->num_slots,
             r->slot[0].buf_idx, r->slot[r->num_slots - 1].buf_idx);
    }
    for (uint32_t ri = 0; ri < w->nif->ni_rx_rings; ri++) {
        const struct netmap_ring * const r = NETMAP_RXRING(w->nif, ri);
        warn(info, "rx ring %d has %d slots (%d-%d)", ri, r->num_slots,
             r->slot[0].buf_idx, r->slot[r->num_slots - 1].buf_idx);
    }
#endif

    // save the indices of the extra buffers in the warpcore structure
    STAILQ_INIT(&w->iov);
    for (uint32_t n = 0, i = w->nif->ni_bufs_head; n < w->req.nr_arg3; n++) {
        struct w_iov * const v = calloc(1, sizeof(struct w_iov));
        assert(v != 0, "cannot allocate w_iov");
        v->buf = IDX2BUF(w, i);
        v->idx = i;
        STAILQ_INSERT_HEAD(&w->iov, v, next);
        i = *(uint32_t *)v->buf;
    }

    if (w->req.nr_arg3 != NUM_BUFS)
        die("can only allocate %d/%d extra buffers", w->req.nr_arg3, NUM_BUFS);
    else
        warn(notice, "allocated %d extra buffers", w->req.nr_arg3);

    // lock memory
    assert(mlockall(MCL_CURRENT | MCL_FUTURE) != -1, "mlockall");

    w->backend = backend_name;
}


/// Helper function for w_cleanup() that links together extra bufs allocated by
/// netmap in the strange format it requires to free them correctly.
///
/// @param[in]  w     Warpcore engine.
/// @param[in]  v     w_iov chain to link together for netmap.
///
/// @return     Last element of the linked w_iov chain.
///
static const struct w_iov * __attribute__((nonnull))
w_chain_extra_bufs(const struct warpcore * const w, const struct w_iov * v)
{
    const struct w_iov * n;
    do {
        n = STAILQ_NEXT(v, next);
        uint32_t * const buf = (void *)IDX2BUF(w, v->idx);
        if (n) {
            *buf = n->idx;
            v = n;
        } else
            *buf = 0;
    } while (n);

    // return the last list element
    return v;
}


/// Shut a warpcore netmap engine down cleanly. This function  returns all w_iov
/// structures associated with all w_sock structures of the engine to netmap.
///
/// @param      w     Warpcore engine.
///
void __attribute__((nonnull)) backend_cleanup(struct warpcore * const w)
{
    // re-construct the extra bufs list, so netmap can free the memory
    const struct w_iov * last = w_chain_extra_bufs(w, STAILQ_FIRST(&w->iov));
    struct w_sock * s;
    SLIST_FOREACH (s, &w->sock, next) {
        if (!STAILQ_EMPTY(&s->iv)) {
            const struct w_iov * const l =
                w_chain_extra_bufs(w, STAILQ_FIRST(&s->iv));
            *(uint32_t *)(last->buf) = STAILQ_FIRST(&s->iv)->idx;
            last = l;
        }
        if (!STAILQ_EMPTY(&s->ov)) {
            const struct w_iov * const lov =
                w_chain_extra_bufs(w, STAILQ_FIRST(&s->ov));
            *(uint32_t *)(last->buf) = STAILQ_FIRST(&s->ov)->idx;
            last = lov;
        }
        *(uint32_t *)(last->buf) = 0;
    }
    w->nif->ni_bufs_head = STAILQ_FIRST(&w->iov)->idx;

    assert(munmap(w->mem, w->req.nr_memsize) != -1,
           "cannot munmap netmap memory");

{'fraction_non_alphanumeric': 0.1503964998632759, 'fraction_numerical': 0.008294594840944308, 'mean_word_length': 2.475451377890402, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 164, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2930564', 'n_tokens_mistral': 4064, 'n_tokens_neox': 3992, 'n_words': 1087}