33 #define SC_PCAP_DONT_INCLUDE_PCAP_H 1
38 #ifdef HAVE_PACKET_EBPF
41 #include <sys/resource.h>
54 #include <bpf/libbpf.h>
59 #define BPF_MAP_MAX_COUNT 16
71 struct bpf_maps_info {
72 struct bpf_map_item array[BPF_MAP_MAX_COUNT];
76 typedef struct BypassedIfaceList_ {
78 struct BypassedIfaceList_ *
next;
81 static void BpfMapsInfoFree(
void *bpf)
83 struct bpf_maps_info *bpfinfo = (
struct bpf_maps_info *)bpf;
85 for (i = 0; i < bpfinfo->last; i ++) {
86 if (bpfinfo->array[i].name) {
87 if (bpfinfo->array[i].to_unlink) {
88 char pinnedpath[PATH_MAX];
89 int ret = snprintf(pinnedpath,
sizeof(pinnedpath),
90 "/sys/fs/bpf/suricata-%s-%s",
91 bpfinfo->array[i].iface,
92 bpfinfo->array[i].name);
95 ret = unlink(pinnedpath);
99 "Unable to remove %s: %s (%d)", pinnedpath, strerror(error), error);
102 SCLogWarning(
"Unable to remove map %s", bpfinfo->array[i].name);
105 SCFree(bpfinfo->array[i].name);
111 static void BypassedListFree(
void *ifl)
113 BypassedIfaceList *mifl = (BypassedIfaceList *)ifl;
114 BypassedIfaceList *nifl;
122 void EBPFDeleteKey(
int fd,
void *key)
124 int ret = bpf_map_delete_elem(fd, key);
126 SCLogWarning(
"Unable to delete entry: %s (%d)", strerror(errno), errno);
130 static struct bpf_maps_info *EBPFGetBpfMap(
const char *iface)
137 return (
struct bpf_maps_info *)data;
147 int EBPFGetMapFDByName(
const char *iface,
const char *
name)
151 if (iface == NULL ||
name == NULL)
153 struct bpf_maps_info *bpf_maps = EBPFGetBpfMap(iface);
154 if (bpf_maps == NULL)
157 for (i = 0; i < BPF_MAP_MAX_COUNT; i++) {
158 if (!bpf_maps->array[i].name)
160 if (!strcmp(bpf_maps->array[i].name,
name)) {
161 SCLogDebug(
"Got fd %d for eBPF map '%s'", bpf_maps->array[i].fd,
name);
162 return bpf_maps->array[i].fd;
169 static int EBPFLoadPinnedMapsFile(
LiveDevice *livedev,
const char *file)
171 char pinnedpath[1024];
172 snprintf(pinnedpath,
sizeof(pinnedpath),
173 "/sys/fs/bpf/suricata-%s-%s",
177 return bpf_obj_get(pinnedpath);
180 static int EBPFLoadPinnedMaps(
LiveDevice *livedev,
struct ebpf_timeout_config *config)
182 int fd_v4 = -1, fd_v6 = -1;
185 if (config->pinned_maps_name) {
186 int ret = EBPFLoadPinnedMapsFile(livedev, config->pinned_maps_name);
193 if (config->mode == AFP_MODE_XDP_BYPASS) {
195 fd_v4 = EBPFLoadPinnedMapsFile(livedev,
"flow_table_v4");
201 fd_v6 = EBPFLoadPinnedMapsFile(livedev,
"flow_table_v6");
203 SCLogWarning(
"Found a flow_table_v4 map but no flow_table_v6 map");
208 struct bpf_maps_info *bpf_map_data =
SCCalloc(1,
sizeof(*bpf_map_data));
209 if (bpf_map_data == NULL) {
214 if (config->mode == AFP_MODE_XDP_BYPASS) {
215 bpf_map_data->array[0].fd = fd_v4;
216 bpf_map_data->array[0].name =
SCStrdup(
"flow_table_v4");
217 if (bpf_map_data->array[0].name == NULL) {
220 bpf_map_data->array[1].fd = fd_v6;
221 bpf_map_data->array[1].name =
SCStrdup(
"flow_table_v6");
222 if (bpf_map_data->array[1].name == NULL) {
225 bpf_map_data->last = 2;
227 bpf_map_data->last = 0;
231 int fd = EBPFLoadPinnedMapsFile(livedev,
"cpu_map");
233 bpf_map_data->array[bpf_map_data->last].fd = fd;
234 bpf_map_data->array[bpf_map_data->last].name =
SCStrdup(
"cpu_map");
235 if (bpf_map_data->array[bpf_map_data->last].name == NULL) {
238 bpf_map_data->last++;
240 fd = EBPFLoadPinnedMapsFile(livedev,
"cpus_available");
242 bpf_map_data->array[bpf_map_data->last].fd = fd;
243 bpf_map_data->array[bpf_map_data->last].name =
SCStrdup(
"cpus_available");
244 if (bpf_map_data->array[bpf_map_data->last].name == NULL) {
247 bpf_map_data->last++;
249 fd = EBPFLoadPinnedMapsFile(livedev,
"tx_peer");
251 bpf_map_data->array[bpf_map_data->last].fd = fd;
252 bpf_map_data->array[bpf_map_data->last].name =
SCStrdup(
"tx_peer");
253 if (bpf_map_data->array[bpf_map_data->last].name == NULL) {
256 bpf_map_data->last++;
258 fd = EBPFLoadPinnedMapsFile(livedev,
"tx_peer_int");
260 bpf_map_data->array[bpf_map_data->last].fd = fd;
261 bpf_map_data->array[bpf_map_data->last].name =
SCStrdup(
"tx_peer_int");
262 if (bpf_map_data->array[bpf_map_data->last].name == NULL) {
265 bpf_map_data->last++;
276 for (
int i = 0; i < bpf_map_data->last; i++) {
277 SCFree(bpf_map_data->array[i].name);
279 bpf_map_data->last = 0;
296 int EBPFLoadFile(
const char *iface,
const char *path,
const char * section,
297 int *val,
struct ebpf_timeout_config *config)
301 struct bpf_object *bpfobj = NULL;
302 struct bpf_program *bpfprog = NULL;
303 struct bpf_map *map = NULL;
311 if (config->flags & EBPF_XDP_CODE && config->flags & EBPF_PINNED_MAPS) {
313 if (EBPFLoadPinnedMaps(livedev, config) == 0) {
314 SCLogInfo(
"Loaded pinned maps, will use already loaded eBPF filter");
320 SCLogError(
"No file defined to load eBPF from");
326 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
327 if (setrlimit(RLIMIT_MEMLOCK, &r) != 0) {
328 SCLogError(
"Unable to lock memory: %s (%d)", strerror(errno), errno);
333 bpfobj = bpf_object__open(path);
334 long error = libbpf_get_error(bpfobj);
337 libbpf_strerror(error, err_buf,
339 SCLogError(
"Unable to load eBPF objects in '%s': %s", path, err_buf);
343 if (config->flags & EBPF_XDP_HW_MODE) {
344 unsigned int ifindex = if_nametoindex(iface);
345 bpf_object__for_each_program(bpfprog, bpfobj) {
346 bpf_program__set_ifindex(bpfprog, ifindex);
348 bpf_map__for_each(map, bpfobj) {
349 bpf_map__set_ifindex(map, ifindex);
354 bpf_object__for_each_program(bpfprog, bpfobj) {
355 #ifdef HAVE_BPF_PROGRAM__SECTION_NAME
356 const char *title = bpf_program__section_name(bpfprog);
358 const char *title = bpf_program__title(bpfprog, 0);
360 if (!strcmp(title, section)) {
361 if (config->flags & EBPF_SOCKET_FILTER) {
362 #ifdef HAVE_BPF_PROGRAM__SET_TYPE
363 bpf_program__set_type(bpfprog, BPF_PROG_TYPE_SOCKET_FILTER);
366 bpf_program__set_socket_filter(bpfprog);
369 #ifdef HAVE_BPF_PROGRAM__SET_TYPE
370 bpf_program__set_type(bpfprog, BPF_PROG_TYPE_XDP);
373 bpf_program__set_xdp(bpfprog);
382 SCLogError(
"No section '%s' in '%s' file. Will not be able to use the file", section, path);
386 err = bpf_object__load(bpfobj);
389 SCLogError(
"Permission issue when loading eBPF object"
390 " (check libbpf error on stdout)");
393 libbpf_strerror(err, buf,
sizeof(buf));
394 SCLogError(
"Unable to load eBPF object: %s (%d)", buf, err);
402 struct bpf_maps_info *bpf_map_data =
SCCalloc(1,
sizeof(*bpf_map_data));
403 if (bpf_map_data == NULL) {
409 bpf_map__for_each(map, bpfobj) {
410 if (bpf_map_data->last == BPF_MAP_MAX_COUNT) {
411 SCLogError(
"Too many BPF maps in eBPF files");
414 if (strcmp(bpf_map__name(map),
"flow_table_v4") == 0) {
415 if (bpf_map__key_size(map) !=
sizeof(
struct flowv4_keys)) {
420 if (strcmp(bpf_map__name(map),
"flow_table_v6") == 0) {
421 if (bpf_map__key_size(map) !=
sizeof(
struct flowv6_keys)) {
426 SCLogDebug(
"Got a map '%s' with fd '%d'", bpf_map__name(map), bpf_map__fd(map));
427 bpf_map_data->array[bpf_map_data->last].fd = bpf_map__fd(map);
428 bpf_map_data->array[bpf_map_data->last].name =
SCStrdup(bpf_map__name(map));
429 snprintf(bpf_map_data->array[bpf_map_data->last].iface, IFNAMSIZ,
431 if (!bpf_map_data->array[bpf_map_data->last].name) {
433 BpfMapsInfoFree(bpf_map_data);
436 bpf_map_data->array[bpf_map_data->last].to_unlink = 0;
437 if (config->flags & EBPF_PINNED_MAPS) {
438 SCLogConfig(
"Pinning: %d to %s", bpf_map_data->array[bpf_map_data->last].fd,
439 bpf_map_data->array[bpf_map_data->last].name);
441 snprintf(buf,
sizeof(buf),
"/sys/fs/bpf/suricata-%s-%s", iface,
442 bpf_map_data->array[bpf_map_data->last].name);
443 int ret = bpf_obj_pin(bpf_map_data->array[bpf_map_data->last].fd, buf);
448 if (config->flags & EBPF_XDP_CODE) {
449 bpf_map_data->array[bpf_map_data->last].to_unlink = 0;
451 bpf_map_data->array[bpf_map_data->last].to_unlink = 1;
454 bpf_map_data->last++;
464 pfd = bpf_program__fd(bpfprog);
466 SCLogError(
"Unable to find %s section", section);
470 SCLogInfo(
"Successfully loaded eBPF file '%s' on '%s'", path, iface);
483 int EBPFSetupXDP(
const char *iface,
int fd, uint8_t
flags)
485 #ifdef HAVE_PACKET_XDP
486 unsigned int ifindex = if_nametoindex(iface);
491 #ifdef HAVE_BPF_XDP_ATTACH
492 int err = bpf_xdp_attach(ifindex, fd,
flags, NULL);
495 int err = bpf_set_link_xdp_fd(ifindex, fd,
flags);
499 libbpf_strerror(err, buf,
sizeof(buf));
500 SCLogError(
"Unable to set XDP on '%s': %s (%d)", iface, buf, err);
513 size_t skey,
FlowKey *flow_key,
struct timespec *ctime,
514 uint64_t pkts_cnt, uint64_t bytes_cnt,
515 int mapfd,
int cpus_count)
539 EBPFBypassData *eb =
SCCalloc(1,
sizeof(EBPFBypassData));
552 memcpy(mkey, key, skey);
555 eb->cpus_count = cpus_count;
563 EBPFBypassData *eb = (EBPFBypassData *) fc->
bypass_data;
570 if (eb->key[0] && eb->key[1]) {
581 memcpy(mkey, key, skey);
589 void EBPFBypassFree(
void *data)
591 EBPFBypassData *eb = (EBPFBypassData *)data;
609 EBPFBypassData *eb,
void *key,
613 uint64_t pkts_cnt = 0;
614 uint64_t bytes_cnt = 0;
617 BPF_DECLARE_PERCPU(
struct pair, values_array, eb->cpus_count);
618 memset(values_array, 0,
sizeof(values_array));
619 int res = bpf_map_lookup_elem(eb->mapfd, key, values_array);
621 SCLogDebug(
"errno: (%d) %s", errno, strerror(errno));
624 for (i = 0; i < eb->cpus_count; i++) {
626 SCLogDebug(
"%d: Adding pkts %lu bytes %lu", i,
627 BPF_PERCPU(values_array, i).packets,
628 BPF_PERCPU(values_array, i).bytes);
629 pkts_cnt += BPF_PERCPU(values_array, i).packets;
630 bytes_cnt += BPF_PERCPU(values_array, i).bytes;
654 bool EBPFBypassUpdate(
Flow *f,
void *data, time_t tsec)
656 EBPFBypassData *eb = (EBPFBypassData *)data;
664 bool activity = EBPFBypassCheckHalfFlow(f, fc, eb, eb->key[0], 0);
665 activity |= EBPFBypassCheckHalfFlow(f, fc, eb, eb->key[1], 1);
669 EBPFDeleteKey(eb->mapfd, eb->key[0]);
670 EBPFDeleteKey(eb->mapfd, eb->key[1]);
680 size_t skey,
FlowKey *flow_key,
struct timespec *ctime,
681 uint64_t pkts_cnt, uint64_t bytes_cnt,
682 int mapfd,
int cpus_count);
691 struct timespec *ctime,
692 struct ebpf_timeout_config *tcfg,
693 OpFlowForKey EBPFOpFlowForKey
697 int mapfd = EBPFGetMapFDByName(dev->
dev,
name);
701 struct flowv4_keys key = {}, next_key;
704 uint64_t hash_cnt = 0;
706 if (tcfg->cpus_count == 0) {
710 bool dead_flow =
false;
711 while (bpf_map_get_next_key(mapfd, &key, &next_key) == 0) {
712 uint64_t bytes_cnt = 0;
713 uint64_t pkts_cnt = 0;
716 EBPFDeleteKey(mapfd, &key);
721 BPF_DECLARE_PERCPU(
struct pair, values_array, tcfg->cpus_count);
722 memset(values_array, 0,
sizeof(values_array));
723 int res = bpf_map_lookup_elem(mapfd, &next_key, values_array);
725 SCLogDebug(
"no entry in v4 table for %d -> %d", key.port16[0], key.port16[1]);
726 SCLogDebug(
"errno: (%d) %s", errno, strerror(errno));
730 for (i = 0; i < tcfg->cpus_count; i++) {
732 SCLogDebug(
"%d: Adding pkts %lu bytes %lu", i,
733 BPF_PERCPU(values_array, i).packets,
734 BPF_PERCPU(values_array, i).bytes);
735 pkts_cnt += BPF_PERCPU(values_array, i).packets;
736 bytes_cnt += BPF_PERCPU(values_array, i).bytes;
741 if (tcfg->mode == AFP_MODE_XDP_BYPASS) {
742 flow_key.
sp = ntohs(next_key.port16[0]);
743 flow_key.
dp = ntohs(next_key.port16[1]);
744 flow_key.
src.addr_data32[0] = next_key.src;
745 flow_key.
dst.addr_data32[0] = next_key.dst;
747 flow_key.
sp = next_key.port16[0];
748 flow_key.
dp = next_key.port16[1];
749 flow_key.
src.addr_data32[0] = ntohl(next_key.src);
750 flow_key.
dst.addr_data32[0] = ntohl(next_key.dst);
753 flow_key.
src.addr_data32[1] = 0;
754 flow_key.
src.addr_data32[2] = 0;
755 flow_key.
src.addr_data32[3] = 0;
757 flow_key.
dst.addr_data32[1] = 0;
758 flow_key.
dst.addr_data32[2] = 0;
759 flow_key.
dst.addr_data32[3] = 0;
760 flow_key.
vlan_id[0] = next_key.vlan0;
761 flow_key.
vlan_id[1] = next_key.vlan1;
762 if (next_key.ip_proto == 1) {
763 flow_key.
proto = IPPROTO_TCP;
765 flow_key.
proto = IPPROTO_UDP;
769 dead_flow = EBPFOpFlowForKey(&flowstats, dev, &next_key,
sizeof(next_key), &flow_key,
770 ctime, pkts_cnt, bytes_cnt,
771 mapfd, tcfg->cpus_count);
783 EBPFDeleteKey(mapfd, &key);
789 SCLogInfo(
"IPv4 bypassed flow table size: %" PRIu64, hash_cnt);
802 struct timespec *ctime,
803 struct ebpf_timeout_config *tcfg,
804 OpFlowForKey EBPFOpFlowForKey
808 int mapfd = EBPFGetMapFDByName(dev->
dev,
name);
812 struct flowv6_keys key = {}, next_key;
815 uint64_t hash_cnt = 0;
817 if (tcfg->cpus_count == 0) {
822 uint64_t pkts_cnt = 0;
823 while (bpf_map_get_next_key(mapfd, &key, &next_key) == 0) {
824 uint64_t bytes_cnt = 0;
827 EBPFDeleteKey(mapfd, &key);
832 BPF_DECLARE_PERCPU(
struct pair, values_array, tcfg->cpus_count);
833 memset(values_array, 0,
sizeof(values_array));
834 int res = bpf_map_lookup_elem(mapfd, &next_key, values_array);
836 SCLogDebug(
"no entry in v4 table for %d -> %d", key.port16[0], key.port16[1]);
840 for (i = 0; i < tcfg->cpus_count; i++) {
842 SCLogDebug(
"%d: Adding pkts %lu bytes %lu", i,
843 BPF_PERCPU(values_array, i).packets,
844 BPF_PERCPU(values_array, i).bytes);
845 pkts_cnt += BPF_PERCPU(values_array, i).packets;
846 bytes_cnt += BPF_PERCPU(values_array, i).bytes;
851 if (tcfg->mode == AFP_MODE_XDP_BYPASS) {
852 flow_key.
sp = ntohs(next_key.port16[0]);
853 flow_key.
dp = ntohs(next_key.port16[1]);
855 flow_key.
src.addr_data32[0] = next_key.src[0];
856 flow_key.
src.addr_data32[1] = next_key.src[1];
857 flow_key.
src.addr_data32[2] = next_key.src[2];
858 flow_key.
src.addr_data32[3] = next_key.src[3];
860 flow_key.
dst.addr_data32[0] = next_key.dst[0];
861 flow_key.
dst.addr_data32[1] = next_key.dst[1];
862 flow_key.
dst.addr_data32[2] = next_key.dst[2];
863 flow_key.
dst.addr_data32[3] = next_key.dst[3];
865 flow_key.
sp = next_key.port16[0];
866 flow_key.
dp = next_key.port16[1];
868 flow_key.
src.addr_data32[0] = ntohl(next_key.src[0]);
869 flow_key.
src.addr_data32[1] = ntohl(next_key.src[1]);
870 flow_key.
src.addr_data32[2] = ntohl(next_key.src[2]);
871 flow_key.
src.addr_data32[3] = ntohl(next_key.src[3]);
873 flow_key.
dst.addr_data32[0] = ntohl(next_key.dst[0]);
874 flow_key.
dst.addr_data32[1] = ntohl(next_key.dst[1]);
875 flow_key.
dst.addr_data32[2] = ntohl(next_key.dst[2]);
876 flow_key.
dst.addr_data32[3] = ntohl(next_key.dst[3]);
878 flow_key.
vlan_id[0] = next_key.vlan0;
879 flow_key.
vlan_id[1] = next_key.vlan1;
880 if (next_key.ip_proto == 1) {
881 flow_key.
proto = IPPROTO_TCP;
883 flow_key.
proto = IPPROTO_UDP;
887 pkts_cnt = EBPFOpFlowForKey(&flowstats, dev, &next_key,
sizeof(next_key), &flow_key,
888 ctime, pkts_cnt, bytes_cnt,
889 mapfd, tcfg->cpus_count);
901 EBPFDeleteKey(mapfd, &key);
907 SCLogInfo(
"IPv6 bypassed flow table size: %" PRIu64, hash_cnt);
912 int EBPFCheckBypassedFlowCreate(
ThreadVars *
th_v,
struct timespec *curtime,
void *data)
915 struct ebpf_timeout_config *cfg = (
struct ebpf_timeout_config *)data;
917 EBPFForEachFlowV4Table(
th_v, ldev,
"flow_table_v4",
919 cfg, EBPFCreateFlowForKey);
920 EBPFForEachFlowV6Table(
th_v, ldev,
"flow_table_v6",
922 cfg, EBPFCreateFlowForKey);
928 void EBPFRegisterExtension(
void)
935 #ifdef HAVE_PACKET_XDP
937 static uint32_t g_redirect_iface_cpu_counter = 0;
939 static int EBPFAddCPUToMap(
const char *iface, uint32_t i)
941 int cpumap = EBPFGetMapFDByName(iface,
"cpu_map");
942 uint32_t queue_size = 4096;
949 ret = bpf_map_update_elem(cpumap, &i, &queue_size, 0);
951 SCLogError(
"Create CPU entry failed (err:%d)", ret);
954 int cpus_available = EBPFGetMapFDByName(iface,
"cpus_available");
955 if (cpus_available < 0) {
960 ret = bpf_map_update_elem(cpus_available, &g_redirect_iface_cpu_counter, &i, 0);
962 SCLogError(
"Create CPU entry failed (err:%d)", ret);
968 static void EBPFRedirectMapAddCPU(
int i,
void *data)
970 if (EBPFAddCPUToMap(data, i) < 0) {
973 g_redirect_iface_cpu_counter++;
977 void EBPFBuildCPUSet(
SCConfNode *node,
char *iface)
980 int mapfd = EBPFGetMapFDByName(iface,
"cpus_count");
982 SCLogError(
"Unable to find 'cpus_count' map");
985 g_redirect_iface_cpu_counter = 0;
987 bpf_map_update_elem(mapfd, &key0, &g_redirect_iface_cpu_counter,
992 SCLogWarning(
"Failed to parse XDP CPU redirect configuration");
995 bpf_map_update_elem(mapfd, &key0, &g_redirect_iface_cpu_counter,
1011 int EBPFSetPeerIface(
const char *iface,
const char *out_iface)
1013 int mapfd = EBPFGetMapFDByName(iface,
"tx_peer");
1018 int intmapfd = EBPFGetMapFDByName(iface,
"tx_peer_int");
1020 SCLogError(
"Unable to find 'tx_peer_int' map");
1025 unsigned int peer_index = if_nametoindex(out_iface);
1026 if (peer_index == 0) {
1030 int ret = bpf_map_update_elem(mapfd, &key0, &peer_index, BPF_ANY);
1032 SCLogError(
"Create peer entry failed (err:%d)", ret);
1035 ret = bpf_map_update_elem(intmapfd, &key0, &peer_index, BPF_ANY);
1037 SCLogError(
"Create peer entry failed (err:%d)", ret);
1048 int EBPFUpdateFlow(
Flow *f,
Packet *
p,
void *data)
1061 BypassedIfaceList *ldev = ifl;
1072 BypassedIfaceList *nifl =
SCCalloc(1,
sizeof(*nifl));