Log packets going through a rule
Allow users to log the packet matched by a rule.
Overview
A new keyword must be introduced to allow users to specify if a rule should log matched packets:
chain [...]
rule
meta.l3 ipv4
log l3 l4
DROP
The log keyword can have the following arguments:
- No argument, or
l3 l4: logs L3 and L4 headers -
l3orl4: log the specified header
The L2 (Ethernet) header is only available for some hooks, it can be skipped for now and supported later.
The logging flags will be carried as part of the chain definition. The generated BPF program will then write the requested headers into a BPF ring buffer. bpf_printk() is not a viable solution as it would be slower than a ring buffer, and bpfilter would have to log each packet according to its protocol and fields. Write the headers to the ring buffer allow the user to read them and log them as they want to. The headers will be logged to the ring buffer as logged_packet structures (see below) of variable size (depending on the logged layers).
At runtime, the packet will be logged to the ring buffer using a custom function, similarly to the counters update.
Eventually, bfcli could introduce chain log or rule log command to print the logs of a chain or rule. This is out of the scope of this feature.
Implementation
- [ ] [core] Store the logging flag(s) in
struct bf_rule, update thebf_rule_...()functions accordingly. - [ ] [bfcli] Add support for
log [l3] [l4]to the parser and lexer. Use thecounterkeyword as an example. Update the documentation. - [ ] [cgen] Add support for the ring buffer map. No need to worry about the map's BTF data for now.
- [ ] [cgen]
bf_programshould contain a reference to the new logging map. It should only be allocated if the chain requires logging. - [ ] [cgen] Store L3 and L4 header size into the program's runtime context. The header sizes are calculated in
bf_stub_parse_l3_hdr()andbf_stub_parse_l4_hdr(), it should then be stored in the runtime context (e.g.BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_x, BF_PROG_CTX_OFF(lx_size))). If the protocol is not supported, store the size of its header as 0. - [ ] [cgen] Define the new logging function as a
fixup(also here). - [ ] [cgen] Similarly to
update_countersfunction, implement thelogfunction to:- Fill a
struct logged_packeton the stack (see below) to write to the ring buffer, such that for the protocol at layer X:-
lX_protois the protocol ID, or 0 if this layer should not be logged. -
lX_sizeis the size of the header for layer X, or 0 if the protocol is not supported, or if the layer should not be logged.
-
-
Call
bpf_ringbuf_output()kfunc - Handle errors properly (update the error counter if needed)
- Fill a
struct logged_packet
{
uint32_t rule_index;
uint8_t l3_proto;
uint16_t l3_size;
uint16_t l4_proto;
uint16_t l4_size;
uint8_t l3_data[l3_size];
uint8_t l4_data[l4_size];
};