Commit cd22025d authored by Tom Barbette's avatar Tom Barbette

Combining batching and I/O elements. Also took some changes from the original...

Combining batching and I/O elements. Also took some changes from the original fatclick without wanting to : the support for DPDK pool (using the DPDK descriptor instead of the click Packet descriptor), the Pipeliner which is the QUeue keeping fullpush (see paper) and some minor modifications
parent 28ad78fa
......@@ -125,9 +125,15 @@
/* Define if you have the <net/netmap.h> header file. */
#undef HAVE_NET_NETMAP_H
/* Define if you have the <net/netmap.h> header file. */
#undef HAVE_NETMAP_PACKET_POOL
/* Define if you have the <netpacket/packet.h> header file. */
#undef HAVE_NETPACKET_PACKET_H
/* Define if Zero-copy is enabled. */
#undef HAVE_ZEROCOPY
/* Define if <new.h> exists and works. */
#undef HAVE_NEW_H
......@@ -220,6 +226,12 @@
/* Define if a Click user-level driver might run multiple threads. */
#undef HAVE_USER_MULTITHREAD
/* Define if a Click user-level driver uses Intel DPDK. */
#undef HAVE_DPDK
/* Define if a Click user-level driver manages Intel DPDK packet pools. */
#undef CLICK_DPDK_POOLS
/* Define if Click should use Valgrind client requests. */
#undef HAVE_VALGRIND
......@@ -229,9 +241,6 @@
/* Define if you have the vsnprintf function. */
#undef HAVE_VSNPRINTF
/* Define if Zero-copy is enabled. */
#undef HAVE_ZEROCOPY
/* The size of a `click_jiffies_t', as computed by sizeof. */
#define SIZEOF_CLICK_JIFFIES_T SIZEOF_INT
......
......@@ -661,6 +661,7 @@ EXPAT_INCLUDES
XML2CLICK
PROPER_LIBS
PROPER_INCLUDES
HAVE_NETMAP_PACKET_POOL
NETMAP_INCLUDES
NUMA_INCLUDES
PCAP_LIBS
......@@ -705,6 +706,7 @@ INCLUDE_KSYMS
LINUXMODULE_FIXINCLUDES
USE_DPDK
PTHREAD_LIBS
HAVE_BATCH
AR_CREATEFLAGS
STRIP
RANLIB
......@@ -790,10 +792,13 @@ ac_user_opts='
enable_option_checking
enable_userlevel
enable_user_multithread
enable_batch
enable_netmap_pool
enable_select
enable_poll
enable_kqueue
enable_dpdk
enable_dpdk_pools
enable_zerocopy
enable_linuxmodule
enable_fixincludes
......@@ -820,7 +825,6 @@ enable_ethernet
enable_etherswitch
enable_grid
enable_icmp
enable_batch
enable_ip
enable_ip6
enable_ipsec
......@@ -1484,12 +1488,15 @@ Optional Features:
--disable-userlevel disable user-level driver
--enable-user-multithread
support userlevel multithreading
--disable-batch disable batching support
--enable-netmap-pool have only netmap packets in the pool
--enable-select=[select|poll|kqueue]
set file descriptor wait mechanism
--disable-select do not use select()
--disable-poll do not use poll()
--disable-kqueue do not use kqueue()
--enable-dpdk use Intel DPDK
--enable-dpdk-pools Click manages DPDK packet pools
--enable-zerocopy use Zero Copy
--disable-linuxmodule disable Linux kernel driver
--disable-fixincludes do not patch Linux kernel headers for C++
......@@ -1512,7 +1519,6 @@ Optional Features:
--enable-etherswitch include Ethernet switch elements
--enable-grid include Grid elements (see FAQ)
--disable-icmp do not include ICMP elements
--disable-batch do not enable batching
--disable-ip do not include IP elements
--enable-ip6 include IPv6 elements
--enable-ipsec include IP security elements
......@@ -6336,6 +6342,37 @@ else
fi
# Check whether --enable-batch was given.
if test "${enable_batch+set}" = set; then :
enableval=$enable_batch; :
else
enable_batch=yes
fi
if test "x$enable_batch" = "xyes"; then
if test "x$enable_userlevel" != "xyes"; then
as_fn_error $? "
=========================================
--enable-batch requires --enable-userlevel which was not provided.
=========================================" "$LINENO" 5
fi
$as_echo "#define HAVE_BATCH 1" >>confdefs.h
HAVE_BATCH=yes
fi
# Check whether --enable-netmap-pool was given.
if test "${enable_netmap_pool+set}" = set; then :
enableval=$enable_netmap_pool; :
else
enable_netmap_pool=no
fi
PTHREAD_LIBS=""
......@@ -6496,6 +6533,14 @@ else
fi
# Check whether --enable-dpdk-pools was given.
if test "${enable_dpdk_pools+set}" = set; then :
enableval=$enable_dpdk_pools; :
else
enable_dpdk_pools=no
fi
if test "x$enable_dpdk" = "xyes"; then
if test "x$enable_user_multithread" != "xyes"; then
as_fn_error $? "
......@@ -6529,6 +6574,19 @@ Define \$RTE_SDK and \$RTE_TARGET as per Intel DPDK documentation.
fi
if test "x$enable_dpdk_pools" = "xyes"; then
if test "x$enable_dpdk" != "xyes"; then
as_fn_error $? "
=========================================
--enable-dpdk-pools requires --enable-dpdk which was not provided.
=========================================" "$LINENO" 5
fi
$as_echo "#define CLICK_DPDK_POOLS 1" >>confdefs.h
fi
# Check whether --enable-zerocopy was given.
if test "${enable_zerocopy+set}" = set; then :
enableval=$enable_zerocopy; :
......@@ -6981,18 +7039,6 @@ test "x$enable_all_elements" = xyes -a \( "x$enable_icmp" = xNO -o "x$enable_icm
if test "x$enable_icmp" = xyes; then
:
fi
# Check whether --enable-batch was given.
if test "${enable_batch+set}" = set; then :
enableval=$enable_batch;
else
enable_batch=yes
fi
test "x$enable_all_elements" = xyes -a \( "x$enable_batch" = xNO -o "x$enable_batch" = x \) && enable_batch=yes
if test "x$enable_batch" = xyes; then
:
$as_echo "#define HAVE_BATCH 1" >>confdefs.h
fi
# Check whether --enable-ip was given.
if test "${enable_ip+set}" = set; then :
......@@ -10669,30 +10715,69 @@ fi
NUMA_INCLUDES="-I$use_numa"
fi
fi
saveflags="$CPPFLAGS"
CPPFLAGS="$saveflags $NUMA_INCLUDES"
HAVE_NUMA=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for numa.h" >&5
$as_echo_n "checking for numa.h... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing numa_available" >&5
$as_echo_n "checking for library containing numa_available... " >&6; }
if ${ac_cv_search_numa_available+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <numa.h>
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char numa_available ();
int
main ()
{
return numa_available ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_cpp "$LINENO"; then :
ac_cv_numa_header_path="found"
for ac_lib in '' numa; do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
if ac_fn_c_try_link "$LINENO"; then :
ac_cv_search_numa_available=$ac_res
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext
if ${ac_cv_search_numa_available+:} false; then :
break
fi
done
if ${ac_cv_search_numa_available+:} false; then :
else
ac_cv_numa_header_path="not found"
ac_cv_search_numa_available=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_numa_available" >&5
$as_echo "$ac_cv_search_numa_available" >&6; }
ac_res=$ac_cv_search_numa_available
if test "$ac_res" != no; then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
ac_have_libnuma=yes
else
ac_have_libnuma=no
fi
rm -f conftest.err conftest.i conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_numa_header_path" >&5
$as_echo "$ac_cv_numa_header_path" >&6; }
if test "$ac_cv_net_numa_header_path" = "found"; then
HAVE_NUMA=yes
fi
if test "$HAVE_NUMA" = yes; then
if test "$ac_have_libnuma" = yes; then
$as_echo "#define HAVE_NUMA 1" >>confdefs.h
......@@ -10818,6 +10903,21 @@ pcap.h and/or -lpcap not found; user-level driver can't steal packets.
HAVE_USERLEVEL_DRIVER=1
fi
if test "x$enable_netmap_pool" = "xyes"; then
if test "x$HAVE_NETMAP" != "xyes"; then
as_fn_error $? "
=========================================
--enable-netmap-pool requires --with-netmap which was not provided.
=========================================" "$LINENO" 5
fi
$as_echo "#define HAVE_NETMAP_PACKET_POOL 1" >>confdefs.h
HAVE_NETMAP_PACKET_POOL=yes
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct if_data has ifi_datalen" >&5
$as_echo_n "checking whether struct if_data has ifi_datalen... " >&6; }
......@@ -13487,7 +13587,7 @@ if test $ac_have_linux_kernel = y; then
fi
fi
if test "x$HAVE_NETMAP" = xyes; then
if test "x$use_netmap" = xyes; then
provisions="$provisions netmap"
fi
......
......@@ -84,7 +84,7 @@ AC_ARG_ENABLE([user-multithread],
[:], [enable_user_multithread=no])
AC_ARG_ENABLE([batch],
[AS_HELP_STRING([--disable-batch], [disable batching support])],
[AS_HELP_STRING([ --disable-batch], [disable batching support])],
[:], [enable_batch=yes])
if test "x$enable_batch" = "xyes"; then
......@@ -99,6 +99,10 @@ if test "x$enable_batch" = "xyes"; then
AC_DEFINE([HAVE_BATCH])
AC_SUBST(HAVE_BATCH, yes)
fi
AC_ARG_ENABLE([netmap-pool],
[AS_HELP_STRING([ --enable-netmap-pool], [have only netmap packets in the pool])],
[:], [enable_netmap_pool=no])
PTHREAD_LIBS=""
AC_SUBST(PTHREAD_LIBS)
......@@ -156,6 +160,11 @@ AC_ARG_ENABLE([dpdk],
[AS_HELP_STRING([ --enable-dpdk], [use Intel DPDK])],
[:], [enable_dpdk=no])
AC_ARG_ENABLE([dpdk-pools],
[AS_HELP_STRING([ --enable-dpdk-pools],
[Click manages DPDK packet pools])],
[:], [enable_dpdk_pools=no])
if test "x$enable_dpdk" = "xyes"; then
if test "x$enable_user_multithread" != "xyes"; then
AC_MSG_ERROR([
......@@ -187,6 +196,18 @@ Define \$RTE_SDK and \$RTE_TARGET as per Intel DPDK documentation.
AC_SUBST(USE_DPDK, yes)
fi
if test "x$enable_dpdk_pools" = "xyes"; then
if test "x$enable_dpdk" != "xyes"; then
AC_MSG_ERROR([
=========================================
--enable-dpdk-pools requires --enable-dpdk which was not provided.
=========================================])
fi
AC_DEFINE([CLICK_DPDK_POOLS])
fi
AC_ARG_ENABLE([zerocopy],
[AS_HELP_STRING([ --enable-zerocopy], [use Zero Copy])],
[:], [enable_zerocopy=no])
......@@ -1252,6 +1273,19 @@ pcap.h and/or -lpcap not found; user-level driver can't steal packets.
HAVE_USERLEVEL_DRIVER=1
fi
if test "x$enable_netmap_pool" = "xyes"; then
if test "x$HAVE_NETMAP" != "xyes"; then
AC_MSG_ERROR([
=========================================
--enable-netmap-pool requires --with-netmap which was not provided.
=========================================])
fi
AC_DEFINE([HAVE_NETMAP_PACKET_POOL])
AC_SUBST(HAVE_NETMAP_PACKET_POOL, yes)
fi
dnl other user-level specifics
AC_CACHE_CHECK([whether struct if_data has ifi_datalen], [ac_cv_if_data_ifi_datalen],
......@@ -2052,7 +2086,7 @@ if test $ac_have_linux_kernel = y; then
fi
dnl add 'netmap' if netmap support is available
if test "x$HAVE_NETMAP" = xyes; then
if test "x$use_netmap" = xyes; then
provisions="$provisions netmap"
fi
......
......@@ -46,7 +46,7 @@ EtherEncap::configure(Vector<String> &conf, ErrorHandler *errh)
return 0;
}
Packet *
inline Packet *
EtherEncap::smaction(Packet *p)
{
if (WritablePacket *q = p->push_mac_header(14)) {
......@@ -56,12 +56,50 @@ EtherEncap::smaction(Packet *p)
return 0;
}
void
EtherEncap::push(int, Packet *p)
{
if (Packet *q = smaction(p))
output(0).push(q);
}
#if HAVE_BATCH
void EtherEncap::push_batch(int, PacketBatch * batch) {
Packet* head = NULL;
Packet* previous = NULL;
Packet* current = batch;
int count = 0;
while (current != NULL) {
Packet* next = current->next();
current = smaction(current);
if (current == NULL) {
click_chatter("%s : could not set ethernet header !",name().c_str());
current = next;
continue;
}
if (previous == NULL)
head = current;
else
previous->set_next(current);
current->set_next(next);
previous = current;
current = next;
count++;
}
if (head != NULL) {
if (batch == head)
output(0).push_batch(PacketBatch::make_from_list(batch,count));
else {
output(0).push_batch(PacketBatch::make_from_list(head,count));
}
}
}
#endif
void
EtherEncap::push(int, Packet *p)
{
if (Packet *q = smaction(p))
output(0).push(q);
}
Packet *
EtherEncap::pull(int)
......
#ifndef CLICK_ETHERENCAP_HH
#define CLICK_ETHERENCAP_HH
#include <click/element.hh>
#include <click/batchelement.hh>
#include <clicknet/ether.h>
CLICK_DECLS
......@@ -46,7 +47,8 @@ Return or set the ETHERTYPE parameter.
EtherVLANEncap, ARPQuerier, EnsureEther, StoreEtherAddress */
class EtherEncap : public Element { public:
class EtherEncap : public BatchElement { public:
EtherEncap() CLICK_COLD;
~EtherEncap() CLICK_COLD;
......@@ -58,10 +60,15 @@ class EtherEncap : public Element { public:
bool can_live_reconfigure() const { return true; }
void add_handlers() CLICK_COLD;
Packet *smaction(Packet *);
void push(int, Packet *);
inline Packet *smaction(Packet *);
Packet *pull(int);
#if HAVE_BATCH
void push_batch(int, PacketBatch *);
#endif
void push(int, Packet *);
private:
click_ether _ethh;
......
......@@ -121,30 +121,12 @@ InfiniteSource::run_task(Task *)
int n = _burstsize;
if (_limit >= 0 && _count + n >= (ucounter_t) _limit)
n = (_count > (ucounter_t) _limit ? 0 : _limit - _count);
#if HAVE_BATCH
PacketBatch* head = NULL;
Packet* last = NULL;
for (int i = 0; i < n; i++) {
if (head == NULL) {
head = PacketBatch::start_head(_packet->clone());
last = head;
} else {
last->set_next(_packet->clone());
last = last->next();
}
if (_timestamp)
last->timestamp_anno().assign_now();
}
if (n > 0)
output(0).push_batch(head->make_tail(last,n));
#else
for (int i = 0; i < n; i++) {
Packet *p = _packet->clone();
if (_timestamp)
p->timestamp_anno().assign_now();
output(0).push(p);
}
#endif
_count += n;
if (n > 0)
_task.fast_reschedule();
......
......@@ -20,6 +20,8 @@
#include "simplequeue.hh"
#include <click/args.hh>
#include <click/error.hh>
#include <click/router.hh>
#include <click/packet.hh>
CLICK_DECLS
SimpleQueue::SimpleQueue()
......@@ -58,9 +60,29 @@ SimpleQueue::initialize(ErrorHandler *errh)
return errh->error("out of memory");
_drops = 0;
_highwater_length = 0;
Bitvector b = get_threads();
unsigned int thisthread = router()->home_thread_id(this);
for (unsigned i = 0; i < (unsigned)b.size(); i++) {
if (b[i] && i != thisthread) {
WritablePacket::pool_transfer(thisthread,i);
}
}
return 0;
}
bool
SimpleQueue::get_runnable_threads(Bitvector& b) {
unsigned int thisthread = router()->home_thread_id(this);
b.clear();
b[thisthread] = 1;
return false;
}
int
SimpleQueue::live_reconfigure(Vector<String> &conf, ErrorHandler *errh)
{
......@@ -142,6 +164,7 @@ SimpleQueue::cleanup(CleanupStage)
}
PacketBatch* SimpleQueue::pull_batch(int port) {
(void) port;
PacketBatch* batch;
MAKE_BATCH(deq(),batch);
return batch;
......
......@@ -69,6 +69,9 @@ class SimpleQueue : public BatchElement, public Storage { public:
int drops() const { return _drops; }
int highwater_length() const { return _highwater_length; }
bool get_runnable_threads(Bitvector& b);
inline bool enq(Packet*);
inline void lifo_enq(Packet*);
inline Packet* deq();
......
......@@ -73,7 +73,7 @@ StaticThreadSched::configure(Vector<String> &conf, ErrorHandler *errh)
}
Bitvector StaticThreadSched::assigned_thread() {
Bitvector v(nthreads,0);
Bitvector v(master()->nthreads(),0);
if (_next_thread_sched) {
v = _next_thread_sched->assigned_thread();
}
......
/*
* fromdpdkdevice.{cc,hh} -- element reads packets live from network via
* Intel's DPDK
*
* Copyright (c) 2014-2015 University of Liège
* Copyright (c) 2014 Cyril Soldani
* 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"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding.
*/
#include <click/config.h>
#include <click/args.hh>
#include <click/error.hh>
#include <rte_ethdev.h>
#include <rte_mbuf.h>
#include "fromdpdkdevice.hh"
CLICK_DECLS
FromDpdkDevice::FromDpdkDevice()
: _port_no(0), _promisc(true), _burst(32)
{
}
FromDpdkDevice::~FromDpdkDevice()
{
}
int FromDpdkDevice::configure(Vector<String> &conf, ErrorHandler *errh)
{
//Default parameters
int maxthreads = -1;
int threadoffset = -1;
int minqueues = 1;
int maxqueues = 128; //TODO Should be device dependent
if (Args(conf, this, errh)
.read_mp("DEVNAME", _port_no)
.read_p("PROMISC", _promisc)
.read_p("BURST", _burst)
.read_p("MAXTHREADS", maxthreads)
.read_p("THREADOFFSET", threadoffset)
.read("MINQUEUES",minqueues)
.read("MAXQUEUES",maxqueues)
.read("NDESC",ndesc)
.complete() < 0)
return -1;
int numa_node = DpdkDevice::get_port_numa_node(_port_no);
int r;
r = QueueDevice::configure_rx(numa_node,maxthreads,minqueues,maxqueues,threadoffset,errh);
if (r != 0) return r;
return 0;
}