Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions config-userlevel.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@
/* Define if you have the <netdb.h> header file. */
#undef HAVE_NETDB_H

/* Define if you have the <net/netmap.h> header file. */
#undef HAVE_NET_NETMAP_H

/* Define if you have the <netpacket/packet.h> header file. */
#undef HAVE_NETPACKET_PACKET_H

Expand Down Expand Up @@ -214,6 +211,9 @@
/* Define if a Click user-level driver might run multiple threads. */
#undef HAVE_USER_MULTITHREAD

/* Define if Netmap support is enabled. */
#undef HAVE_NETMAP

/* Define if a Click user-level driver uses Intel DPDK. */
#undef HAVE_DPDK

Expand Down
6 changes: 5 additions & 1 deletion configure
Original file line number Diff line number Diff line change
Expand Up @@ -10705,11 +10705,15 @@ $as_echo "$ac_cv_working_net_netmap_h" >&6; }
CPPFLAGS="$saveflags"
if test "$HAVE_NETMAP" = yes -a "$use_netmap" != no; then

$as_echo "#define HAVE_NET_NETMAP_H 1" >>confdefs.h
$as_echo "#define HAVE_NETMAP 1" >>confdefs.h

EXTRA_DRIVER_OBJS="netmapdevice.o $EXTRA_DRIVER_OBJS"
else
HAVE_NETMAP=no
fi



if test "$HAVE_PCAP" != yes -a "$HAVE_NETMAP" != yes -a "$ac_cv_under_linux" != yes; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
=========================================
Expand Down
17 changes: 10 additions & 7 deletions elements/userlevel/fromdevice.cc
Original file line number Diff line number Diff line change
Expand Up @@ -472,9 +472,15 @@ FromDevice::emit_packet(WritablePacket *p, int extra_len, const Timestamp &ts)
else
checked_output_push(1, p);
}

void
FromDevice::emit_packet_arg(WritablePacket *p, int extra_len, const Timestamp &ts, void* arg) {
FromDevice* fd = static_cast<FromDevice*>(arg);
fd->emit_packet(p, extra_len, ts);
}
#endif

