[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/dnwick/netmap-tutorial/master/codelab/fe.c [Back]  [Original]

/*
 * This program reads UDP packets from the first netmap port and
 * selectively forwards them to the second or third port, depending
 * on the UDP destination port. The user can specify two UDP ports A and
 * B by command line: packets with destination port A will be forwarded
 * to the second netmap port; packets with destination port B will be
 * forwarded to the third netmap port; all the other packets are
 * dropped.
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define NETMAP_WITH_LIBS
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static int stop                   = 0;
static unsigned long long fwdback = 0;
static unsigned long long fwda    = 0;
static unsigned long long fwdb    = 0;
static unsigned long long tot     = 0;

static void
sigint_handler(int signum)
{
    stop = 1;
}

static int
rx_ready(struct nm_desc *nmd)
{
    unsigned int ri;

    for (ri = nmd->first_rx_ring; ri last_rx_ring; ri++) {
        struct netmap_ring *ring;

        ring = NETMAP_RXRING(nmd->nifp, ri);
        if (nm_ring_space(ring)) {
            return 1; /* there is something to read */
        }
    }

    return 0;
}

static inline int
pkt_get_udp_port(const char *buf)
{
    struct ether_header *ethh;
    struct ip *iph;
    struct udphdr *udph;

    ethh = (struct ether_header *)buf;
    if (ethh->ether_type != htons(ETHERTYPE_IP)) {
        /* Filter out non-IP traffic. */
        return 0;
    }
    iph = (struct ip *)(ethh + 1);
    if (iph->ip_p != IPPROTO_UDP) {
        /* Filter out non-UDP traffic. */
        return 0;
    }
    udph = (struct udphdr *)(iph + 1);

    /* Return destination port. */
    return ntohs(udph->uh_dport);
}

static void
forward_pkts(struct nm_desc *src, struct nm_desc *dst)
{
    unsigned int si = src->first_rx_ring;
    unsigned int di = dst->first_tx_ring;

    while (si last_rx_ring && di last_tx_ring) {
        struct netmap_ring *txring;
        struct netmap_ring *rxring;
        unsigned int rxhead, txhead;
        int nrx, ntx;

        rxring = NETMAP_RXRING(src->nifp, si);
        txring = NETMAP_TXRING(dst->nifp, di);
        nrx    = nm_ring_space(rxring);
        ntx    = nm_ring_space(txring);
        if (nrx == 0) {
            si++;
            continue;
        }
        if (ntx == 0) {
            di++;
            continue;
        }

        rxhead = rxring->head;
        txhead = txring->head;
        for (; nrx > 0 && ntx > 0;
             nrx--, rxhead = nm_ring_next(rxring, rxhead), tot++) {
            struct netmap_slot *rs = &rxring->slot[rxhead];
            struct netmap_slot *ts = &txring->slot[txhead];
            char *rxbuf            = NETMAP_BUF(rxring, rs->buf_idx);
            char *txbuf            = NETMAP_BUF(txring, ts->buf_idx);

            ts->len = rs->len;
            memcpy(txbuf, rxbuf, ts->len);
            txhead = nm_ring_next(txring, txhead);
            ntx--;
            fwdback++;
            tot++;
        }
        /* Update state of netmap ring. */
        rxring->head = rxring->cur = rxhead;
        txring->head = txring->cur = txhead;
    }
}

