-/* Copyright (C) 2016 Open Information Security Foundation
+/* Copyright (C) 2016-2017 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "flow-private.h"
#include "util-ebpf.h"
-#define BYPASSED_FLOW_TIMEOUT 60
#define FLOW_BYPASS_DELAY 10
typedef struct BypassedFlowManagerThreadData_ {
uint16_t flow_bypassed_bytes;
} BypassedFlowManagerThreadData;
-#ifdef HAVE_PACKET_EBPF
-
-static int BypassedFlowV4Timeout(int fd, struct flowv4_keys *key, struct pair *value, void *data)
-{
- struct timespec *curtime = (struct timespec *)data;
- SCLogDebug("Got curtime %" PRIu64 " and value %" PRIu64 " (sp:%d, dp:%d) %u",
- curtime->tv_sec, value->time / 1000000000,
- key->port16[0], key->port16[1], key->ip_proto
- );
-
- if (curtime->tv_sec - value->time / 1000000000 > BYPASSED_FLOW_TIMEOUT) {
- SCLogDebug("Got no packet for %d -> %d at %" PRIu64,
- key->port16[0], key->port16[1], value->time);
- return 1;
- }
- return 0;
-}
-
-static int BypassedFlowV6Timeout(int fd, struct flowv6_keys *key, struct pair *value, void *data)
-{
- struct timespec *curtime = (struct timespec *)data;
- SCLogDebug("Got curtime %" PRIu64 " and value %" PRIu64 " (sp:%d, dp:%d)",
- curtime->tv_sec, value->time / 1000000000,
- key->port16[0], key->port16[1]
- );
-
- if (curtime->tv_sec - value->time / 1000000000 > BYPASSED_FLOW_TIMEOUT) {
- SCLogDebug("Got no packet for %d -> %d at %" PRIu64,
- key->port16[0], key->port16[1], value->time);
- EBPFDeleteKey(fd, key);
- return 1;
- }
- return 0;
-}
-
-#endif
+#define BYPASSFUNCMAX 4
+int g_bypassed_func_max_index = 0;
+BypassedCheckFunc BypassedFuncList[BYPASSFUNCMAX];
static TmEcode BypassedFlowManager(ThreadVars *th_v, void *thread_data)
{
BypassedFlowManagerThreadData *ftd = thread_data;
while (1) {
+ int i;
SCLogDebug("Dumping the table");
struct timespec curtime;
- struct flows_stats bypassstats = { 0, 0, 0};
if (clock_gettime(CLOCK_MONOTONIC, &curtime) != 0) {
SCLogWarning(SC_ERR_INVALID_VALUE, "Can't get time: %s (%d)",
strerror(errno), errno);
sleep(1);
continue;
}
- /* TODO indirection here: AF_PACKET and NFQ should be able to give their iterate function */
- tcount = EBPFForEachFlowV4Table("flow_table_v4", BypassedFlowV4Timeout, &bypassstats, &curtime);
- if (tcount) {
- StatsAddUI64(th_v, ftd->flow_bypassed_cnt_clo, (uint64_t)bypassstats.count);
- StatsAddUI64(th_v, ftd->flow_bypassed_pkts, (uint64_t)bypassstats.packets);
- StatsAddUI64(th_v, ftd->flow_bypassed_bytes, (uint64_t)bypassstats.bytes);
- }
- memset(&bypassstats, 0, sizeof(bypassstats));
- /* TODO indirection here: AF_PACKET and NFQ should be able to give their iterate function */
- tcount = EBPFForEachFlowV6Table("flow_table_v6", BypassedFlowV6Timeout, &bypassstats, &curtime);
- if (tcount) {
- StatsAddUI64(th_v, ftd->flow_bypassed_cnt_clo, (uint64_t)bypassstats.count);
- StatsAddUI64(th_v, ftd->flow_bypassed_pkts, (uint64_t)bypassstats.packets);
- StatsAddUI64(th_v, ftd->flow_bypassed_bytes, (uint64_t)bypassstats.bytes);
+ for (i = 0; i < g_bypassed_func_max_index; i++) {
+ struct flows_stats bypassstats = { 0, 0, 0};
+ tcount = BypassedFuncList[i](&bypassstats, &curtime);
+ if (tcount) {
+ StatsAddUI64(th_v, ftd->flow_bypassed_cnt_clo, (uint64_t)bypassstats.count);
+ StatsAddUI64(th_v, ftd->flow_bypassed_pkts, (uint64_t)bypassstats.packets);
+ StatsAddUI64(th_v, ftd->flow_bypassed_bytes, (uint64_t)bypassstats.bytes);
+ }
}
if (TmThreadsCheckFlag(th_v, THV_KILL)) {
return;
#endif
-#ifdef HAVE_PACKET_EBPF
ThreadVars *tv_flowmgr = NULL;
tv_flowmgr = TmThreadCreateMgmtThreadByName("BypassedFlowManager",
"BypassedFlowManager", 0);
printf("ERROR: TmThreadSpawn failed\n");
exit(1);
}
-#endif
+}
+
+int BypassedFlowManagerRegisterCheckFunc(BypassedCheckFunc CheckFunc)
+{
+ if (!CheckFunc) {
+ return -1;
+ }
+ if (g_bypassed_func_max_index < BYPASSFUNCMAX) {
+ BypassedFuncList[g_bypassed_func_max_index] = CheckFunc;
+ g_bypassed_func_max_index++;
+ } else {
+ return -1;
+ }
+ return 0;
}
void TmModuleBypassedFlowManagerRegister (void)
#ifndef __FLOW_BYPASS_H__
#define __FLOW_BYPASS_H__
+struct flows_stats {
+ uint64_t count;
+ uint64_t packets;
+ uint64_t bytes;
+};
+
+typedef int (*BypassedCheckFunc)(struct flows_stats *bypassstats,
+ struct timespec *curtime);
+
void FlowAddToBypassed(Flow *f);
void BypassedFlowManagerThreadSpawn(void);
void TmModuleBypassedFlowManagerRegister(void);
+int BypassedFlowManagerRegisterCheckFunc(BypassedCheckFunc CheckFunc);
+
#endif
#include "alert-unified2-alert.h"
#include "alert-debuglog.h"
+#include "flow-bypass.h"
+
#include "util-debug.h"
#include "util-time.h"
#include "util-cpu.h"
aconf->ebpf_filter_file = ebpf_file;
ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
if (conf_val) {
+#ifdef HAVE_PACKET_EBPF
SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
aconf->iface);
aconf->flags |= AFP_BYPASS;
RunModeEnablesBypassManager();
+ BypassedFlowManagerRegisterCheckFunc(EBPFCheckBypassedFlowTimeout);
+#else
+ SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but eBPF support is not built-in");
+#endif
}
}
aconf->xdp_filter_file = ebpf_file;
ConfGetChildValueBoolWithDefault(if_root, if_default, "bypass", &conf_val);
if (conf_val) {
+#ifdef HAVE_PACKET_XDP
SCLogConfig("Using bypass kernel functionality for AF_PACKET (iface %s)",
aconf->iface);
aconf->flags |= AFP_XDPBYPASS;
RunModeEnablesBypassManager();
+ BypassedFlowManagerRegisterCheckFunc(EBPFCheckBypassedFlowTimeout);
+#else
+ SCLogError(SC_ERR_UNIMPLEMENTED, "Bypass set but XDP support is not built-in");
+#endif
}
#ifdef HAVE_PACKET_XDP
const char *xdp_mode;
#define SC_PCAP_DONT_INCLUDE_PCAP_H 1
#include "suricata-common.h"
+#include "flow-bypass.h"
#ifdef HAVE_PACKET_EBPF
#define BPF_MAP_MAX_COUNT 16
+#define BYPASSED_FLOW_TIMEOUT 60
+
struct bpf_map_item {
const char * name;
int fd;
static struct bpf_map_item bpf_map_array[BPF_MAP_MAX_COUNT];
static int bpf_map_last = 0;
+static void EBPFDeleteKey(int fd, void *key)
+{
+ bpf_map_delete_elem(fd, key);
+}
+
int EBPFGetMapFDByName(const char *name)
{
int i;
}
-int EBPFForEachFlowV4Table(const char *name,
+static int EBPFForEachFlowV4Table(const char *name,
int (*FlowCallback)(int fd, struct flowv4_keys *key, struct pair *value, void *data),
struct flows_stats *flowstats,
void *data)
return found;
}
-int EBPFForEachFlowV6Table(const char *name,
+static int EBPFForEachFlowV6Table(const char *name,
int (*FlowCallback)(int fd, struct flowv6_keys *key, struct pair *value, void *data),
struct flows_stats *flowstats,
void *data)
return found;
}
-void EBPFDeleteKey(int fd, void *key)
+static int EBPFBypassedFlowV4Timeout(int fd, struct flowv4_keys *key, struct pair *value, void *data)
{
- bpf_map_delete_elem(fd, key);
+ struct timespec *curtime = (struct timespec *)data;
+ SCLogDebug("Got curtime %" PRIu64 " and value %" PRIu64 " (sp:%d, dp:%d) %u",
+ curtime->tv_sec, value->time / 1000000000,
+ key->port16[0], key->port16[1], key->ip_proto
+ );
+
+ if (curtime->tv_sec - value->time / 1000000000 > BYPASSED_FLOW_TIMEOUT) {
+ SCLogDebug("Got no packet for %d -> %d at %" PRIu64,
+ key->port16[0], key->port16[1], value->time);
+ return 1;
+ }
+ return 0;
+}
+
+static int EBPFBypassedFlowV6Timeout(int fd, struct flowv6_keys *key, struct pair *value, void *data)
+{
+ struct timespec *curtime = (struct timespec *)data;
+ SCLogDebug("Got curtime %" PRIu64 " and value %" PRIu64 " (sp:%d, dp:%d)",
+ curtime->tv_sec, value->time / 1000000000,
+ key->port16[0], key->port16[1]
+ );
+
+ if (curtime->tv_sec - value->time / 1000000000 > BYPASSED_FLOW_TIMEOUT) {
+ SCLogDebug("Got no packet for %d -> %d at %" PRIu64,
+ key->port16[0], key->port16[1], value->time);
+ EBPFDeleteKey(fd, key);
+ return 1;
+ }
+ return 0;
+}
+
+int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats,
+ struct timespec *curtime)
+{
+ struct flows_stats l_bypassstats = { 0, 0, 0};
+ int ret = 0;
+ int tcount = 0;
+ tcount = EBPFForEachFlowV4Table("flow_table_v4", EBPFBypassedFlowV4Timeout,
+ &l_bypassstats, curtime);
+ if (tcount) {
+ bypassstats->count = l_bypassstats.count;
+ bypassstats->packets = l_bypassstats.packets ;
+ bypassstats->bytes = l_bypassstats.bytes;
+ ret = 1;
+ }
+ memset(&l_bypassstats, 0, sizeof(l_bypassstats));
+ tcount = EBPFForEachFlowV6Table("flow_table_v6", EBPFBypassedFlowV6Timeout,
+ &l_bypassstats, curtime);
+ if (tcount) {
+ bypassstats->count += l_bypassstats.count;
+ bypassstats->packets += l_bypassstats.packets ;
+ bypassstats->bytes += l_bypassstats.bytes;
+ ret = 1;
+ }
+ return ret;
}
#endif
#define XDP_FLAGS_DRV_MODE (1U << 2)
#define XDP_FLAGS_HW_MODE (1U << 3)
-
+#include "flow-bypass.h"
struct flowv4_keys {
__be32 src;
uint64_t bytes;
} __attribute__((__aligned__(8)));
-struct flows_stats {
- uint64_t count;
- uint64_t packets;
- uint64_t bytes;
-};
-
#define EBPF_SOCKET_FILTER (1<<0)
#define EBPF_XDP_CODE (1<<1)
int EBPFLoadFile(const char *path, const char * section, int *val, uint8_t flags);
int EBPFSetupXDP(const char *iface, int fd, uint8_t flags);
-int EBPFForEachFlowV4Table(const char *name,
- int (*FlowCallback)(int fd, struct flowv4_keys *key, struct pair *value, void *data),
- struct flows_stats *flowstats,
- void *data);
-int EBPFForEachFlowV6Table(const char *name,
- int (*FlowCallback)(int fd, struct flowv6_keys *key, struct pair *value, void *data),
- struct flows_stats *flowstats,
- void *data);
-void EBPFDeleteKey(int fd, void *key);
+int EBPFCheckBypassedFlowTimeout(struct flows_stats *bypassstats,
+ struct timespec *curtime);
#endif