Skip to content

Commit cc3eb42

Browse files
author
Tom Barbette
committed
Support Zero-Copy for Netmap
This commit adds zero-copy through buffer swapping with extra buffer allocated on startup. Netmap Buffers are now organized in pool much like click pool through a completed implementation of Luigi Rizzo's NetmapBufQ. A shared linked list allows multiple thread-local NetmapBufQ to exchange batches of buffers. The amount of extra buffers allocated on startup is set using NetmapInfo, which is now a real element. NetmapBufQ and other old NetmapInfo methods (renamed more accurately NetmapDevice) are moved to lib/netmapdevice.cc Also there was confusion between HAVE_NET_NETMAP_H and HAVE_NETMAP, and the ELEMENT_REQUIRES(netmap). It's not really needed to have part of the netmap subsystem built without HAVE_NETMAP, so HAVE_NET_NETMAP_H is changed by HAVE_NETMAP. This is a first, minimal change just to introduce Zero Copy, it provides improvement but the send and receive method are nearly untouched and not re-worked in this commit.
1 parent 1490de3 commit cc3eb42

File tree

15 files changed

+640
-283
lines changed

15 files changed

+640
-283
lines changed

config-userlevel.h.in

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,6 @@
113113
/* Define if you have the <netdb.h> header file. */
114114
#undef HAVE_NETDB_H
115115

116-
/* Define if you have the <net/netmap.h> header file. */
117-
#undef HAVE_NET_NETMAP_H
118-
119116
/* Define if you have the <netpacket/packet.h> header file. */
120117
#undef HAVE_NETPACKET_PACKET_H
121118

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

214+
/* Define if Netmap support is enabled. */
215+
#undef HAVE_NETMAP
216+
217217
/* Define if a Click user-level driver uses Intel DPDK. */
218218
#undef HAVE_DPDK
219219

configure

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10705,11 +10705,15 @@ $as_echo "$ac_cv_working_net_netmap_h" >&6; }
1070510705
CPPFLAGS="$saveflags"
1070610706
if test "$HAVE_NETMAP" = yes -a "$use_netmap" != no; then
1070710707

10708-
$as_echo "#define HAVE_NET_NETMAP_H 1" >>confdefs.h
10708+
$as_echo "#define HAVE_NETMAP 1" >>confdefs.h
1070910709

10710+
EXTRA_DRIVER_OBJS="netmapdevice.o $EXTRA_DRIVER_OBJS"
10711+
else
10712+
HAVE_NETMAP=no
1071010713
fi
1071110714

1071210715

10716+
1071310717
if test "$HAVE_PCAP" != yes -a "$HAVE_NETMAP" != yes -a "$ac_cv_under_linux" != yes; then
1071410718
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
1071510719
=========================================

elements/userlevel/fromdevice.cc

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,15 @@ FromDevice::emit_packet(WritablePacket *p, int extra_len, const Timestamp &ts)
472472
else
473473
checked_output_push(1, p);
474474
}
475+
476+
void
477+
FromDevice::emit_packet_arg(WritablePacket *p, int extra_len, const Timestamp &ts, void* arg) {
478+
FromDevice* fd = static_cast<FromDevice*>(arg);
479+
fd->emit_packet(p, extra_len, ts);
480+
}
475481
#endif
476482

