Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/bfcli/lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
%s STATE_MATCHER_META_FLOW_HASH
%s STATE_MATCHER_L4_PROTO
%s STATE_MATCHER_META_PROBA
%s STATE_MATCHER_META_RATELIMIT
%s STATE_MATCHER_IPV4_ADDR
%s STATE_MATCHER_IP4_NET
%s STATE_MATCHER_IP4_DSCP
Expand Down Expand Up @@ -177,6 +178,16 @@ meta\.flow_hash { BEGIN(STATE_MATCHER_META_FLOW_HASH); yylval.sval = strdup(
}
}

meta\.ratelimit { BEGIN(STATE_MATCHER_META_RATELIMIT); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
<STATE_MATCHER_META_RATELIMIT>{
(eq) { yylval.sval = strdup(yytext); return MATCHER_OP; }
{int}|[0-9a-zA-Z-]+ {
BEGIN(INITIAL);
yylval.sval = strdup(yytext);
return RAW_PAYLOAD;
}
}

ip4\.saddr { BEGIN(STATE_MATCHER_IPV4_ADDR); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
ip4\.daddr { BEGIN(STATE_MATCHER_IPV4_ADDR); yylval.sval = strdup(yytext); return MATCHER_TYPE; }
<STATE_MATCHER_IPV4_ADDR>{
Expand Down
1 change: 1 addition & 0 deletions src/libbpfilter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ bf_target_add_elfstubs(libbpfilter
"pkt_log"
"flow_hash"
"sock_addr_log"
"ratelimit"
)

target_compile_definitions(libbpfilter
Expand Down
34 changes: 34 additions & 0 deletions src/libbpfilter/bpf/ratelimit.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <linux/bpf.h>

#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>
#include <stddef.h>

#define BF_TIME_S 1000000000

struct bf_ratelimit
{
__u64 current;
__u64 last_time;
};

__u8 bf_ratelimit(void *map, const __u32 limit)
{
struct bf_ratelimit *ratelimit;
__u64 current_time = bpf_ktime_get_ns() / BF_TIME_S;
__u32 key = 0;

ratelimit = bpf_map_lookup_elem(map, &key);
if (!ratelimit) {
bpf_printk("failed to fetch the rule's ratelimit");
return 1;
}

if (current_time != ratelimit->last_time)
ratelimit->current = 0;

ratelimit->current++;
ratelimit->last_time = current_time;

return (ratelimit->current > limit);
}
2 changes: 2 additions & 0 deletions src/libbpfilter/cgen/fixup.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ enum bf_fixup_type
BF_FIXUP_TYPE_PRINTER_MAP_FD,
/// Set the log map file descriptor in the @c BPF_LD_MAP_FD instruction.
BF_FIXUP_TYPE_LOG_MAP_FD,
/// Set the ratelimit map file descriptor in the @c BPF_LD_MAP_FD instruction.
BF_FIXUP_TYPE_RATELIMIT_MAP_FD,
/// Set a set map file descriptor in the @c BPF_LD_MAP_FD instruction.
BF_FIXUP_TYPE_SET_MAP_FD,
/// Call an ELF stub.
Expand Down
38 changes: 38 additions & 0 deletions src/libbpfilter/cgen/handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ int bf_handle_new_from_pack(struct bf_handle **handle, struct bf_lock *lock,
return bf_rpack_key_err(r, "bf_handle.lmap");
}

r = bf_rpack_kv_node(node, "rmap", &child);
if (r)
return bf_rpack_key_err(r, "bf_handle.rmap");
if (!bf_rpack_is_nil(child)) {
r = bf_map_new_from_pack(&_handle->rmap, dir_fd, child);
if (r)
return bf_rpack_key_err(r, "bf_handle.rmap");
}

r = bf_rpack_kv_array(node, "sets", &child);
if (r)
return bf_rpack_key_err(r, "bf_handle.sets");
Expand Down Expand Up @@ -145,6 +154,7 @@ void bf_handle_free(struct bf_handle **handle)
bf_map_free(&(*handle)->cmap);
bf_map_free(&(*handle)->pmap);
bf_map_free(&(*handle)->lmap);
bf_map_free(&(*handle)->rmap);
bf_list_clean(&(*handle)->sets);

free(*handle);
Expand Down Expand Up @@ -190,6 +200,14 @@ int bf_handle_pack(const struct bf_handle *handle, bf_wpack_t *pack)
bf_wpack_kv_nil(pack, "lmap");
}

if (handle->rmap) {
bf_wpack_open_object(pack, "rmap");
bf_map_pack(handle->rmap, pack);
bf_wpack_close_object(pack);
} else {
bf_wpack_kv_nil(pack, "rmap");
}

bf_wpack_kv_list(pack, "sets", &handle->sets);

return bf_wpack_is_valid(pack) ? 0 : -EINVAL;
Expand Down Expand Up @@ -243,6 +261,15 @@ void bf_handle_dump(const struct bf_handle *handle, prefix_t *prefix)
DUMP(prefix, "lmap: struct bf_map * (NULL)");
}

if (handle->rmap) {
DUMP(prefix, "rmap: struct bf_map *");
bf_dump_prefix_push(prefix);
bf_map_dump(handle->rmap, bf_dump_prefix_last(prefix));
bf_dump_prefix_pop(prefix);
} else {
DUMP(prefix, "rmap: struct bf_map * (NULL)");
}

DUMP(bf_dump_prefix_last(prefix), "sets: bf_list<bf_map>[%lu]",
bf_list_size(&handle->sets));
bf_dump_prefix_push(prefix);
Expand Down Expand Up @@ -304,6 +331,14 @@ int bf_handle_pin(struct bf_handle *handle, struct bf_lock *lock)
}
}

