Skip to content

Commit

Permalink
extend flow filter apis to introduce peerCIDR and make it part of the…
Browse files Browse the repository at this point in the history
… key

Signed-off-by: Mohamed Mahmoud <[email protected]>
  • Loading branch information
msherif1234 committed Jan 7, 2025
1 parent 9e28edf commit 8d61d00
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 168 deletions.
113 changes: 46 additions & 67 deletions bpf/flows_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,62 @@
if (trace_messages) \
bpf_printk(fmt, ##args)

static __always_inline int is_zero_ip(u8 *ip, u8 len) {
for (int i = 0; i < len; i++) {
if (ip[i] != 0) {
BPF_PRINTK("ip not zero ip[%d]:%d\n", i, ip[i]);
return 0;
}
}
return 1;
}
static __always_inline int flow_filter_setup_lookup_key(flow_id *id, struct filter_key_t *key,
u8 *len, u8 *offset, bool use_src_ip,
u16 eth_protocol) {

static __always_inline int is_equal_ip(u8 *ip1, u8 *ip2, u8 len) {
for (int i = 0; i < len; i++) {
if (ip1[i] != ip2[i]) {
BPF_PRINTK("ip mismatched ip1[%d]:%d not equal to ip2[%d]:%d\n", i, ip1[i], i, ip2[i]);
return 0;
if (eth_protocol == ETH_P_IP) {
*len = sizeof(u32);
*offset = sizeof(ip4in6);
if (use_src_ip) {
__builtin_memcpy(key->ip_data, id->src_ip + *offset, *len);
} else {
__builtin_memcpy(key->ip_data, id->dst_ip + *offset, *len);
}
key->prefix_len = 32;
} else if (eth_protocol == ETH_P_IPV6) {
*len = IP_MAX_LEN;
*offset = 0;
if (use_src_ip) {
__builtin_memcpy(key->ip_data, id->src_ip + *offset, *len);
} else {
__builtin_memcpy(key->ip_data, id->dst_ip + *offset, *len);
}
key->prefix_len = 128;
} else {
return -1;
}
return 1;
return 0;
}

static __always_inline int do_flow_filter_lookup(flow_id *id, struct filter_key_t *key,
filter_action *action, u8 len, u8 offset,
u16 flags, u32 drop_reason, u32 *sampling) {
u16 flags, u32 drop_reason, u32 *sampling,
bool use_src_ip, u16 eth_protocol) {
int result = 0;

struct filter_value_t *rule = (struct filter_value_t *)bpf_map_lookup_elem(&filter_map, key);

if (rule) {
BPF_PRINTK("rule found drop_reason %d flags %d\n", drop_reason, flags);
result++;
if (rule->do_peerCIDR_lookup) {
struct filter_key_t peerKey;
__builtin_memset(&peerKey, 0, sizeof(peerKey));
// PeerCIDR lookup will will target the opposite IP compared to original CIDR lookup
// In other words in cidr is using srcIP then peerCIDR will be the dstIP
if (flow_filter_setup_lookup_key(id, &peerKey, &len, &offset, !use_src_ip,
eth_protocol) < 0) {
result = 0;
goto end;
}
if (!*(bool *)bpf_map_lookup_elem(&peer_filter_map, &peerKey)) {
BPF_PRINTK("peerCIDR mismatched\n");
result = 0;
goto end;
}
}

if (rule->action != MAX_FILTER_ACTIONS) {
BPF_PRINTK("action matched: %d\n", rule->action);
*action = rule->action;
Expand Down Expand Up @@ -159,27 +185,6 @@ static __always_inline int do_flow_filter_lookup(flow_id *id, struct filter_key_
goto end;
}

if (!is_zero_ip(rule->ip, len)) {
// for Ingress side we can filter using dstIP and for Egress side we can filter using srcIP
if (id->direction == INGRESS) {
if (is_equal_ip(rule->ip, id->dst_ip + offset, len)) {
BPF_PRINTK("dstIP matched\n");
result++;
} else {
result = 0;
goto end;
}
} else {
if (is_equal_ip(rule->ip, id->src_ip + offset, len)) {
BPF_PRINTK("srcIP matched\n");
result++;
} else {
result = 0;
goto end;
}
}
}

if (rule->direction != MAX_DIRECTION) {
if (rule->direction == id->direction) {
BPF_PRINTK("direction matched\n");
Expand All @@ -205,34 +210,6 @@ static __always_inline int do_flow_filter_lookup(flow_id *id, struct filter_key_
return result;
}

static __always_inline int flow_filter_setup_lookup_key(flow_id *id, struct filter_key_t *key,
u8 *len, u8 *offset, bool use_src_ip,
u16 eth_protocol) {

if (eth_protocol == ETH_P_IP) {
*len = sizeof(u32);
*offset = sizeof(ip4in6);
if (use_src_ip) {
__builtin_memcpy(key->ip_data, id->src_ip + *offset, *len);
} else {
__builtin_memcpy(key->ip_data, id->dst_ip + *offset, *len);
}
key->prefix_len = 32;
} else if (eth_protocol == ETH_P_IPV6) {
*len = IP_MAX_LEN;
*offset = 0;
if (use_src_ip) {
__builtin_memcpy(key->ip_data, id->src_ip + *offset, *len);
} else {
__builtin_memcpy(key->ip_data, id->dst_ip + *offset, *len);
}
key->prefix_len = 128;
} else {
return -1;
}
return 0;
}

/*
* check if the flow match filter rule and return >= 1 if the flow is to be dropped
*/
Expand All @@ -251,7 +228,8 @@ static __always_inline int is_flow_filtered(flow_id *id, filter_action *action,
return result;
}

result = do_flow_filter_lookup(id, &key, action, len, offset, flags, drop_reason, sampling);
result = do_flow_filter_lookup(id, &key, action, len, offset, flags, drop_reason, sampling,
true, eth_protocol);
// we have a match so return
if (result > 0) {
return result;
Expand All @@ -263,7 +241,8 @@ static __always_inline int is_flow_filtered(flow_id *id, filter_action *action,
return result;
}

return do_flow_filter_lookup(id, &key, action, len, offset, flags, drop_reason, sampling);
return do_flow_filter_lookup(id, &key, action, len, offset, flags, drop_reason, sampling, false,
eth_protocol);
}

#endif //__FLOWS_FILTER_H__
12 changes: 11 additions & 1 deletion bpf/maps_definition.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ struct {
__uint(pinning, LIBBPF_PIN_BY_NAME);
} global_counters SEC(".maps");

// LPM trie map used to filter traffic by IP address CIDR and direction
// LPM trie map used to filter traffic by IP address CIDR
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__type(key, struct filter_key_t);
Expand All @@ -69,4 +69,14 @@ struct {
__uint(pinning, LIBBPF_PIN_BY_NAME);
} filter_map SEC(".maps");

// LPM trie map used to filter traffic by peer IP address CIDR
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__type(key, struct filter_key_t);
__type(value, bool);
__uint(max_entries, MAX_FILTER_ENTRIES);
__uint(map_flags, BPF_F_NO_PREALLOC);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} peer_filter_map SEC(".maps");

#endif //__MAPS_DEFINITION_H__
6 changes: 3 additions & 3 deletions bpf/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ const enum global_counters_key_t *unused9 __attribute__((unused));
struct filter_key_t {
u32 prefix_len;
u8 ip_data[IP_MAX_LEN];
} __attribute__((packed));
} filter_key;

// Force emitting enums/structs into the ELF
const struct filter_key_t *unused10 __attribute__((unused));
Expand Down Expand Up @@ -267,8 +267,8 @@ struct filter_value_t {
tcp_flags tcpFlags;
u8 filter_drops;
u32 sample;
u8 ip[IP_MAX_LEN];
} __attribute__((packed));
bool do_peerCIDR_lookup;
} filter_value;

// Force emitting enums/structs into the ELF
const struct filter_value_t *unused12 __attribute__((unused));
Expand Down
3 changes: 2 additions & 1 deletion hack/build-bytecode-images-multi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ MAPS='{
"packets_record":"perf_event_array",
"dns_flows":"hash",
"global_counters":"per_cpu_array",
"filter_map":"lpm_trie"
"filter_map":"lpm_trie",
"peer_filter_map":"lpm_trie"
}'

if [[ ${OCI_BIN} == "docker" ]]; then
Expand Down
1 change: 1 addition & 0 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ func FlowsAgent(cfg *Config) (*Flows, error) {
FilterIPCIDR: r.FilterIPCIDR,
FilterProtocol: r.FilterProtocol,
FilterPeerIP: r.FilterPeerIP,
FilterPeerCIDR: r.FilterPeerCIDR,
FilterDestinationPort: tracer.ConvertFilterPortsToInstr(r.FilterDestinationPort, r.FilterDestinationPortRange, r.FilterDestinationPorts),
FilterSourcePort: tracer.ConvertFilterPortsToInstr(r.FilterSourcePort, r.FilterSourcePortRange, r.FilterSourcePorts),
FilterPort: tracer.ConvertFilterPortsToInstr(r.FilterPort, r.FilterPortRange, r.FilterPorts),
Expand Down
3 changes: 3 additions & 0 deletions pkg/agent/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ type FlowFilter struct {
FilterDrops bool `json:"drops,omitempty"`
// FilterSample is the sample rate this matching flow will use
FilterSample uint32 `json:"sample,omitempty"`
// FilterPeerCIDR is the PeerIP CIDR to filter flows.
// Example: 10.10.10.0/24 or 100:100:100:100::/64, default is 0.0.0.0/0
FilterPeerCIDR string `json:"peer_cidr,omitempty"`
}

type Config struct {
Expand Down
1 change: 1 addition & 0 deletions pkg/agent/packets_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func PacketsAgent(cfg *Config) (*Packets, error) {
FilterIPCIDR: r.FilterIPCIDR,
FilterProtocol: r.FilterProtocol,
FilterPeerIP: r.FilterPeerIP,
FilterPeerCIDR: r.FilterPeerCIDR,
FilterDestinationPort: tracer.ConvertFilterPortsToInstr(r.FilterDestinationPort, r.FilterDestinationPortRange, r.FilterDestinationPorts),
FilterSourcePort: tracer.ConvertFilterPortsToInstr(r.FilterSourcePort, r.FilterSourcePortRange, r.FilterSourcePorts),
FilterPort: tracer.ConvertFilterPortsToInstr(r.FilterPort, r.FilterPortRange, r.FilterPorts),
Expand Down
48 changes: 27 additions & 21 deletions pkg/ebpf/bpf_arm64_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified pkg/ebpf/bpf_arm64_bpfel.o
Binary file not shown.
48 changes: 27 additions & 21 deletions pkg/ebpf/bpf_powerpc_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified pkg/ebpf/bpf_powerpc_bpfel.o
Binary file not shown.
Loading

0 comments on commit 8d61d00

Please sign in to comment.