Пример #1
0
 def _open(self,
           map_fd: ct.c_int,
           func: Callable,
           ctx: ct.c_void_p = None) -> None:
     """
     Open a new ringbuf with @func as a callback.
     """
     # Cast func as _RINGBUF_CB_TYPE
     func = _RINGBUF_CB_TYPE(func)
     # Handle case where we don't have a manager yet
     if not self._skel._ringbuf_mgr:
         self._skel._ringbuf_mgr = Lib.ring_buffer_new(
             map_fd, func, ctx, None)
         if not self._skel._ringbuf_mgr:
             raise Exception(
                 f'Failed to create new ring buffer manager: {cerr()}')
     # Handle case where we already have a manager
     else:
         ret = Lib.ring_buffer_add(self._skel._ringbuf_mgr, map_fd, func,
                                   ctx)
         if ret != 0:
             raise Exception(
                 f'Failed to add ringbuf to ring buffer manager: {cerr(ret)}'
             )
     # Keep a refcnt so that our function doesn't get cleaned up
     self._cb = func
Пример #2
0
def generate_progs(bpf_obj: ct.c_void_p):
    progs = {}
    for prog in Lib.obj_programs(bpf_obj):
        if not prog:
            continue
        prog_fd = Lib.bpf_program_fd(prog)
        prog_name = Lib.bpf_program_name(prog).decode(FILESYSTEMENCODING)
        prog_type = Lib.bpf_program_type(prog)
        progs[prog_name] = create_prog(prog, prog_name, prog_type, prog_fd)
    return progs
Пример #3
0
    def next(self, key):
        """
        Returns the next map key.
        """
        next_key = self.KeyType()

        if key is None:
            ret = Lib.bpf_map_get_next_key(self._map_fd, None,
                                           ct.byref(next_key))
        else:
            ret = Lib.bpf_map_get_next_key(self._map_fd, ct.byref(key),
                                           ct.byref(next_key))

        if ret < 0:
            raise StopIteration()

        return next_key
Пример #4
0
 def __delitem__(self, key):
     try:
         key = self.KeyType(key)
     except TypeError:
         pass
     ret = Lib.bpf_map_delete_elem(self._map_fd, ct.byref(key))
     if ret < 0:
         raise KeyError(f'Unable to delete item item: {cerr(ret)}')
Пример #5
0
 def attach(self):
     """
     Attach the BPF program.
     """
     if self._link:
         return
     self._link = Lib.bpf_program_attach(self._prog)
     if not self._link:
         raise Exception(f'Failed to attach BPF program {self._name}: {cerr()}')
Пример #6
0
 def peek(self):
     """
     Peek an element from the map.
     """
     value = self.ValueType()
     ret = Lib.bpf_map_lookup_elem(self._map_fd, None, ct.byref(value))
     if ret < 0:
         raise KeyError(f'Unable to peek value: {cerr(ret)}')
     return value
Пример #7
0
 def pop(self) -> self.ValueType:
     """
     Pop an element from the map.
     """
     value = self.ValueType()
     ret = Lib.bpf_map_lookup_and_delete_elem(self._map_fd, None,
                                              ct.byref(value))
     if ret < 0:
         raise KeyError(f'Unable to pop value: {cerr(ret)}')
     return value
Пример #8
0
 def __getitem__(self, key):
     value = self.ValueType()
     try:
         key = self.KeyType(key)
     except TypeError:
         pass
     ret = Lib.bpf_map_lookup_elem(self._map_fd, ct.byref(key),
                                   ct.byref(value))
     if ret < 0:
         raise KeyError(f'Unable to fetch item: {cerr(ret)}')
     return value
Пример #9
0
 def push(self, value: self.ValueType, flags: int = 0):
     """
     Push an element onto the map.
     """
     try:
         value = self.ValueType(value)
     except TypeError:
         pass
     ret = Lib.bpf_map_update_elem(self._map_fd, None, ct.byref(value),
                                   flags)
     if ret < 0:
         raise KeyError(f'Unable to push value: {cerr(ret)}')
