/*
* 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;
}