477-
#if FROMDEVICE_ALLOW_PCAP || FROMDEVICE_ALLOW_NETMAP
483+
#if FROMDEVICE_ALLOW_PCAP
478484
CLICK_ENDDECLS
479485
extern "C" {
480486
void
@@ -497,7 +503,6 @@ FromDevice_get_packet(u_char* clientdata,
497503
CLICK_DECLS
498504
#endif
499505

500-
501506
void
502507
FromDevice::selected(int, int)
503508
{
@@ -507,8 +512,7 @@ FromDevice::selected(int, int)
507512
#if FROMDEVICE_ALLOW_NETMAP
508513
if (_method == method_netmap) {
509514
// Read and push() at most one burst of packets.
510-
int r = _netmap.dispatch(_burst,
511-
reinterpret_cast<nm_cb_t>(FromDevice_get_packet), (u_char *) this);
515+
int r = _netmap.receive(_burst, _headroom, emit_packet_arg, this);
512516
if (r > 0) {
513517
_count += r;
514518
_task.reschedule();
@@ -570,8 +574,7 @@ FromDevice::run_task(Task *)
570574
# if FROMDEVICE_ALLOW_NETMAP
571575
if (_method == method_netmap) {
572576
// Read and push() at most one burst of packets.
573-
r = _netmap.dispatch(_burst,
574-
reinterpret_cast<nm_cb_t>(FromDevice_get_packet), (u_char *) this);
577+
r = _netmap.receive(_burst,_headroom,emit_packet_arg, this);
575578
if (r < 0 && ++_pcap_complaints < 5)
576579
ErrorHandler::default_handler()->error("%p{element}: %s",
577580
this, "nm_dispatch failed");
@@ -652,5 +655,5 @@ FromDevice::add_handlers()
652655
}
653656

654657
CLICK_ENDDECLS
655-
ELEMENT_REQUIRES(userlevel FakePcap KernelFilter NetmapInfo)
658+
ELEMENT_REQUIRES(userlevel FakePcap KernelFilter)
656659
EXPORT_ELEMENT(FromDevice)

elements/userlevel/fromdevice.hh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ int pcap_setnonblock(pcap_t *p, int nonblock, char *errbuf);
1818
}
1919
#endif
2020

21-
#if HAVE_NET_NETMAP_H
21+
#if HAVE_NETMAP
2222
# define FROMDEVICE_ALLOW_NETMAP 1
23-
# include "elements/userlevel/netmapinfo.hh"
23+
# include <click/netmapdevice.hh>
2424
#endif
2525

2626
#if FROMDEVICE_ALLOW_NETMAP || FROMDEVICE_ALLOW_PCAP
@@ -187,7 +187,6 @@ class FromDevice : public Element { public:
187187
#else
188188
inline int fd() const { return -1; }
189189
#endif
190-
191190
void selected(int fd, int mask);
192191

193192
#if FROMDEVICE_ALLOW_PCAP
@@ -203,7 +202,7 @@ class FromDevice : public Element { public:
203202
#endif
204203

205204
#if FROMDEVICE_ALLOW_NETMAP
206-
const NetmapInfo *netmap() const { return _method == method_netmap ? &_netmap : 0; }
205+
const NetmapDevice *netmap() const { return _method == method_netmap ? &_netmap : 0; }
207206
#endif
208207

209208
#if FROMDEVICE_ALLOW_NETMAP || FROMDEVICE_ALLOW_PCAP
@@ -222,13 +221,14 @@ class FromDevice : public Element { public:
222221
#endif
223222
#if FROMDEVICE_ALLOW_PCAP || FROMDEVICE_ALLOW_NETMAP
224223
void emit_packet(WritablePacket *p, int extra_len, const Timestamp &ts);
224+
static void emit_packet_arg(WritablePacket *p, int extra_len, const Timestamp &ts, void* arg);
225225
#endif
226226
#if FROMDEVICE_ALLOW_PCAP
227227
pcap_t *_pcap;
228228
int _pcap_complaints;
229229
#endif
230230
#if FROMDEVICE_ALLOW_NETMAP
231-
NetmapInfo _netmap;
231+
NetmapDevice _netmap;
232232
int netmap_dispatch();
233233
#endif
234234
#if FROMDEVICE_ALLOW_PCAP || FROMDEVICE_ALLOW_NETMAP

elements/userlevel/netmapinfo.cc

Lines changed: 18 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// -*- mode: c++; c-basic-offset: 4 -*-
22
/*
33
* netmapinfo.{cc,hh} -- library for interfacing with netmap
4-
* Eddie Kohler, Luigi Rizzo
54
*
6-
* Copyright (c) 2012 Eddie Kohler
5+
* Copyright (c) 2015 Tom Barbette
76
*
87
* Permission is hereby granted, free of charge, to any person obtaining a
98
* copy of this software and associated documentation files (the "Software"),
@@ -17,130 +16,29 @@
1716
*/
1817

1918
#include <click/config.h>
20-
#include <click/glue.hh>
21-
#if HAVE_NET_NETMAP_H
22-
#define NETMAP_WITH_LIBS
19+
#include <click/args.hh>
20+
#include <click/error.hh>
2321
#include "netmapinfo.hh"
24-
#include <sys/mman.h>
25-
#include <sys/ioctl.h>
26-
#include <click/sync.hh>
27-
#include <unistd.h>
28-
#include <fcntl.h>
29-
CLICK_DECLS
30-
31-
/*
32-
* keep a list of netmap ports so matching the name we
33-
* can recycle the regions
34-
*/
35-
static Spinlock netmap_memory_lock;
36-
//static struct NetmapInfo *netmap_ports;
3722

38-
int
39-
NetmapInfo::open(const String &ifname,
40-
bool always_error, ErrorHandler *errh)
41-
{
42-
click_chatter("%s ifname %s\n", __FUNCTION__, ifname.c_str());
43-
ErrorHandler *initial_errh = always_error ? errh : ErrorHandler::silent_handler();
23+
CLICK_DECLS
4424

45-
netmap_memory_lock.acquire();
46-
// for the time being, just a new block
47-
do {
48-
desc = nm_open(ifname.c_str(), NULL, 0, NULL);
49-
if (desc == NULL) {
50-
initial_errh->error("nm_open(%s): %s", ifname.c_str(), strerror(errno));
51-
break;
25+
int NetmapInfo::configure(Vector<String> &conf, ErrorHandler *errh) {
26+
if (instance) {
27+
return errh->error("You cannot place multiple instances of NetmapInfo !");
5228
}
53-
click_chatter("%s %s memsize %d mem %p buf_start %p buf_end %p",
54-
__FUNCTION__, desc->req.nr_name,
55-
desc->memsize, desc->mem, desc->buf_start, desc->buf_end);
56-
bufq.init(desc->buf_start, desc->buf_end,
57-
desc->some_ring->nr_buf_size);
58-
/* eventually try to match the region */
59-
destructor_arg = this;
60-
click_chatter("private mapping for %s\n", ifname.c_str());
61-
} while (0);
62-
netmap_memory_lock.release();
63-
return desc ? desc->fd : -1;
64-
}
29+
instance = this;
30+
if (Args(conf, this, errh)
31+
.read_p("EXTRA_BUFFER", NetmapDevice::global_alloc)
32+
.complete() < 0)
33+
return -1;
6534

66-
void
67-
NetmapInfo::initialize_rings_rx(int timestamp)
68-
{
69-
click_chatter("%s timestamp %d\n", __FUNCTION__, timestamp);
70-
if (timestamp >= 0) {
71-
int flags = (timestamp > 0 ? NR_TIMESTAMP : 0);
72-
for (unsigned i = desc->first_rx_ring; i <= desc->last_rx_ring; ++i)
73-
NETMAP_RXRING(desc->nifp, i)->flags = flags;
74-
}
35+
return 0;
7536
}
7637

77-
void
78-
NetmapInfo::initialize_rings_tx()
79-
{
80-
click_chatter("%s\n", __FUNCTION__);
81-
}
82-
83-
int
84-
NetmapInfo::dispatch(int count, nm_cb_t cb, u_char *arg)
85-
{
86-
return nm_dispatch(desc, count, cb, arg);
87-
}
88-
89-
bool
90-
NetmapInfo::send_packet(Packet *p, int noutputs)
91-
{
92-
int ret = nm_inject(desc, p->data(), p->length());
93-
if (0) click_chatter("%s buf %p size %d returns %d\n",
94-
__FUNCTION__, p->data(), p->length(), ret);
95-
return ret > 0 ? 0 : -1;
96-
#if 0
97-
// we can do a smart nm_inject
98-
for (unsigned ri = desc->first_tx_ring; ri <= desc->last_tx_ring; ++ri) {
99-
struct netmap_ring *ring = NETMAP_TXRING(desc->nifp, ri);
100-
if (nm_ring_empty(ring))
101-
continue;
102-
unsigned cur = ring->cur;
103-
unsigned buf_idx = ring->slot[cur].buf_idx;
104-
if (buf_idx < 2)
105-
continue;
106-
unsigned char *buf = (unsigned char *) NETMAP_BUF(ring, buf_idx);
107-
uint32_t p_length = p->length();
108-
if (NetmapInfo::is_netmap_buffer(p)
109-
&& !p->shared()
110-
&& p->buffer() == p->data()
111-
&& (char *)p->buffer() >= desc->buf_start
112-
&& (char *)p->buffer() < desc->buf_end
113-
&& noutputs == 0) {
114-
// put the original buffer in the freelist
115-
NetmapInfo::buffer_destructor(buf, 0, (void *)this);
116-
// now enqueue
117-
ring->slot[cur].buf_idx = NETMAP_BUF_IDX(ring, (char *) p->buffer());
118-
ring->slot[cur].flags |= NS_BUF_CHANGED;
119-
// and make sure nobody uses this packet
120-
p->reset_buffer();
121-
} else
122-
memcpy(buf, p->data(), p_length);
123-
ring->slot[cur].len = p_length;
124-
__asm__ volatile("" : : : "memory");
125-
ring->head = ring->cur = nm_ring_next(ring, cur);
126-
return 0;
127-
}
128-
errno = ENOBUFS;
129-
return -1;
130-
#endif
131-
}
132-
void
133-
NetmapInfo::close(int fd)
134-
{
135-
click_chatter("fd %d interface %s\n",
136-
fd, desc->req.nr_name);
137-
netmap_memory_lock.acquire();
138-
// unlink from the list ?
139-
nm_close(desc);
140-
desc = 0;
141-
netmap_memory_lock.release();
142-
}
38+
NetmapInfo* NetmapInfo::instance = 0;
14339

14440
CLICK_ENDDECLS
145-
#endif
146-
ELEMENT_PROVIDES(NetmapInfo)
41+
42+
ELEMENT_REQUIRES(userlevel netmap)
43+
EXPORT_ELEMENT(NetmapInfo)
44+
ELEMENT_MT_SAFE(NetmapInfo)

0 commit comments

Comments
 (0)