diff --git a/CMakeLists.txt b/CMakeLists.txt index 7dbf8109ad..f345514aa9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,6 +155,7 @@ include(TestBigEndian) test_big_endian(WORDS_BIGENDIAN) include(CheckSymbolExists) check_symbol_exists(htonll arpa/inet.h HAVE_BYTEORDER_64) +check_symbol_exists(PACKET_FANOUT linux/if_packet.h HAVE_PACKET_FANOUT) include(OSSpecific) include(CheckTypes) diff --git a/bro-config.h.in b/bro-config.h.in index 755a9eee98..fd24a1fe30 100644 --- a/bro-config.h.in +++ b/bro-config.h.in @@ -213,6 +213,9 @@ /* Common IPv6 extension structure */ #cmakedefine HAVE_IP6_EXT +/* Linux packet fanout */ +#cmakedefine HAVE_PACKET_FANOUT + /* String with host architecture (e.g., "linux-x86_64") */ #define HOST_ARCHITECTURE "@HOST_ARCHITECTURE@" diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index f28aa66c74..0097e4d47b 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -3710,12 +3710,34 @@ export { ## external harness and shouldn't output anything to the console. const errors_to_stderr = T &redef; } + +module Fanout; + +type Method: enum { + METHOD_HASH = 0, + METHOD_LB = 1, + METHOD_CPU = 2, + METHOD_ROLLOVER = 3 +}; + +type Flag: enum { + FLAG_NONE = 0, + FLAG_DEFRAG = 0x8000, + FLAG_ROLLOVER = 0x1000 +}; + +export { + const enable = F &redef; + const id = 0 &redef; + const method = METHOD_HASH &redef; + const flag = FLAG_NONE &redef; +} module GLOBAL; ## Number of bytes per packet to capture from live interfaces. const snaplen = 8192 &redef; -## Number of bytes for libpcap buffer. +## Number of bytes per packet to capture from live interfaces. const bufsize = 128 &redef; ## Seed for hashes computed internally for probabilistic data structures. Using diff --git a/src/const.bif b/src/const.bif index 0ba168ca85..f96b15818b 100644 --- a/src/const.bif +++ b/src/const.bif @@ -9,6 +9,9 @@ const detect_filtered_trace: bool; const report_gaps_for_partial: bool; const exit_only_after_terminate: bool; +const Fanout::enable: bool; +const Fanout::id: count; + const NFS3::return_data: bool; const NFS3::return_data_max: count; const NFS3::return_data_first_only: bool; diff --git a/src/iosource/IOSource.h b/src/iosource/IOSource.h index df82012268..a129429e0e 100644 --- a/src/iosource/IOSource.h +++ b/src/iosource/IOSource.h @@ -3,6 +3,27 @@ #ifndef IOSOURCE_IOSOURCE_H #define IOSOURCE_IOSOURCE_H +#ifdef HAVE_PACKET_FANOUT +#include +#ifndef PACKET_FANOUT +#define PACKET_FANOUT 18 +#define PACKET_FANOUT_HASH 0 +#define PACKET_FANOUT_LB 1 +#define PACKET_FANOUT_CPU 2 +#define PACKET_FANOUT_FLAG_DEFRAG 0x8000 + +#ifndef PACKET_FANOUT_ROLLOVER +#define PACKET_FANOUT_ROLLOVER 3 +#endif + +#ifndef PACKET_FANOUT_FLAG_ROLLOVER +#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 +#endif + +#define PACKET_FANOUT_FLAG_NONE -1 +#endif /* PACKET_FANOUT */ +#endif /* HAVE_PACKET_FANOUT */ + extern "C" { #include } diff --git a/src/iosource/PktSrc.cc b/src/iosource/PktSrc.cc index 125a72c052..42be77cb21 100644 --- a/src/iosource/PktSrc.cc +++ b/src/iosource/PktSrc.cc @@ -73,7 +73,7 @@ int PktSrc::SnapLen() const int PktSrc::BufSize() const { - return bufsize; // That's a global too. Change? + return bufsize; // That's a global. Change? } bool PktSrc::IsLive() const diff --git a/src/iosource/pcap/Source.cc b/src/iosource/pcap/Source.cc index 9c5ba2819a..e430dfc6a7 100644 --- a/src/iosource/pcap/Source.cc +++ b/src/iosource/pcap/Source.cc @@ -84,13 +84,12 @@ void PcapSource::OpenLive() props.netmask = PktSrc::NETMASK_UNKNOWN; #endif - // We use the smallest time-out possible to return almost immediately if + // ### We use the smallest time-out possible to return almost immediately if // no packets are available. (We can't use set_nonblocking() as it's // broken on FreeBSD: even when select() indicates that we can read // something, we may get nothing if the store buffer hasn't filled up // yet.) pd = pcap_create(props.path.c_str(), errbuf); - if ( ! pd ) { safe_snprintf(errbuf, sizeof(errbuf), @@ -160,6 +159,19 @@ void PcapSource::OpenLive() // Was closed, couldn't get header size. return; +#ifdef HAVE_PACKET_FANOUT + /* Turn on cluster mode for the device. */ + if ( fanout_enable ) + { + uint32_t fanout_arg = (fanout_method << 16) | (fanout_id & 0xffff); + if (setsockopt(props.selectable_fd, SOL_PACKET, PACKET_FANOUT, &fanout_arg, sizeof(fanout_arg)) == -1) + { + Error(fmt("%s: setsockopt: %s", __FUNCTION__, strerror(errno))); + return; + } + } +#endif + props.is_live = true; Opened(props); diff --git a/src/iosource/pcap/Source.h b/src/iosource/pcap/Source.h index f627e30afa..2f169f7819 100644 --- a/src/iosource/pcap/Source.h +++ b/src/iosource/pcap/Source.h @@ -5,6 +5,13 @@ #include "../PktSrc.h" +#ifdef HAVE_PACKET_FANOUT +extern bool fanout_enable; +extern int fanout_id; +extern int fanout_method; +extern int fanout_flag; +#endif + namespace iosource { namespace pcap { diff --git a/src/main.cc b/src/main.cc index 347d01137e..b7d1bbfa40 100644 --- a/src/main.cc +++ b/src/main.cc @@ -124,6 +124,13 @@ char* proc_status_file = 0; int snaplen = 0; // this gets set from the scripting-layer's value int bufsize = 0; +#ifdef HAVE_PACKET_FANOUT +bool fanout_enable = false; +int fanout_id = 0; +int fanout_method = PACKET_FANOUT_HASH; +int fanout_flag = 0; +#endif + OpaqueType* md5_type = 0; OpaqueType* sha1_type = 0; OpaqueType* sha256_type = 0; @@ -991,7 +998,14 @@ int main(int argc, char** argv) } snaplen = internal_val("snaplen")->AsCount(); - bufsize = internal_val("bufsize")->AsCount() * 1024 * 1024; // Size in Mbytes + bufsize = internal_val("bufsize")->AsCount() * 1024 * 1024; + +#ifdef HAVE_PACKET_FANOUT + fanout_enable = internal_val("Fanout::enable")->AsBool(); + fanout_id = internal_val("Fanout::id")->AsCount(); + fanout_method = internal_val("Fanout::method")->AsEnum(); + fanout_flag = internal_val("Fanout::flag")->AsEnum(); +#endif if ( dns_type != DNS_PRIME ) net_init(interfaces, read_files, writefile, do_watchdog);