From: Eric Leblond Date: Mon, 10 Jun 2019 14:40:47 +0000 (+0200) Subject: af-packet: better accounting and error handling X-Git-Tag: suricata-5.0.0-rc1~293 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9206b30fe14060ad4b5f01f079fe8987e60bef8e;p=thirdparty%2Fsuricata.git af-packet: better accounting and error handling This patch improves the bypass error handling add adds more counters to the interface so it is possible to get a view on success and failure of insertion in the eBPF maps via the `iface-bypassed-stat` command. --- diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 68ad9acfd3..31eb5f6547 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -2331,12 +2331,16 @@ static int AFPInsertHalfFlow(int mapd, void *key, unsigned int nr_cpus) return 1; } -static int AFPSetFlowStorage(Packet *p, int map_fd, void *key0, void* key1) +static int AFPSetFlowStorage(Packet *p, int map_fd, void *key0, void* key1, + int family) { FlowBypassInfo *fc = FlowGetStorageById(p->flow, GetFlowBypassInfoID()); if (fc) { EBPFBypassData *eb = SCCalloc(1, sizeof(EBPFBypassData)); if (eb == NULL) { + EBPFDeleteKey(map_fd, key0); + EBPFDeleteKey(map_fd, key1); + LiveDevAddBypassFail(p->livedev, 1, family); SCFree(key0); SCFree(key1); return 0; @@ -2348,7 +2352,16 @@ static int AFPSetFlowStorage(Packet *p, int map_fd, void *key0, void* key1) fc->BypassUpdate = EBPFBypassUpdate; fc->BypassFree = EBPFBypassFree; fc->bypass_data = eb; + } else { + EBPFDeleteKey(map_fd, key0); + EBPFDeleteKey(map_fd, key1); + LiveDevAddBypassFail(p->livedev, 1, family); + SCFree(key0); + SCFree(key1); + return 0; } + + LiveDevAddBypassStats(p->livedev, 1, family); return 1; } @@ -2413,11 +2426,14 @@ static int AFPBypassCallback(Packet *p) } if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { + LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); return 0; } keys[1]= SCCalloc(1, sizeof(struct flowv4_keys)); if (keys[1] == NULL) { + EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]); + LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); return 0; } @@ -2431,13 +2447,14 @@ static int AFPBypassCallback(Packet *p) keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { + EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]); + LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); SCFree(keys[1]); return 0; } EBPFUpdateFlow(p->flow, p, NULL); - LiveDevAddBypassStats(p->livedev, 1, AF_INET); - return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1]); + return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1], AF_INET); } /* For IPv6 case we don't handle extended header in eBPF */ if (PKT_IS_IPV6(p) && @@ -2450,6 +2467,7 @@ static int AFPBypassCallback(Packet *p) struct flowv6_keys *keys[2]; keys[0] = SCCalloc(1, sizeof(struct flowv6_keys)); if (keys[0] == NULL) { + LiveDevAddBypassFail(p->livedev, 1, AF_INET6); return 0; } for (i = 0; i < 4; i++) { @@ -2468,11 +2486,14 @@ static int AFPBypassCallback(Packet *p) } if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { + LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); return 0; } keys[1]= SCCalloc(1, sizeof(struct flowv6_keys)); if (keys[1] == NULL) { + EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]); + LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); return 0; } @@ -2488,14 +2509,15 @@ static int AFPBypassCallback(Packet *p) keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { + EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]); + LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); SCFree(keys[1]); return 0; } if (p->flow) EBPFUpdateFlow(p->flow, p, NULL); - LiveDevAddBypassStats(p->livedev, 1, AF_INET6); - return AFPSetFlowStorage(p, p->afp_v.v6_map_fd, keys[0], keys[1]); + return AFPSetFlowStorage(p, p->afp_v.v6_map_fd, keys[0], keys[1], AF_INET6); } #endif return 0; @@ -2537,6 +2559,7 @@ static int AFPXDPBypassCallback(Packet *p) struct flowv4_keys *keys[2]; keys[0]= SCCalloc(1, sizeof(struct flowv4_keys)); if (keys[0] == NULL) { + LiveDevAddBypassFail(p->livedev, 1, AF_INET); return 0; } if (p->afp_v.v4_map_fd == -1) { @@ -2558,11 +2581,14 @@ static int AFPXDPBypassCallback(Packet *p) } if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { + LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); return 0; } keys[1]= SCCalloc(1, sizeof(struct flowv4_keys)); if (keys[1] == NULL) { + EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]); + LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); return 0; } @@ -2575,12 +2601,13 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { + EBPFDeleteKey(p->afp_v.v4_map_fd, keys[0]); + LiveDevAddBypassFail(p->livedev, 1, AF_INET); SCFree(keys[0]); SCFree(keys[1]); return 0; } - LiveDevAddBypassStats(p->livedev, 1, AF_INET); - return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1]); + return AFPSetFlowStorage(p, p->afp_v.v4_map_fd, keys[0], keys[1], AF_INET); } /* For IPv6 case we don't handle extended header in eBPF */ if (PKT_IS_IPV6(p) && @@ -2611,11 +2638,14 @@ static int AFPXDPBypassCallback(Packet *p) } if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { + LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); return 0; } keys[1]= SCCalloc(1, sizeof(struct flowv6_keys)); if (keys[1] == NULL) { + EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]); + LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); return 0; } @@ -2630,12 +2660,13 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { + EBPFDeleteKey(p->afp_v.v6_map_fd, keys[0]); + LiveDevAddBypassFail(p->livedev, 1, AF_INET6); SCFree(keys[0]); SCFree(keys[1]); return 0; } - LiveDevAddBypassStats(p->livedev, 1, AF_INET6); - return AFPSetFlowStorage(p, p->afp_v.v6_map_fd, keys[0], keys[1]); + return AFPSetFlowStorage(p, p->afp_v.v6_map_fd, keys[0], keys[1], AF_INET6); } #endif return 0; diff --git a/src/util-device.c b/src/util-device.c index fd4b598a07..73d7c0a867 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -49,7 +49,11 @@ static TAILQ_HEAD(, LiveDeviceName_) pre_live_devices = typedef struct BypassInfo_ { SC_ATOMIC_DECLARE(uint64_t, ipv4_hash_count); + SC_ATOMIC_DECLARE(uint64_t, ipv4_fail); + SC_ATOMIC_DECLARE(uint64_t, ipv4_success); SC_ATOMIC_DECLARE(uint64_t, ipv6_hash_count); + SC_ATOMIC_DECLARE(uint64_t, ipv6_fail); + SC_ATOMIC_DECLARE(uint64_t, ipv6_success); } BypassInfo; /** if set to 0 when we don't have real devices */ @@ -526,8 +530,10 @@ void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family) if (bpfdata) { if (family == AF_INET) { SC_ATOMIC_ADD(bpfdata->ipv4_hash_count, cnt); + SC_ATOMIC_ADD(bpfdata->ipv4_success, cnt); } else if (family == AF_INET6) { SC_ATOMIC_ADD(bpfdata->ipv6_hash_count, cnt); + SC_ATOMIC_ADD(bpfdata->ipv6_success, cnt); } } } @@ -551,6 +557,27 @@ void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family) } } +/** + * Increase number of failed captured flows for a protocol family + * + * \param dev pointer to LiveDevice to set stats for + * \param cnt number of flows to add + * \param family AF_INET to set IPv4 count or AF_INET6 to set IPv6 count + */ +void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family) +{ + BypassInfo *bpfdata = LiveDevGetStorageById(dev, g_bypass_storage_id); + if (bpfdata) { + if (family == AF_INET) { + SC_ATOMIC_ADD(bpfdata->ipv4_fail, cnt); + } else if (family == AF_INET6) { + SC_ATOMIC_ADD(bpfdata->ipv6_fail, cnt); + } + } +} + + + #ifdef BUILD_UNIX_SOCKET TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data) { @@ -562,6 +589,10 @@ TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data) 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); + uint64_t ipv4_success = SC_ATOMIC_GET(bpinfo->ipv4_success); + uint64_t ipv4_fail = SC_ATOMIC_GET(bpinfo->ipv4_fail); + uint64_t ipv6_success = SC_ATOMIC_GET(bpinfo->ipv6_success); + uint64_t ipv6_fail = SC_ATOMIC_GET(bpinfo->ipv6_fail); json_t *iface = json_object(); if (ifaces == NULL) { ifaces = json_object(); @@ -571,8 +602,12 @@ TmEcode LiveDeviceGetBypassedStats(json_t *cmd, json_t *answer, void *data) 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(iface, "ipv4_maps_count", json_integer(ipv4_hash_count)); + json_object_set_new(iface, "ipv4_success", json_integer(ipv4_success)); + json_object_set_new(iface, "ipv4_fail", json_integer(ipv4_fail)); + json_object_set_new(iface, "ipv6_maps_count", json_integer(ipv6_hash_count)); + json_object_set_new(iface, "ipv6_success", json_integer(ipv6_success)); + json_object_set_new(iface, "ipv6_fail", json_integer(ipv6_fail)); json_object_set_new(ifaces, ldev->dev, iface); } } diff --git a/src/util-device.h b/src/util-device.h index 9765ec224e..27f60179ac 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -68,6 +68,7 @@ int LiveDevUseBypass(LiveDevice *dev); void LiveDevSetBypassStats(LiveDevice *dev, uint64_t cnt, int family); void LiveDevAddBypassStats(LiveDevice *dev, uint64_t cnt, int family); void LiveDevSubBypassStats(LiveDevice *dev, uint64_t cnt, int family); +void LiveDevAddBypassFail(LiveDevice *dev, uint64_t cnt, int family); int LiveGetDeviceCount(void); const char *LiveGetDeviceName(int number); LiveDevice *LiveGetDevice(const char *dev); diff --git a/src/util-ebpf.c b/src/util-ebpf.c index 7117d0aa7b..59f434a4cf 100644 --- a/src/util-ebpf.c +++ b/src/util-ebpf.c @@ -125,7 +125,7 @@ static void BypassedListFree(void *ifl) } } -static void EBPFDeleteKey(int fd, void *key) +void EBPFDeleteKey(int fd, void *key) { int ret = bpf_map_delete_elem(fd, key); if (ret < 0) { diff --git a/src/util-ebpf.h b/src/util-ebpf.h index f66cc7c955..83e36f88a8 100644 --- a/src/util-ebpf.h +++ b/src/util-ebpf.h @@ -93,6 +93,8 @@ int EBPFUpdateFlow(Flow *f, Packet *p, void *data); bool EBPFBypassUpdate(Flow *f, void *data, time_t tsec); void EBPFBypassFree(void *data); +void EBPFDeleteKey(int fd, void *key); + #ifdef BUILD_UNIX_SOCKET TmEcode EBPFGetBypassedStats(json_t *cmd, json_t *answer, void *data); #endif