diff --git a/ebpfcat/arraymap.py b/ebpfcat/arraymap.py index c687d46d8ae0fde3945df563ad275448a637be65..ce3ecea05cab6b62aed38a4d120d45dbd66705af 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 b9985af20f10f491f688f6f0100043d6e650f89f..2da7527b3a88285e3ad96b63dee697d08f60b74d 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)