From: Eric Leblond Date: Sat, 9 Mar 2019 14:13:26 +0000 (+0100) Subject: ebpf: fix percpu hash handling X-Git-Tag: suricata-5.0.0-rc1~350 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=651a27e4fb9d9a8b56da4b390492140de114b398;p=thirdparty%2Fsuricata.git ebpf: fix percpu hash handling An alignement issue was preventing the code to work properly. We introduce macros taken from Linux source code sample to get something that should work on the long term. --- diff --git a/src/source-af-packet.c b/src/source-af-packet.c index d770050c00..d87776f56c 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -2299,7 +2299,7 @@ static int AFPInsertHalfFlow(int mapd, void *key, uint32_t hash, uint64_t pkts_cnt, uint64_t bytes_cnt, unsigned int nr_cpus) { - struct pair value[nr_cpus]; + BPF_DECLARE_PERCPU(struct pair, value, nr_cpus); unsigned int i; if (mapd == -1) { @@ -2310,12 +2310,13 @@ static int AFPInsertHalfFlow(int mapd, void *key, uint32_t hash, * is not duplicating the data on each CPU by itself. We set the first entry to * the actual flow pkts and bytes count as we need to continue from actual point * to detect an absence of packets in the future. */ - value[0].packets = pkts_cnt; - value[0].bytes = bytes_cnt; - value[0].hash = hash; + BPF_PERCPU(value,0).packets = pkts_cnt; + BPF_PERCPU(value,0).bytes = bytes_cnt; + BPF_PERCPU(value,0).hash = hash; for (i = 1; i < nr_cpus; i++) { - value[i].packets = 0; - value[i].bytes = 0; + BPF_PERCPU(value, i).packets = 0; + BPF_PERCPU(value, i).bytes = 0; + BPF_PERCPU(value, i).hash = hash; } if (bpf_map_update_elem(mapd, key, value, BPF_NOEXIST) != 0) { switch (errno) { diff --git a/src/util-ebpf.c b/src/util-ebpf.c index 7774b25163..4a5f25bd0a 100644 --- a/src/util-ebpf.c +++ b/src/util-ebpf.c @@ -560,7 +560,7 @@ static int EBPFForEachFlowV4Table(LiveDevice *dev, const char *name, pkts_cnt = 0; /* We use a per CPU structure so we will get a array of values. But if nr_cpus * is 1 then we have a global hash. */ - struct pair values_array[tcfg->cpus_count]; + BPF_DECLARE_PERCPU(struct pair, values_array, tcfg->cpus_count); memset(values_array, 0, sizeof(values_array)); int res = bpf_map_lookup_elem(mapfd, &next_key, values_array); if (res < 0) { @@ -572,9 +572,10 @@ static int EBPFForEachFlowV4Table(LiveDevice *dev, const char *name, for (i = 0; i < tcfg->cpus_count; i++) { /* let's start accumulating value so we can compute the counters */ SCLogDebug("%d: Adding pkts %lu bytes %lu", i, - values_array[i].packets, values_array[i].bytes); - pkts_cnt += values_array[i].packets; - bytes_cnt += values_array[i].bytes; + BPF_PERCPU(values_array, i).packets, + BPF_PERCPU(values_array, i).bytes); + pkts_cnt += BPF_PERCPU(values_array, i).packets; + bytes_cnt += BPF_PERCPU(values_array, i).bytes; } /* Get the corresponding Flow in the Flow table to compare and update * its counters and lastseen if needed */ @@ -600,7 +601,8 @@ static int EBPFForEachFlowV4Table(LiveDevice *dev, const char *name, flow_key.vlan_id[1] = next_key.vlan_id[1]; flow_key.proto = next_key.ip_proto; flow_key.recursion_level = 0; - pkts_cnt = EBPFOpFlowForKey(flowstats, &flow_key, values_array[0].hash, + pkts_cnt = EBPFOpFlowForKey(flowstats, &flow_key, + BPF_PERCPU(values_array, 0).hash, ctime, pkts_cnt, bytes_cnt); if (pkts_cnt > 0) { found = 1; @@ -656,7 +658,7 @@ static int EBPFForEachFlowV6Table(LiveDevice *dev, const char *name, pkts_cnt = 0; /* We use a per CPU structure so we will get a array of values. But if nr_cpus * is 1 then we have a global hash. */ - struct pair values_array[tcfg->cpus_count]; + BPF_DECLARE_PERCPU(struct pair, values_array, tcfg->cpus_count); memset(values_array, 0, sizeof(values_array)); int res = bpf_map_lookup_elem(mapfd, &next_key, values_array); if (res < 0) { @@ -667,9 +669,10 @@ static int EBPFForEachFlowV6Table(LiveDevice *dev, const char *name, for (i = 0; i < tcfg->cpus_count; i++) { /* let's start accumulating value so we can compute the counters */ SCLogDebug("%d: Adding pkts %lu bytes %lu", i, - values_array[i].packets, values_array[i].bytes); - pkts_cnt += values_array[i].packets; - bytes_cnt += values_array[i].bytes; + BPF_PERCPU(values_array, i).packets, + BPF_PERCPU(values_array, i).bytes); + pkts_cnt += BPF_PERCPU(values_array, i).packets; + bytes_cnt += BPF_PERCPU(values_array, i).bytes; } /* Get the corresponding Flow in the Flow table to compare and update * its counters and lastseen if needed */ @@ -695,7 +698,7 @@ static int EBPFForEachFlowV6Table(LiveDevice *dev, const char *name, flow_key.vlan_id[1] = next_key.vlan_id[1]; flow_key.proto = next_key.ip_proto; flow_key.recursion_level = 0; - pkts_cnt = EBPFOpFlowForKey(flowstats, &flow_key, values_array[0].hash, + pkts_cnt = EBPFOpFlowForKey(flowstats, &flow_key, BPF_PERCPU(values_array, 0).hash, ctime, pkts_cnt, bytes_cnt); if (pkts_cnt > 0) { found = 1; diff --git a/src/util-ebpf.h b/src/util-ebpf.h index c66c1d9e2e..078870aa4b 100644 --- a/src/util-ebpf.h +++ b/src/util-ebpf.h @@ -88,6 +88,14 @@ int EBPFUpdateFlow(Flow *f, Packet *p, void *data); TmEcode EBPFGetBypassedStats(json_t *cmd, json_t *answer, void *data); #endif +#define __bpf_percpu_val_align __attribute__((__aligned__(8))) + +#define BPF_DECLARE_PERCPU(type, name, nr_cpus) \ + struct { type v; /* padding */ } __bpf_percpu_val_align \ + name[nr_cpus] +#define BPF_PERCPU(name, cpu) name[(cpu)].v + + #endif #endif