if (handle->rmap) {
r = bf_map_pin(handle->rmap, dir_fd);
if (r) {
bf_err_r(r, "failed to pin BPF ratelimit map");
goto err_unpin_all;
}
}

bf_list_foreach (&handle->sets, set_node) {
struct bf_map *map = bf_list_node_get_data(set_node);

Expand Down Expand Up @@ -347,6 +382,8 @@ void bf_handle_unpin(struct bf_handle *handle, struct bf_lock *lock)
bf_map_unpin(handle->pmap, dir_fd);
if (handle->lmap)
bf_map_unpin(handle->lmap, dir_fd);
if (handle->rmap)
bf_map_unpin(handle->rmap, dir_fd);

bf_list_foreach (&handle->sets, set_node) {
struct bf_map *map = bf_list_node_get_data(set_node);
Expand Down Expand Up @@ -429,5 +466,6 @@ void bf_handle_unload(struct bf_handle *handle)
bf_map_free(&handle->cmap);
bf_map_free(&handle->pmap);
bf_map_free(&handle->lmap);
bf_map_free(&handle->rmap);
bf_list_clean(&handle->sets);
}
3 changes: 3 additions & 0 deletions src/libbpfilter/cgen/handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ struct bf_handle
/** Log map. NULL if not created. */
struct bf_map *lmap;

/** Ratelimit map. NULL if not created. */
struct bf_map *rmap;

/** List of set maps. Contains at most one map for each unique key
* format. */
bf_list sets;
Expand Down
22 changes: 22 additions & 0 deletions src/libbpfilter/cgen/matcher/meta.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,26 @@ _bf_matcher_generate_meta_flow_probability(struct bf_program *program,
return 0;
}

static int _bf_matcher_generate_meta_ratelimit(struct bf_program *program,
const struct bf_matcher *matcher)
{
uint32_t ratelimit = *(uint32_t *)bf_matcher_payload(matcher);

EMIT_LOAD_RATELIMIT_FD_FIXUP(program, BPF_REG_1);
EMIT(program, BPF_MOV32_IMM(BPF_REG_2, ratelimit));
EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_RATELIMIT);

if (bf_matcher_get_negate(matcher)) {
EMIT_FIXUP_JMP_NEXT_RULE(program,
BPF_JMP32_IMM(BPF_JEQ, BPF_REG_0, 0, 0));
} else {
EMIT_FIXUP_JMP_NEXT_RULE(program,
BPF_JMP32_IMM(BPF_JNE, BPF_REG_0, 0, 0));
}

return 0;
}

