From 46152e48b917b10ef0b22d5d5dfe6c1c8b3de2c9 Mon Sep 17 00:00:00 2001 From: Martin Teichmann <martin.teichmann@gmail.com> Date: Mon, 9 Jan 2023 22:10:09 +0000 Subject: [PATCH] add support for mmaped ArrayMaps this is still rough --- ebpfcat/arraymap.py | 20 +++++++++++--------- ebpfcat/bpf.py | 13 ++++++++++--- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/ebpfcat/arraymap.py b/ebpfcat/arraymap.py index c687d46..ce3ecea 100644 --- a/ebpfcat/arraymap.py +++ b/ebpfcat/arraymap.py @@ -16,10 +16,11 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from itertools import chain +from mmap import mmap from struct import pack_into, unpack_from, calcsize from .ebpf import FuncId, Map, MemoryDesc -from .bpf import create_map, lookup_elem, MapType, update_elem +from .bpf import create_map, lookup_elem, MapType, MapFlags, update_elem class ArrayGlobalVarDesc(MemoryDesc): @@ -63,22 +64,21 @@ class ArrayGlobalVarDesc(MemoryDesc): class ArrayMapAccess: """This is the array map proper""" - def __init__(self, fd, write_size, size): - self.fd = fd - self.write_size = write_size + def __init__(self, data, size): + self.data = data self.size = size - self.data = bytearray(size) + #self.data = bytearray(size) def read(self): """read all variables in the map from EBPF to user space""" - self.data = lookup_elem(self.fd, b"\0\0\0\0", self.size) + #self.data = lookup_elem(self.fd, b"\0\0\0\0", self.size) def write(self): """write all variables in the map from user space to EBPF *all* variables are written, even those not marked ``write=True`` """ - update_elem(self.fd, b"\0\0\0\0", self.data, 0) + #update_elem(self.fd, b"\0\0\0\0", self.data, 0) def readwrite(self): """read variables from EBPF and write them out immediately @@ -95,6 +95,7 @@ class ArrayMapAccess: will have the value from the EBPF program in user space, and vice-versa. """ + return write = self.data[:self.write_size] data = lookup_elem(self.fd, b"\0\0\0\0", self.size) self.data[:] = data @@ -137,8 +138,9 @@ class ArrayMap(Map): write_size, size = self.collect(ebpf) if not size: # nobody is actually using the map return - fd = create_map(MapType.ARRAY, 4, size, 1) - setattr(ebpf, self.name, ArrayMapAccess(fd, write_size, size)) + fd = create_map(MapType.ARRAY, 4, size, 1, MapFlags.MMAPABLE) + data = mmap(fd, size) + setattr(ebpf, self.name, ArrayMapAccess(data, size)) with ebpf.save_registers(list(range(6))), ebpf.get_stack(4) as stack: ebpf.mI[ebpf.r10 + stack] = 0 ebpf.r1 = ebpf.get_fd(fd) diff --git a/ebpfcat/bpf.py b/ebpfcat/bpf.py index b9985af..2da7527 100644 --- a/ebpfcat/bpf.py +++ b/ebpfcat/bpf.py @@ -19,7 +19,7 @@ A module that wraps the `bpf` system call in Python, using `ctypes`. """ from ctypes import CDLL, c_int, get_errno, cast, c_void_p, create_string_buffer, c_char_p, addressof, c_char -from enum import Enum +from enum import Enum, Flag from struct import pack, unpack from platform import machine @@ -60,6 +60,10 @@ class MapType(Enum): SOCKHASH = 18 +class MapFlags(Flag): + MMAPABLE = 1 << 10 + + class ProgType(Enum): UNSPEC = 0 SOCKET_FILTER = 1 @@ -96,9 +100,12 @@ def bpf(cmd, fmt, *args): raise OSError(get_errno(), strerror(get_errno())) return ret, unpack(fmt, attr.raw) -def create_map(map_type, key_size, value_size, max_entries): +def create_map(map_type, key_size, value_size, max_entries, + attributes=MapFlags(0)): assert isinstance(map_type, MapType) - return bpf(0, "IIII", map_type.value, key_size, value_size, max_entries)[0] + assert isinstance(attributes, MapFlags) + return bpf(0, "IIIII", map_type.value, key_size, value_size, max_entries, + attributes.value)[0] def lookup_elem(fd, key, size): value = bytearray(size) -- GitLab