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.
pull/3952/head
Eric Leblond 6 years ago committed by Victor Julien
parent aeb2bd3aa1
commit 9206b30fe1

@ -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;

@ -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);
}
}

@ -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);

@ -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) {

@ -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

Loading…
Cancel
Save