#if FROMDEVICE_ALLOW_PCAP || FROMDEVICE_ALLOW_NETMAP
#if FROMDEVICE_ALLOW_PCAP
CLICK_ENDDECLS
extern "C" {
void
Expand All @@ -497,7 +503,6 @@ FromDevice_get_packet(u_char* clientdata,
CLICK_DECLS
#endif


void
FromDevice::selected(int, int)
{
Expand All @@ -507,8 +512,7 @@ FromDevice::selected(int, int)
#if FROMDEVICE_ALLOW_NETMAP
if (_method == method_netmap) {
// Read and push() at most one burst of packets.
int r = _netmap.dispatch(_burst,
reinterpret_cast<nm_cb_t>(FromDevice_get_packet), (u_char *) this);
int r = _netmap.receive(_burst, _headroom, emit_packet_arg, this);
if (r > 0) {
_count += r;
_task.reschedule();
Expand Down Expand Up @@ -570,8 +574,7 @@ FromDevice::run_task(Task *)
# if FROMDEVICE_ALLOW_NETMAP
if (_method == method_netmap) {
// Read and push() at most one burst of packets.
r = _netmap.dispatch(_burst,
reinterpret_cast<nm_cb_t>(FromDevice_get_packet), (u_char *) this);
r = _netmap.receive(_burst,_headroom,emit_packet_arg, this);
if (r < 0 && ++_pcap_complaints < 5)
ErrorHandler::default_handler()->error("%p{element}: %s",
this, "nm_dispatch failed");
Expand Down Expand Up @@ -652,5 +655,5 @@ FromDevice::add_handlers()
}

CLICK_ENDDECLS
ELEMENT_REQUIRES(userlevel FakePcap KernelFilter NetmapInfo)
ELEMENT_REQUIRES(userlevel FakePcap KernelFilter)
EXPORT_ELEMENT(FromDevice)
10 changes: 5 additions & 5 deletions elements/userlevel/fromdevice.hh
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf);
}
#endif

#if HAVE_NET_NETMAP_H
#if HAVE_NETMAP
# define FROMDEVICE_ALLOW_NETMAP 1
# include "elements/userlevel/netmapinfo.hh"
# include <click/netmapdevice.hh>
#endif

#if FROMDEVICE_ALLOW_NETMAP || FROMDEVICE_ALLOW_PCAP
Expand Down Expand Up @@ -187,7 +187,6 @@ class FromDevice : public Element { public:
#else
inline int fd() const { return -1; }
#endif

void selected(int fd, int mask);

#if FROMDEVICE_ALLOW_PCAP
Expand All @@ -203,7 +202,7 @@ class FromDevice : public Element { public:
#endif

#if FROMDEVICE_ALLOW_NETMAP
const NetmapInfo *netmap() const { return _method == method_netmap ? &_netmap : 0; }
const NetmapDevice *netmap() const { return _method == method_netmap ? &_netmap : 0; }
#endif

#if FROMDEVICE_ALLOW_NETMAP || FROMDEVICE_ALLOW_PCAP
Expand All @@ -222,13 +221,14 @@ class FromDevice : public Element { public:
#endif
#if FROMDEVICE_ALLOW_PCAP || FROMDEVICE_ALLOW_NETMAP
void emit_packet(WritablePacket *p, int extra_len, const Timestamp &ts);
static void emit_packet_arg(WritablePacket *p, int extra_len, const Timestamp &ts, void* arg);
#endif
#if FROMDEVICE_ALLOW_PCAP
pcap_t *_pcap;
int _pcap_complaints;
#endif
#if FROMDEVICE_ALLOW_NETMAP
NetmapInfo _netmap;
NetmapDevice _netmap;
int netmap_dispatch();
#endif
#if FROMDEVICE_ALLOW_PCAP || FROMDEVICE_ALLOW_NETMAP
Expand Down
138 changes: 18 additions & 120 deletions elements/userlevel/netmapinfo.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
* netmapinfo.{cc,hh} -- library for interfacing with netmap
* Eddie Kohler, Luigi Rizzo
*
* Copyright (c) 2012 Eddie Kohler
* Copyright (c) 2015 Tom Barbette
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
Expand All @@ -17,130 +16,29 @@
*/

#include <click/config.h>
#include <click/glue.hh>
#if HAVE_NET_NETMAP_H
#define NETMAP_WITH_LIBS
#include <click/args.hh>
#include <click/error.hh>
#include "netmapinfo.hh"
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <click/sync.hh>
#include <unistd.h>
#include <fcntl.h>
CLICK_DECLS

/*
* keep a list of netmap ports so matching the name we
* can recycle the regions
*/
static Spinlock netmap_memory_lock;
//static struct NetmapInfo *netmap_ports;

int
NetmapInfo::open(const String &ifname,
bool always_error, ErrorHandler *errh)
{
click_chatter("%s ifname %s\n", __FUNCTION__, ifname.c_str());
ErrorHandler *initial_errh = always_error ? errh : ErrorHandler::silent_handler();
CLICK_DECLS

netmap_memory_lock.acquire();
// for the time being, just a new block
do {
desc = nm_open(ifname.c_str(), NULL, 0, NULL);
if (desc == NULL) {
initial_errh->error("nm_open(%s): %s", ifname.c_str(), strerror(errno));
break;
int NetmapInfo::configure(Vector<String> &conf, ErrorHandler *errh) {
if (instance) {
return errh->error("You cannot place multiple instances of NetmapInfo !");
}
click_chatter("%s %s memsize %d mem %p buf_start %p buf_end %p",
__FUNCTION__, desc->req.nr_name,
desc->memsize, desc->mem, desc->buf_start, desc->buf_end);
bufq.init(desc->buf_start, desc->buf_end,
desc->some_ring->nr_buf_size);
/* eventually try to match the region */
destructor_arg = this;
click_chatter("private mapping for %s\n", ifname.c_str());
} while (0);
netmap_memory_lock.release();
return desc ? desc->fd : -1;
}
instance = this;
if (Args(conf, this, errh)
.read_p("EXTRA_BUFFER", NetmapDevice::global_alloc)
.complete() < 0)
return -1;

void
NetmapInfo::initialize_rings_rx(int timestamp)
{
click_chatter("%s timestamp %d\n", __FUNCTION__, timestamp);
if (timestamp >= 0) {
int flags = (timestamp > 0 ? NR_TIMESTAMP : 0);
for (unsigned i = desc->first_rx_ring; i <= desc->last_rx_ring; ++i)
NETMAP_RXRING(desc->nifp, i)->flags = flags;
}
return 0;
}

void
NetmapInfo::initialize_rings_tx()
{
click_chatter("%s\n", __FUNCTION__);
}

int
NetmapInfo::dispatch(int count, nm_cb_t cb, u_char *arg)
{
return nm_dispatch(desc, count, cb, arg);
}

bool
NetmapInfo::send_packet(Packet *p, int noutputs)
{
int ret = nm_inject(desc, p->data(), p->length());
if (0) click_chatter("%s buf %p size %d returns %d\n",
__FUNCTION__, p->data(), p->length(), ret);
return ret > 0 ? 0 : -1;
#if 0
// we can do a smart nm_inject
for (unsigned ri = desc->first_tx_ring; ri <= desc->last_tx_ring; ++ri) {
struct netmap_ring *ring = NETMAP_TXRING(desc->nifp, ri);
if (nm_ring_empty(ring))
continue;
unsigned cur = ring->cur;
unsigned buf_idx = ring->slot[cur].buf_idx;
if (buf_idx < 2)
continue;
unsigned char *buf = (unsigned char *) NETMAP_BUF(ring, buf_idx);
uint32_t p_length = p->length();
if (NetmapInfo::is_netmap_buffer(p)
&& !p->shared()
&& p->buffer() == p->data()
&& (char *)p->buffer() >= desc->buf_start
&& (char *)p->buffer() < desc->buf_end
&& noutputs == 0) {
// put the original buffer in the freelist
NetmapInfo::buffer_destructor(buf, 0, (void *)this);
// now enqueue
ring->slot[cur].buf_idx = NETMAP_BUF_IDX(ring, (char *) p->buffer());
ring->slot[cur].flags |= NS_BUF_CHANGED;
// and make sure nobody uses this packet
p->reset_buffer();
} else
memcpy(buf, p->data(), p_length);
ring->slot[cur].len = p_length;
__asm__ volatile("" : : : "memory");
ring->head = ring->cur = nm_ring_next(ring, cur);
return 0;
}
errno = ENOBUFS;
return -1;
#endif
}
void
NetmapInfo::close(int fd)
{
click_chatter("fd %d interface %s\n",
fd, desc->req.nr_name);
netmap_memory_lock.acquire();
// unlink from the list ?
nm_close(desc);
desc = 0;
netmap_memory_lock.release();
}
NetmapInfo* NetmapInfo::instance = 0;

CLICK_ENDDECLS
#endif
ELEMENT_PROVIDES(NetmapInfo)

ELEMENT_REQUIRES(userlevel netmap)
EXPORT_ELEMENT(NetmapInfo)
ELEMENT_MT_SAFE(NetmapInfo)
Loading