StorageInit();
#ifdef HAVE_PACKET_EBPF
EBPFRegisterExtension();
+ LiveDevRegisterExtension();
#endif
AppLayerSetup();
UnixManagerRegisterCommand("iface-stat", LiveDeviceIfaceStat, NULL,
UNIX_CMD_TAKE_ARGS);
UnixManagerRegisterCommand("iface-list", LiveDeviceIfaceList, NULL, 0);
+ UnixManagerRegisterCommand("iface-bypassed-stat",
+ LiveDeviceGetBypassedStats, NULL, 0);
+ /* For backward compatibility */
+ UnixManagerRegisterCommand("ebpf-bypassed-stat",
+ LiveDeviceGetBypassedStats, NULL, 0);
UnixManagerThreadSpawn(0);
-#ifdef HAVE_PACKET_EBPF
- UnixManagerRegisterCommand("ebpf-bypassed-stats", EBPFGetBypassedStats, NULL, 0);
-#endif
}
}
}
#define MAX_DEVNAME 10
+static int g_bypass_storage_id = -1;
+
/**
* \file
*
static TAILQ_HEAD(, LiveDeviceName_) pre_live_devices =
TAILQ_HEAD_INITIALIZER(pre_live_devices);
+typedef struct BypassInfo_ {
+ SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count);
+ SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count);
+} BypassInfo;
+
/** if set to 0 when we don't have real devices */
static int live_devices_stats = 1;
+
static int LiveSafeDeviceName(const char *devname,
char *newdevname, size_t destlen);
SCFree(ld);
}
}
+
+static void LiveDevExtensionFree(void *x)
+{
+ if (x)
+ SCFree(x);
+}
+
+/**
+ * Register bypass stats storage
+ */
+void LiveDevRegisterExtension(void)
+{
+ g_bypass_storage_id = LiveDevStorageRegister("bypass_stats", sizeof(void *),
+ NULL, LiveDevExtensionFree);
+}
+
+/**
+ * Prepare a LiveDevice so we can set bypass stats
+ */
+int LiveDevUseBypass(LiveDevice *dev)
+{
+ BypassInfo *bpinfo = SCCalloc(1, sizeof(*bpinfo));
+ if (bpinfo == NULL) {
+ SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate bypass info structure");
+ return -1;
+ }
+
+ SC_ATOMIC_INIT(bpinfo->ipv4_hash_count);
+ SC_ATOMIC_INIT(bpinfo->ipv4_hash_count);
+
+ LiveDevSetStorageById(dev, g_bypass_storage_id, bpinfo);
+ return 0;
+}
+
+/**
+ * Set number of currently bypassed flows for a protocol family
+ *
+ * \param dev pointer to LiveDevice to set stats for
+ * \param cnt number of currently bypassed flows
+ * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count
+ */
+void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family)
+{
+ BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id);
+ if (bpfdata) {
+ if (family == AF_INET) {
+ SC_ATOMIC_SET(bpfdata->ipv4_hash_count, cnt);
+ } else if (family == AF_INET6) {
+ SC_ATOMIC_SET(bpfdata->ipv6_hash_count, cnt);
+ }
+ }
+}
+
+#ifdef BUILD_UNIX_SOCKET
+TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data)
+{
+ LiveDevice *ldev = NULL, *ndev;
+
+ json_t *ifaces = NULL;
+ while(LiveDeviceForEach(&ldev, &ndev)) {
+ BypassInfo *bpinfo = LiveDevGetStorageById(ldev, g_bypass_storage_id);
+ if (bpinfo) {
+ uint64_t ipv4_hash_count = SC_ATOMIC_GET(bpinfo->ipv4_hash_count);
+ uint64_t ipv6_hash_count = SC_ATOMIC_GET(bpinfo->ipv6_hash_count);
+ json_t *iface = json_object();
+ if (ifaces == NULL) {
+ ifaces = json_object();
+ if (ifaces == NULL) {
+ json_object_set_new(answer, "message",
+ json_string("internal error at json object creation"));
+ return TM_ECODE_FAILED;
+ }
+ }
+ json_object_set_new(iface, "ipv4_count", json_integer(ipv4_hash_count));
+ json_object_set_new(iface, "ipv6_count", json_integer(ipv6_hash_count));
+ json_object_set_new(ifaces, ldev->dev, iface);
+ }
+ }
+ if (ifaces) {
+ json_object_set_new(answer, "message", ifaces);
+ SCReturnInt(TM_ECODE_OK);
+ }
+
+ json_object_set_new(answer, "message",
+ json_string("No interface using bypass"));
+ SCReturnInt(TM_ECODE_FAILED);
+}
+#endif
TAILQ_ENTRY(LiveDeviceName_) next;
} LiveDeviceName;
+void LiveDevRegisterExtension(void);
+
int LiveRegisterDeviceName(const char *dev);
int LiveRegisterDevice(const char *dev);
+int LiveDevUseBypass(LiveDevice *dev);
+void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family);
int LiveGetDeviceCount(void);
const char *LiveGetDeviceName(int number);
LiveDevice *LiveGetDevice(const char *dev);
#ifdef BUILD_UNIX_SOCKET
TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *server_msg, void *data);
TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *server_msg, void *data);
+TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data);
#endif
#endif /* __UTIL_DEVICE_H__ */
struct bpf_maps_info {
struct bpf_map_item array[BPF_MAP_MAX_COUNT];
- SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count);
- SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count);
int last;
};
SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate bpf map array");
return -1;
}
- SC_ATOMIC_INIT(bpf_map_data->ipv4_hash_count);
- SC_ATOMIC_INIT(bpf_map_data->ipv6_hash_count);
+
if (config->mode == AFP_MODE_XDP_BYPASS) {
bpf_map_data->array[0].fd = fd_v4;
bpf_map_data->array[0].name = SCStrdup("flow_table_v4");
/* Attach the bpf_maps_info to the LiveDevice via the device storage */
LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data);
+ /* Declare that device will use bypass stats */
+ LiveDevUseBypass(livedev);
return 0;
SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate bpf map array");
return -1;
}
- SC_ATOMIC_INIT(bpf_map_data->ipv4_hash_count);
- SC_ATOMIC_INIT(bpf_map_data->ipv6_hash_count);
/* Store the maps in bpf_maps_info:: */
bpf_map__for_each(map, bpfobj) {
/* Attach the bpf_maps_info to the LiveDevice via the device storage */
LiveDevSetStorageById(livedev, g_livedev_storage_id, bpf_map_data);
+ LiveDevUseBypass(livedev);
/* Finally we get the file descriptor for our eBPF program. We will use
* the fd to attach the program to the socket (eBPF case) or to the device
}
SC_ATOMIC_ADD(dev->bypassed, flowstats->packets);
- struct bpf_maps_info *bpfdata = LiveDevGetStorageById(dev, g_livedev_storage_id);
- if (bpfdata) {
- SC_ATOMIC_SET(bpfdata->ipv4_hash_count, hash_cnt);
- }
+ LiveDevSetBypassStats(dev, hash_cnt, AF_INET);
return found;
}
}
SC_ATOMIC_ADD(dev->bypassed, flowstats->packets);
- struct bpf_maps_info *bpfdata = LiveDevGetStorageById(dev, g_livedev_storage_id);
- if (bpfdata) {
- SC_ATOMIC_SET(bpfdata->ipv6_hash_count, hash_cnt);
- }
+ LiveDevSetBypassStats(dev, hash_cnt, AF_INET6);
return found;
}
return ret;
}
-#ifdef BUILD_UNIX_SOCKET
-TmEcode EBPFGetBypassedStats(json_t *cmd, json_t *answer, void *data)
-{
- LiveDevice *ldev = NULL, *ndev;
-
- json_t *ifaces = NULL;
- while(LiveDeviceForEach(&ldev, &ndev)) {
- struct bpf_maps_info *bpfdata = LiveDevGetStorageById(ldev, g_livedev_storage_id);
- if (bpfdata) {
- uint64_t ipv4_hash_count = SC_ATOMIC_GET(bpfdata->ipv4_hash_count);
- uint64_t ipv6_hash_count = SC_ATOMIC_GET(bpfdata->ipv6_hash_count);
- json_t *iface = json_object();
- if (ifaces == NULL) {
- ifaces = json_object();
- if (ifaces == NULL) {
- json_object_set_new(answer, "message",
- json_string("internal error at json object creation"));
- return TM_ECODE_FAILED;
- }
- }
- json_object_set_new(iface, "ipv4_count", json_integer(ipv4_hash_count));
- json_object_set_new(iface, "ipv6_count", json_integer(ipv6_hash_count));
- json_object_set_new(ifaces, ldev->dev, iface);
- }
- }
- if (ifaces) {
- json_object_set_new(answer, "message", ifaces);
- SCReturnInt(TM_ECODE_OK);
- }
-
- json_object_set_new(answer, "message",
- json_string("No interface using eBPF bypass"));
- SCReturnInt(TM_ECODE_FAILED);
-}
-#endif
-
void EBPFRegisterExtension(void)
{
g_livedev_storage_id = LiveDevStorageRegister("bpfmap", sizeof(void *), NULL, BpfMapsInfoFree);