Пример #10
0
 def __init__(self, *args, **kwargs):
     self._num_cpus = Lib.num_possible_cpus()
     try:
         alignment = self._vsize % 8
     except AttributeError:
         raise Exception('PerCpuMixin without value size?!')
     # Force aligned value size
     if alignment != 0:
         self._vsize += (8 - alignment)
         # Make sure we are now aligned
         alignment = self._vsize % 8
         assert alignment == 0
Пример #11
0
def generate_maps(skel, bpf_obj: ct.c_void_p):
    maps = {}
    for _map in Lib.obj_maps(bpf_obj):
        if not _map:
            continue
        map_fd = Lib.bpf_map_fd(_map)
        map_name = Lib.bpf_map_name(_map).decode(FILESYSTEMENCODING)
        map_entries = Lib.bpf_map_max_entries(_map)
        map_ksize = Lib.bpf_map_key_size(_map)
        map_vsize = Lib.bpf_map_value_size(_map)
        map_type = Lib.bpf_map_type(_map)
        maps[map_name] = create_map(skel, _map, map_fd, map_type, map_ksize,
                                    map_vsize, map_entries)
    return maps
Пример #12
0
 def update(self, key: self.KeyType, value: self.ValueType, flags: int):
     """
     Update a map value, operating according to specified flags.
     This provides more control than the traditional map[key] = value method.
     """
     try:
         key = self.KeyType(key)
     except TypeError:
         pass
     try:
         value = self.ValueType(value)
     except TypeError:
         pass
     ret = Lib.bpf_map_update_elem(self._map_fd, ct.byref(key),
                                   ct.byref(value), flags)
     if ret < 0:
         raise KeyError(f'Unable to update item: {cerr(ret)}')
Пример #13
0
 def remove_xdp(self, *ifnames: str):
     """
     Remove all XDP programs from interfaces with names @ifnames.
     """
     try:
         from pyroute2 import IPRoute
     except ImportError:
         raise ImportError('pyroute2 must be installed before removing XDP programs') from None
     ipr = IPRoute()
     for ifname in ifnames:
         try:
             ifindex = ipr.link_lookup(ifname=ifname)[0]
         except IndexError:
             raise KeyError(f'No such interface "{ifname}"') from None
         retval = Lib.bpf_set_link_xdp_fd(ifindex, -1, 0)
     if retval < 0:
         raise Exception(f'Failed to remove XDP program {self._name} to interface "{ifname}" ({ifindex}): {cerr(retval)}')
Пример #14
0
    def invoke(self, data: ct.Structure = None):
        """
        Invoke the BPF program once and capture and return its return value.
        If the program is of type BPF_PROG_TYPE_USER, you can pass it data
        using a ctypes struct @data.
        """
        if data == None:
            data_p = None
            data_size = ct.c_uint32(0)
        else:
            data_p = ct.addressof(data)
            data_size = ct.sizeof(data)

        # Make this signed so that we can express negative return values,
        # should be okay to pass to the unsigned retval pointer
        bpf_ret = ct.c_uint32()

        retval = Lib.bpf_prog_test_run(self._prog_fd, ct.c_int(1), data_p, data_size, None, ct.c_uint32(0), ct.byref(bpf_ret), None)
        if retval < 0:
            raise Exception(f'Failed to invoke BPF program {self._name}: {cerr(retval)}')

        bpf_retval = ct.c_int16(bpf_ret.value)
        return bpf_retval.value
Пример #15
0
def open_bpf_object(bpf_obj_path: str) -> ct.c_void_p:
    bpf_obj_path = force_bytes(bpf_obj_path)
    res = Lib.bpf_object_open(bpf_obj_path)
    if not res:
        raise Exception(f'Failed to open BPF object: {cerr()}')
    return res
Пример #16
0
def close_bpf_object(bpf_obj: ct.c_void_p):
    if not bpf_obj:
        return
    Lib.bpf_object_close(bpf_obj)
Пример #17
0
def load_bpf_object(bpf_obj: ct.c_void_p):
    res = Lib.bpf_object_load(bpf_obj)
    if res < 0:
        raise Exception(f'Failed to load BPF object: {cerr()}')
    return res