vincentmli / BPFire

BPFire development tree
12 stars 0 forks source link

set UDP/DNS rate limit at XDP program run time #6

Open vincentmli opened 2 months ago

vincentmli commented 2 months ago

technical background to update global data variable at runtime https://lore.kernel.org/bpf/20190228231829.11993-7-daniel@iogearbox.net/t/#mbb899f37f07924076ab2ace4144ef7fcf7bf82e7

quote from above discussion below for BPF code in general

> The non initialized
> global variable will not be in any allocated section in ELF file,
> it is in a COM section which is to be allocated by loader.
> So user defines some like
>     int g;
> and later on uses it. Right now, it will not work. The workaround
> is "int g = 4", or "static int g". I guess it should be
> okay, we should encourage users to use "static" variables instead.

Would it be reasonable to just plain disable usage of uninitialized
global variables, as it kind of goes against BPF's philosophy that
everything should be written to, before can be read? So while we can
just implicitly zero-out everything beforehand, it might be a good
idea to remind and enforce that explictly?

everything should be written to before can be read

elf static data relocation

pdf

vincentmli commented 2 months ago

get decimal input from user cli/WeBUI, convert to hex as bash or perl example below, then use bpftool map update bash example:

#!/bin/bash

decimal=1000
hex=$(printf '%08x' "$decimal")  # Convert decimal to hexadecimal
bytes=$(echo "$hex" | fold -w2 | tac)   # Split the hexadecimal into pairs of bytes and reverse the order
hex_le=$(echo "$bytes" | sed 's/^/0x/' | tr '\n' ' ')  # Add prefix "0x" to each byte and concatenate them

echo "$hex_le"  # Output: 0xe8 0x03 0x00 0x00
bpftool map update name xdp_udp.data key hex 00 00 00 00 value $hex_le
bpftool map lookup name xdp_udp.data key hex 00 00 00 00

or perl

#/usr/bin/perl

use strict;
use warnings;

sub decimal_to_hex_le {
    my ($decimal) = @_;
    my $hex = sprintf('%08x', $decimal);  # Convert decimal to hexadecimal
    my @bytes = $hex =~ /(..)/g;          # Split the hexadecimal into pairs of bytes
    my $little_endian_hex = join(' ', map { '0x' . $_ } reverse @bytes);  # Add prefix "0x" and reverse the order of bytes
    return $little_endian_hex;
}

# Test with input 1000
my $decimal = 1000;
my $hex_le = decimal_to_hex_le($decimal);
print "$hex_le\n";  # Output: 0xe8 0x03 0x00 0x00
vincentmli commented 2 months ago

if xdp program has two global variables, for example:

static volatile unsigned int ratelimit = 1000;
static volatile unsigned int cpus = 2;

the global data map value would be:

# bpftool map lookup name xdp_udp.data key hex 00 00 00 00
{
    "value": {
        ".data": [{
                "ratelimit": 1000
            },{
                "cpus": 1
            }
        ]
    }
}

value has 8 bytes, so when use bpftool to update the value, need to keep the number of bytes in mind, and if only update the cpus, then

# bpftool map update name xdp_udp.data key hex 00 00 00 00 value hex e8 03 00 00 02 00 00 00
# bpftool map lookup name xdp_udp.data key hex 00 00 00 00
{
    "value": {
        ".data": [{
                "ratelimit": 1000
            },{
                "cpus": 2
            }
        ]
    }
}