From 69d2c8eb750ab20aa8577833ed4fb05d23d89375 Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Sun, 9 Jun 2019 22:09:42 +0200 Subject: [PATCH] ebpf: get rid of hash in map value --- ebpf/xdp_filter.c | 1 - src/flow-hash.c | 13 +++++++++++++ src/flow-hash.h | 1 + src/source-af-packet.c | 20 +++++++++---------- src/util-ebpf.c | 44 ++++++++++++++++++++++++++++++------------ src/util-ebpf.h | 1 - 6 files changed, 55 insertions(+), 25 deletions(-) diff --git a/ebpf/xdp_filter.c b/ebpf/xdp_filter.c index 229a912e6b..ff00cef3f2 100644 --- a/ebpf/xdp_filter.c +++ b/ebpf/xdp_filter.c @@ -90,7 +90,6 @@ struct flowv6_keys { struct pair { __u32 packets; __u32 bytes; - __u32 hash; }; struct bpf_map_def SEC("maps") flow_table_v4 = { diff --git a/src/flow-hash.c b/src/flow-hash.c index 1c795a51a5..4c4b6ae222 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -210,6 +210,19 @@ static inline uint32_t FlowGetHash(const Packet *p) return hash; } +/** + * Basic hashing function for FlowKey + * + * \note Function only used for bypass + * + * \note this is only used at start to create Flow from pinned maps + * so fairness is not an issue + */ +uint32_t FlowKeyGetHash(FlowKey *fk) +{ + return hashword((uint32_t *)fk, sizeof(*fk)/4, flow_config.hash_rand); +} + /* Since two or more flows can have the same hash key, we need to compare * the flow with the current flow key. */ #define CMP_FLOW(f1,f2) \ diff --git a/src/flow-hash.h b/src/flow-hash.h index d70c4d377a..b5853b7d51 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -78,6 +78,7 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *, Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash); Flow *FlowGetExistingFlowFromHash(FlowKey * key, uint32_t hash); +uint32_t FlowKeyGetHash(FlowKey *flow_key); void FlowDisableTcpReuseHandling(void); diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 9645b781a6..52676838d2 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -2294,8 +2294,7 @@ TmEcode AFPSetBPFFilter(AFPThreadVars *ptv) * \param key data to use as key in the table * \return 0 in case of error, 1 if success */ -static int AFPInsertHalfFlow(int mapd, void *key, uint32_t hash, - unsigned int nr_cpus) +static int AFPInsertHalfFlow(int mapd, void *key, unsigned int nr_cpus) { BPF_DECLARE_PERCPU(struct pair, value, nr_cpus); unsigned int i; @@ -2309,7 +2308,6 @@ static int AFPInsertHalfFlow(int mapd, void *key, uint32_t hash, for (i = 0; i < nr_cpus; i++) { 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) { @@ -2409,7 +2407,7 @@ static int AFPBypassCallback(Packet *p) keys[0]->vlan_id[1] = p->vlan_id[1]; keys[0]->ip_proto = IPV4_GET_IPPROTO(p); - if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], p->flow_hash, + if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { SCFree(keys[0]); return 0; @@ -2427,7 +2425,7 @@ static int AFPBypassCallback(Packet *p) keys[1]->vlan_id[1] = p->vlan_id[1]; keys[1]->ip_proto = IPV4_GET_IPPROTO(p); - if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->flow_hash, + if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { SCFree(keys[0]); SCFree(keys[1]); @@ -2458,7 +2456,7 @@ static int AFPBypassCallback(Packet *p) keys[0]->vlan_id[0] = p->vlan_id[0]; keys[0]->vlan_id[1] = p->vlan_id[1]; keys[0]->ip_proto = IPV6_GET_NH(p); - if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], p->flow_hash, + if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { SCFree(keys[0]); return 0; @@ -2477,7 +2475,7 @@ static int AFPBypassCallback(Packet *p) keys[1]->vlan_id[0] = p->vlan_id[0]; keys[1]->vlan_id[1] = p->vlan_id[1]; keys[1]->ip_proto = IPV6_GET_NH(p); - if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->flow_hash, + if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { SCFree(keys[0]); SCFree(keys[1]); @@ -2542,7 +2540,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[0]->vlan_id[0] = p->vlan_id[0]; keys[0]->vlan_id[1] = p->vlan_id[1]; keys[0]->ip_proto = IPV4_GET_IPPROTO(p); - if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], p->flow_hash, + if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { SCFree(keys[0]); return 0; @@ -2559,7 +2557,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->vlan_id[0] = p->vlan_id[0]; keys[1]->vlan_id[1] = p->vlan_id[1]; keys[1]->ip_proto = IPV4_GET_IPPROTO(p); - if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->flow_hash, + if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { SCFree(keys[0]); SCFree(keys[1]); @@ -2590,7 +2588,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[0]->vlan_id[0] = p->vlan_id[0]; keys[0]->vlan_id[1] = p->vlan_id[1]; keys[0]->ip_proto = IPV6_GET_NH(p); - if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], p->flow_hash, + if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[0], p->afp_v.nr_cpus) == 0) { SCFree(keys[0]); return 0; @@ -2609,7 +2607,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->vlan_id[0] = p->vlan_id[0]; keys[1]->vlan_id[1] = p->vlan_id[1]; keys[1]->ip_proto = IPV6_GET_NH(p); - if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->flow_hash, + if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { SCFree(keys[0]); SCFree(keys[1]); diff --git a/src/util-ebpf.c b/src/util-ebpf.c index bc3e1e9cbc..c507494f51 100644 --- a/src/util-ebpf.c +++ b/src/util-ebpf.c @@ -501,11 +501,15 @@ int EBPFSetupXDP(const char *iface, int fd, uint8_t flags) * * \return false (this create function never returns true) */ -static bool EBPFCreateFlowForKey(struct flows_stats *flowstats, FlowKey *flow_key, - uint32_t hash, struct timespec *ctime, - uint64_t pkts_cnt, uint64_t bytes_cnt) +static bool EBPFCreateFlowForKey(struct flows_stats *flowstats, void *key, + FlowKey *flow_key, struct timespec *ctime, + uint64_t pkts_cnt, uint64_t bytes_cnt, + int mapfd, int cpus_count) { - Flow *f = FlowGetFromFlowKey(flow_key, ctime, hash); + Flow *f = NULL; + uint32_t hash = FlowKeyGetHash(flow_key); + + f = FlowGetFromFlowKey(flow_key, ctime, hash); if (f == NULL) return false; @@ -523,6 +527,16 @@ static bool EBPFCreateFlowForKey(struct flows_stats *flowstats, FlowKey *flow_ke fc->BypassFree = EBPFBypassFree; fc->todstpktcnt = pkts_cnt; fc->todstbytecnt = bytes_cnt; + EBPFBypassData *eb = SCCalloc(1, sizeof(EBPFBypassData)); + if (eb == NULL) { + SCFree(fc); + FLOWLOCK_UNLOCK(f); + return false; + } + eb->key[0] = key; + eb->mapfd = mapfd; + eb->cpus_count = cpus_count; + fc->bypass_data = eb; } else { FLOWLOCK_UNLOCK(f); return false; @@ -530,6 +544,10 @@ static bool EBPFCreateFlowForKey(struct flows_stats *flowstats, FlowKey *flow_ke } else { fc->tosrcpktcnt = pkts_cnt; fc->tosrcbytecnt = bytes_cnt; + EBPFBypassData *eb = (EBPFBypassData *) fc->bypass_data; + if (eb) { + eb->key[1] = key; + } } FLOWLOCK_UNLOCK(f); return false; @@ -627,9 +645,10 @@ bool EBPFBypassUpdate(Flow *f, void *data, time_t tsec) return false; } -typedef bool (*OpFlowForKey)(struct flows_stats *flowstats, FlowKey *flow_key, - uint32_t hash, struct timespec *ctime, - uint64_t pkts_cnt, uint64_t bytes_cnt); +typedef bool (*OpFlowForKey)(struct flows_stats *flowstats, void *key, + FlowKey *flow_key, struct timespec *ctime, + uint64_t pkts_cnt, uint64_t bytes_cnt, + int mapfd, int cpus_count); /** * Bypassed flows cleaning for IPv4 @@ -709,9 +728,9 @@ static int EBPFForEachFlowV4Table(ThreadVars *th_v, LiveDevice *dev, const char flow_key.vlan_id[1] = next_key.vlan_id[1]; flow_key.proto = next_key.ip_proto; flow_key.recursion_level = 0; - dead_flow = EBPFOpFlowForKey(flowstats, &flow_key, - BPF_PERCPU(values_array, 0).hash, - ctime, pkts_cnt, bytes_cnt); + dead_flow = EBPFOpFlowForKey(flowstats, &next_key, &flow_key, + ctime, pkts_cnt, bytes_cnt, + mapfd, tcfg->cpus_count); if (dead_flow) { found = 1; } @@ -818,8 +837,9 @@ static int EBPFForEachFlowV6Table(ThreadVars *th_v, 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, BPF_PERCPU(values_array, 0).hash, - ctime, pkts_cnt, bytes_cnt); + pkts_cnt = EBPFOpFlowForKey(flowstats, &next_key, &flow_key, + ctime, pkts_cnt, bytes_cnt, + mapfd, tcfg->cpus_count); if (pkts_cnt > 0) { found = 1; } diff --git a/src/util-ebpf.h b/src/util-ebpf.h index 043f137e8c..818283d7af 100644 --- a/src/util-ebpf.h +++ b/src/util-ebpf.h @@ -58,7 +58,6 @@ struct flowv6_keys { struct pair { uint32_t packets; uint32_t bytes; - uint32_t hash; }; typedef struct EBPFBypassData_ {