static int
main_loop(const char *netmap_port_one, const char *netmap_port_two,
          const char *netmap_port_three, int udp_port_a, int udp_port_b)
{
    struct nm_desc *nmd_one;
    struct nm_desc *nmd_two;
    struct nm_desc *nmd_three;

    nmd_one = nm_open(netmap_port_one, NULL, 0, NULL);
    if (nmd_one == NULL) {
        if (!errno) {
            printf("Failed to nm_open(%s): not a netmap port\n",
                   netmap_port_one);
        } else {
            printf("Failed to nm_open(%s): %s\n", netmap_port_one,
                   strerror(errno));
        }
        return -1;
    }

    nmd_two = nm_open(netmap_port_two, NULL, 0, NULL);
    if (nmd_two == NULL) {
        if (!errno) {
            printf("Failed to nm_open(%s): not a netmap port\n",
                   netmap_port_two);
        } else {
            printf("Failed to nm_open(%s): %s\n", netmap_port_two,
                   strerror(errno));
        }
        return -1;
    }

    nmd_three = nm_open(netmap_port_three, NULL, 0, NULL);
    if (nmd_three == NULL) {
        if (!errno) {
            printf("Failed to nm_open(%s): not a netmap port\n",
                   netmap_port_three);
        } else {
            printf("Failed to nm_open(%s): %s\n", netmap_port_three,
                   strerror(errno));
        }
        return -1;
    }

    while (!stop) {
        /* Forward traffic from ports two and three back to port one. */
        forward_pkts(nmd_two, nmd_one);
        forward_pkts(nmd_three, nmd_one);
    }

    nm_close(nmd_one);
    nm_close(nmd_two);
    nm_close(nmd_three);

    printf("Total processed packets: %llu\n", tot);
    printf("Forwarded to port one  : %llu\n", fwdback);
    printf("Forwarded to port two  : %llu\n", fwda);
    printf("Forwarded to port three: %llu\n", fwdb);

    return 0;
}

static void
usage(char **argv)
{
    printf("usage: %s [-h] [-i NETMAP_PORT_ONE] "
           "[-i NETMAP_PORT_TWO] [-i NETMAP_PORT_THREE] "
           "[-p UDP_PORT_A] [-p UDP_PORT_B]\n",
           argv[0]);
    exit(EXIT_SUCCESS);
}

int
main(int argc, char **argv)
{
    const char *netmap_port_one   = NULL;
    const char *netmap_port_two   = NULL;
    const char *netmap_port_three = NULL;
    int udp_port;
    int udp_port_a    = 8000;
    int udp_port_b    = 8001;
    int udp_port_args = 0;
    struct sigaction sa;
    int opt;
    int ret;

    while ((opt = getopt(argc, argv, "hi:p:")) != -1) {
        switch (opt) {
        case 'h':
            usage(argv);
            return 0;

        case 'i':
            if (netmap_port_one == NULL) {
                netmap_port_one = optarg;
            } else if (netmap_port_two == NULL) {
                netmap_port_two = optarg;
            } else if (netmap_port_three == NULL) {
                netmap_port_three = optarg;
            }
            break;

        case 'p':
            udp_port = atoi(optarg);
            if (udp_port = 65535) {
                printf("    invalid UDP port %s\n", optarg);
                usage(argv);
            }
            switch (udp_port_args) {
            case 0:
                udp_port_a = udp_port;
                break;
            case 1:
                udp_port_b = udp_port;
                break;
            }
            udp_port_args++;
            break;

        default:
            printf("    unrecognized option '-%c'\n", opt);
            usage(argv);
            return -1;
        }
    }

    if (netmap_port_one == NULL) {
        printf("    missing netmap port #1\n");
        usage(argv);
    }

    if (netmap_port_two == NULL) {
        printf("    missing netmap port #2\n");
        usage(argv);
    }

    /* Register Ctrl-C handler. */
    sa.sa_handler = sigint_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    ret         = sigaction(SIGINT, &sa, NULL);
    if (ret) {
        perror("sigaction(SIGINT)");
        exit(EXIT_FAILURE);
    }
    (void)rx_ready;

    printf("Port one  : %s\n", netmap_port_one);
    printf("Port two  : %s\n", netmap_port_two);
    printf("Port three: %s\n", netmap_port_three);
    printf("UDP port A: %d\n", udp_port_a);
    printf("UDP port B: %d\n", udp_port_b);

    main_loop(netmap_port_one, netmap_port_two, netmap_port_three, udp_port_a,
              udp_port_b);

    (void)pkt_get_udp_port;

    return 0;
}

Web Proxy Viewer  |  New URL  |  Original Page