int bf_matcher_generate_meta(struct bf_program *program,
const struct bf_matcher *matcher)
{
Expand All @@ -177,6 +197,8 @@ int bf_matcher_generate_meta(struct bf_program *program,
return _bf_matcher_generate_meta_port(program, matcher);
case BF_MATCHER_META_FLOW_PROBABILITY:
return _bf_matcher_generate_meta_flow_probability(program, matcher);
case BF_MATCHER_META_RATELIMIT:
return _bf_matcher_generate_meta_ratelimit(program, matcher);
case BF_MATCHER_META_MARK:
case BF_MATCHER_META_FLOW_HASH:
return bf_err_r(-ENOTSUP,
Expand Down
1 change: 1 addition & 0 deletions src/libbpfilter/cgen/packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ int bf_packet_gen_inline_matcher(struct bf_program *program,
case BF_MATCHER_META_SPORT:
case BF_MATCHER_META_DPORT:
case BF_MATCHER_META_FLOW_PROBABILITY:
case BF_MATCHER_META_RATELIMIT:
return bf_matcher_generate_meta(program, matcher);
case BF_MATCHER_META_MARK:
case BF_MATCHER_META_FLOW_HASH:
Expand Down
4 changes: 4 additions & 0 deletions src/libbpfilter/cgen/prog/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ static struct bf_btf *_bf_map_make_btf(const struct bf_map *map)
case BF_MAP_TYPE_PRINTER:
case BF_MAP_TYPE_SET:
case BF_MAP_TYPE_LOG:
case BF_MAP_TYPE_RATELIMIT:
case BF_MAP_TYPE_CTX:
// No BTF data available for these map types
return NULL;
Expand Down Expand Up @@ -194,6 +195,8 @@ int bf_map_new(struct bf_map **map, const char *name, enum bf_map_type type,
[BF_MAP_TYPE_COUNTERS] = BF_BPF_MAP_TYPE_ARRAY,
[BF_MAP_TYPE_PRINTER] = BF_BPF_MAP_TYPE_ARRAY,
[BF_MAP_TYPE_LOG] = BF_BPF_MAP_TYPE_RINGBUF,
[BF_MAP_TYPE_RATELIMIT] =
BF_BPF_MAP_TYPE_ARRAY, // Not sure if ARRAY or RINGBUF
[BF_MAP_TYPE_CTX] = BF_BPF_MAP_TYPE_ARRAY,
};

Expand Down Expand Up @@ -310,6 +313,7 @@ static const char *_bf_map_type_to_str(enum bf_map_type type)
[BF_MAP_TYPE_COUNTERS] = "BF_MAP_TYPE_COUNTERS",
[BF_MAP_TYPE_PRINTER] = "BF_MAP_TYPE_PRINTER",
[BF_MAP_TYPE_LOG] = "BF_MAP_TYPE_LOG",
[BF_MAP_TYPE_RATELIMIT] = "BF_MAP_TYPE_RATELIMIT",
[BF_MAP_TYPE_SET] = "BF_MAP_TYPE_SET",
[BF_MAP_TYPE_CTX] = "BF_MAP_TYPE_CTX",
};
Expand Down
1 change: 1 addition & 0 deletions src/libbpfilter/cgen/prog/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ enum bf_map_type
BF_MAP_TYPE_COUNTERS,
BF_MAP_TYPE_PRINTER,
BF_MAP_TYPE_LOG,
BF_MAP_TYPE_RATELIMIT,
BF_MAP_TYPE_SET,
BF_MAP_TYPE_CTX,
_BF_MAP_TYPE_MAX,
Expand Down
35 changes: 35 additions & 0 deletions src/libbpfilter/cgen/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#define _BF_COUNTER_MAP_NAME "bf_cmap"
#define _BF_PRINTER_MAP_NAME "bf_pmap"
#define _BF_LOG_MAP_NAME "bf_lmap"
#define _BF_RATELIMIT_MAP_NAME "bf_rmap"

static inline size_t _bf_round_next_power_of_2(size_t value)
{
Expand Down Expand Up @@ -433,6 +434,10 @@ static int _bf_program_fixup(struct bf_program *program,
insn_type = BF_FIXUP_INSN_IMM;
value = program->handle->lmap->fd;
break;
case BF_FIXUP_TYPE_RATELIMIT_MAP_FD:
insn_type = BF_FIXUP_INSN_IMM;
value = program->handle->rmap->fd;
break;
case BF_FIXUP_TYPE_SET_MAP_FD: {
const struct bf_set_group *group =
_bf_program_find_set_group(program, fixup->attr.set_ptr);
Expand Down Expand Up @@ -900,6 +905,32 @@ static int _bf_program_load_log_map(struct bf_program *program)
return 0;
}

static int _bf_program_load_ratelimit_map(struct bf_program *program)
{
_cleanup_free_ void *pstr = NULL;
uint32_t key = 0;
struct bf_ratelimit val = {.current = 0, .last_time = 0};
int r;

assert(program);

r = bf_map_new(&program->handle->rmap, _BF_RATELIMIT_MAP_NAME,
BF_MAP_TYPE_RATELIMIT, sizeof(uint32_t),
sizeof(struct bf_ratelimit), 1);
if (r)
return bf_err_r(r, "failed to create the ratelimit bf_map object");

r = bf_map_set_elem(program->handle->rmap, &key, &val);
if (r)
return bf_err_r(r, "failed to set ratelimit map elem");

r = _bf_program_fixup(program, BF_FIXUP_TYPE_RATELIMIT_MAP_FD);
if (r)
return bf_err_r(r, "failed to fixup ratelimit map FD");

return 0;
}

/**
* @brief Load set maps, one BPF map per `bf_set_group`.
*
Expand Down Expand Up @@ -1001,6 +1032,10 @@ int bf_program_load(struct bf_program *prog)
if (r)
return bf_err_r(r, "failed to load the log map");

r = _bf_program_load_ratelimit_map(prog);
if (r)
return bf_err_r(r, "failed to load the ratelimit map");

if (bf_ctx_is_verbose(BF_VERBOSE_DEBUG)) {
log_buf = malloc(_BF_LOG_BUF_SIZE);
if (!log_buf) {
Expand Down
18 changes: 18 additions & 0 deletions src/libbpfilter/cgen/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@
return __r; \
})

#define EMIT_LOAD_RATELIMIT_FD_FIXUP(program, reg) \
({ \
const struct bpf_insn ld_insn[2] = {BPF_LD_MAP_FD(reg, 0)}; \
int __r = bf_program_emit_fixup( \
(program), BF_FIXUP_TYPE_RATELIMIT_MAP_FD, ld_insn[0], NULL); \
if (__r < 0) \
return __r; \
__r = bf_program_emit((program), ld_insn[1]); \
if (__r < 0) \
return __r; \
})

/**
* Load a specific set's file descriptor.
*
Expand Down Expand Up @@ -232,6 +244,12 @@ struct bf_program

#define _free_bf_program_ __attribute__((__cleanup__(bf_program_free)))

struct bf_ratelimit
{
uint64_t current;
uint64_t last_time;
};

/**
* @brief Allocate and initialize a new `bf_program` object.
*
Expand Down
13 changes: 13 additions & 0 deletions src/libbpfilter/include/bpfilter/elfstub.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,19 @@ enum bf_elfstub_id
*/
BF_ELFSTUB_SOCK_ADDR_LOG,

/**
* Check if `limit` packets have already been seen in the last unit of time
*
* `__u8 bf_ratelimit(void *map, __u32 limit)`
*
* **Parameters**
* - `map`: address of the ratelimit map.
* - `limit`: number of packets allowed to pass in one unit of time.
*
* **Return** 0 if in the allowed limit (inclusive), or 1 if over the limit.
*/
BF_ELFSTUB_RATELIMIT,

_BF_ELFSTUB_MAX,
};

Expand Down
2 changes: 2 additions & 0 deletions src/libbpfilter/include/bpfilter/matcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ enum bf_matcher_type
BF_MATCHER_META_FLOW_HASH,
/// Matches packets based on flow probability (consistent per flow).
BF_MATCHER_META_FLOW_PROBABILITY,
/// Matches a number of packets per unit of time
BF_MATCHER_META_RATELIMIT,
/// Matches IPv4 source address.
BF_MATCHER_IP4_SADDR,
/// Matches IPv4 source network.
Expand Down
Loading
Loading