diff --git a/bpf/flows_filter.h b/bpf/flows_filter.h index 74e8553aa..e3ad6cd93 100644 --- a/bpf/flows_filter.h +++ b/bpf/flows_filter.h @@ -11,29 +11,38 @@ 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); @@ -41,6 +50,29 @@ static __always_inline int do_flow_filter_lookup(flow_id *id, struct filter_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; + } + bool *peer_result = (bool *)bpf_map_lookup_elem(&peer_filter_map, &peerKey); + if (peer_result) { + if (*peer_result == false) { + BPF_PRINTK("peerCIDR mismatched\n"); + result = 0; + goto end; + } + } else { + result = 0; + goto end; + } + } + if (rule->action != MAX_FILTER_ACTIONS) { BPF_PRINTK("action matched: %d\n", rule->action); *action = rule->action; @@ -159,27 +191,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"); @@ -205,34 +216,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 */ @@ -251,7 +234,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; @@ -263,7 +247,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__ diff --git a/bpf/maps_definition.h b/bpf/maps_definition.h index 1cb466990..1156cfbee 100644 --- a/bpf/maps_definition.h +++ b/bpf/maps_definition.h @@ -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); @@ -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__ diff --git a/bpf/types.h b/bpf/types.h index 558ba2f17..1ff3c67ab 100644 --- a/bpf/types.h +++ b/bpf/types.h @@ -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)); @@ -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)); diff --git a/hack/build-bytecode-images-multi.sh b/hack/build-bytecode-images-multi.sh index 75c790bdc..799228926 100755 --- a/hack/build-bytecode-images-multi.sh +++ b/hack/build-bytecode-images-multi.sh @@ -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 diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 47fab9897..cffa7dfc1 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -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), diff --git a/pkg/agent/config.go b/pkg/agent/config.go index 9968b01a5..84677bf90 100644 --- a/pkg/agent/config.go +++ b/pkg/agent/config.go @@ -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 { diff --git a/pkg/agent/packets_agent.go b/pkg/agent/packets_agent.go index 5c76bc9ed..b3b95ea34 100644 --- a/pkg/agent/packets_agent.go +++ b/pkg/agent/packets_agent.go @@ -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), diff --git a/pkg/ebpf/bpf_arm64_bpfel.go b/pkg/ebpf/bpf_arm64_bpfel.go index 44dc2de78..209423152 100644 --- a/pkg/ebpf/bpf_arm64_bpfel.go +++ b/pkg/ebpf/bpf_arm64_bpfel.go @@ -67,27 +67,30 @@ type BpfFilterKeyT struct { } type BpfFilterValueT struct { - Protocol uint8 - DstPortStart uint16 - DstPortEnd uint16 - DstPort1 uint16 - DstPort2 uint16 - SrcPortStart uint16 - SrcPortEnd uint16 - SrcPort1 uint16 - SrcPort2 uint16 - PortStart uint16 - PortEnd uint16 - Port1 uint16 - Port2 uint16 - IcmpType uint8 - IcmpCode uint8 - Direction BpfDirectionT - Action BpfFilterActionT - TcpFlags BpfTcpFlagsT - FilterDrops uint8 - Sample uint32 - Ip [16]uint8 + Protocol uint8 + _ [1]byte + DstPortStart uint16 + DstPortEnd uint16 + DstPort1 uint16 + DstPort2 uint16 + SrcPortStart uint16 + SrcPortEnd uint16 + SrcPort1 uint16 + SrcPort2 uint16 + PortStart uint16 + PortEnd uint16 + Port1 uint16 + Port2 uint16 + IcmpType uint8 + IcmpCode uint8 + Direction BpfDirectionT + Action BpfFilterActionT + TcpFlags BpfTcpFlagsT + FilterDrops uint8 + _ [3]byte + Sample uint32 + DoPeerCIDR_lookup bool + _ [3]byte } type BpfFlowId BpfFlowIdT @@ -247,6 +250,7 @@ type BpfMapSpecs struct { FilterMap *ebpf.MapSpec `ebpf:"filter_map"` GlobalCounters *ebpf.MapSpec `ebpf:"global_counters"` PacketRecord *ebpf.MapSpec `ebpf:"packet_record"` + PeerFilterMap *ebpf.MapSpec `ebpf:"peer_filter_map"` } // BpfObjects contains all objects after they have been loaded into the kernel. @@ -275,6 +279,7 @@ type BpfMaps struct { FilterMap *ebpf.Map `ebpf:"filter_map"` GlobalCounters *ebpf.Map `ebpf:"global_counters"` PacketRecord *ebpf.Map `ebpf:"packet_record"` + PeerFilterMap *ebpf.Map `ebpf:"peer_filter_map"` } func (m *BpfMaps) Close() error { @@ -286,6 +291,7 @@ func (m *BpfMaps) Close() error { m.FilterMap, m.GlobalCounters, m.PacketRecord, + m.PeerFilterMap, ) } diff --git a/pkg/ebpf/bpf_arm64_bpfel.o b/pkg/ebpf/bpf_arm64_bpfel.o index f11c52f93..1ab82084b 100644 Binary files a/pkg/ebpf/bpf_arm64_bpfel.o and b/pkg/ebpf/bpf_arm64_bpfel.o differ diff --git a/pkg/ebpf/bpf_powerpc_bpfel.go b/pkg/ebpf/bpf_powerpc_bpfel.go index b6381dd1c..1db381deb 100644 --- a/pkg/ebpf/bpf_powerpc_bpfel.go +++ b/pkg/ebpf/bpf_powerpc_bpfel.go @@ -67,27 +67,30 @@ type BpfFilterKeyT struct { } type BpfFilterValueT struct { - Protocol uint8 - DstPortStart uint16 - DstPortEnd uint16 - DstPort1 uint16 - DstPort2 uint16 - SrcPortStart uint16 - SrcPortEnd uint16 - SrcPort1 uint16 - SrcPort2 uint16 - PortStart uint16 - PortEnd uint16 - Port1 uint16 - Port2 uint16 - IcmpType uint8 - IcmpCode uint8 - Direction BpfDirectionT - Action BpfFilterActionT - TcpFlags BpfTcpFlagsT - FilterDrops uint8 - Sample uint32 - Ip [16]uint8 + Protocol uint8 + _ [1]byte + DstPortStart uint16 + DstPortEnd uint16 + DstPort1 uint16 + DstPort2 uint16 + SrcPortStart uint16 + SrcPortEnd uint16 + SrcPort1 uint16 + SrcPort2 uint16 + PortStart uint16 + PortEnd uint16 + Port1 uint16 + Port2 uint16 + IcmpType uint8 + IcmpCode uint8 + Direction BpfDirectionT + Action BpfFilterActionT + TcpFlags BpfTcpFlagsT + FilterDrops uint8 + _ [3]byte + Sample uint32 + DoPeerCIDR_lookup bool + _ [3]byte } type BpfFlowId BpfFlowIdT @@ -247,6 +250,7 @@ type BpfMapSpecs struct { FilterMap *ebpf.MapSpec `ebpf:"filter_map"` GlobalCounters *ebpf.MapSpec `ebpf:"global_counters"` PacketRecord *ebpf.MapSpec `ebpf:"packet_record"` + PeerFilterMap *ebpf.MapSpec `ebpf:"peer_filter_map"` } // BpfObjects contains all objects after they have been loaded into the kernel. @@ -275,6 +279,7 @@ type BpfMaps struct { FilterMap *ebpf.Map `ebpf:"filter_map"` GlobalCounters *ebpf.Map `ebpf:"global_counters"` PacketRecord *ebpf.Map `ebpf:"packet_record"` + PeerFilterMap *ebpf.Map `ebpf:"peer_filter_map"` } func (m *BpfMaps) Close() error { @@ -286,6 +291,7 @@ func (m *BpfMaps) Close() error { m.FilterMap, m.GlobalCounters, m.PacketRecord, + m.PeerFilterMap, ) } diff --git a/pkg/ebpf/bpf_powerpc_bpfel.o b/pkg/ebpf/bpf_powerpc_bpfel.o index 1d54f4b45..1c42a79c6 100644 Binary files a/pkg/ebpf/bpf_powerpc_bpfel.o and b/pkg/ebpf/bpf_powerpc_bpfel.o differ diff --git a/pkg/ebpf/bpf_s390_bpfeb.go b/pkg/ebpf/bpf_s390_bpfeb.go index c13de86c1..46e388e64 100644 --- a/pkg/ebpf/bpf_s390_bpfeb.go +++ b/pkg/ebpf/bpf_s390_bpfeb.go @@ -67,27 +67,30 @@ type BpfFilterKeyT struct { } type BpfFilterValueT struct { - Protocol uint8 - DstPortStart uint16 - DstPortEnd uint16 - DstPort1 uint16 - DstPort2 uint16 - SrcPortStart uint16 - SrcPortEnd uint16 - SrcPort1 uint16 - SrcPort2 uint16 - PortStart uint16 - PortEnd uint16 - Port1 uint16 - Port2 uint16 - IcmpType uint8 - IcmpCode uint8 - Direction BpfDirectionT - Action BpfFilterActionT - TcpFlags BpfTcpFlagsT - FilterDrops uint8 - Sample uint32 - Ip [16]uint8 + Protocol uint8 + _ [1]byte + DstPortStart uint16 + DstPortEnd uint16 + DstPort1 uint16 + DstPort2 uint16 + SrcPortStart uint16 + SrcPortEnd uint16 + SrcPort1 uint16 + SrcPort2 uint16 + PortStart uint16 + PortEnd uint16 + Port1 uint16 + Port2 uint16 + IcmpType uint8 + IcmpCode uint8 + Direction BpfDirectionT + Action BpfFilterActionT + TcpFlags BpfTcpFlagsT + FilterDrops uint8 + _ [3]byte + Sample uint32 + DoPeerCIDR_lookup bool + _ [3]byte } type BpfFlowId BpfFlowIdT @@ -247,6 +250,7 @@ type BpfMapSpecs struct { FilterMap *ebpf.MapSpec `ebpf:"filter_map"` GlobalCounters *ebpf.MapSpec `ebpf:"global_counters"` PacketRecord *ebpf.MapSpec `ebpf:"packet_record"` + PeerFilterMap *ebpf.MapSpec `ebpf:"peer_filter_map"` } // BpfObjects contains all objects after they have been loaded into the kernel. @@ -275,6 +279,7 @@ type BpfMaps struct { FilterMap *ebpf.Map `ebpf:"filter_map"` GlobalCounters *ebpf.Map `ebpf:"global_counters"` PacketRecord *ebpf.Map `ebpf:"packet_record"` + PeerFilterMap *ebpf.Map `ebpf:"peer_filter_map"` } func (m *BpfMaps) Close() error { @@ -286,6 +291,7 @@ func (m *BpfMaps) Close() error { m.FilterMap, m.GlobalCounters, m.PacketRecord, + m.PeerFilterMap, ) } diff --git a/pkg/ebpf/bpf_s390_bpfeb.o b/pkg/ebpf/bpf_s390_bpfeb.o index 1c4e40035..89ce8fa3e 100644 Binary files a/pkg/ebpf/bpf_s390_bpfeb.o and b/pkg/ebpf/bpf_s390_bpfeb.o differ diff --git a/pkg/ebpf/bpf_x86_bpfel.go b/pkg/ebpf/bpf_x86_bpfel.go index c81facb65..39677715f 100644 --- a/pkg/ebpf/bpf_x86_bpfel.go +++ b/pkg/ebpf/bpf_x86_bpfel.go @@ -67,27 +67,30 @@ type BpfFilterKeyT struct { } type BpfFilterValueT struct { - Protocol uint8 - DstPortStart uint16 - DstPortEnd uint16 - DstPort1 uint16 - DstPort2 uint16 - SrcPortStart uint16 - SrcPortEnd uint16 - SrcPort1 uint16 - SrcPort2 uint16 - PortStart uint16 - PortEnd uint16 - Port1 uint16 - Port2 uint16 - IcmpType uint8 - IcmpCode uint8 - Direction BpfDirectionT - Action BpfFilterActionT - TcpFlags BpfTcpFlagsT - FilterDrops uint8 - Sample uint32 - Ip [16]uint8 + Protocol uint8 + _ [1]byte + DstPortStart uint16 + DstPortEnd uint16 + DstPort1 uint16 + DstPort2 uint16 + SrcPortStart uint16 + SrcPortEnd uint16 + SrcPort1 uint16 + SrcPort2 uint16 + PortStart uint16 + PortEnd uint16 + Port1 uint16 + Port2 uint16 + IcmpType uint8 + IcmpCode uint8 + Direction BpfDirectionT + Action BpfFilterActionT + TcpFlags BpfTcpFlagsT + FilterDrops uint8 + _ [3]byte + Sample uint32 + DoPeerCIDR_lookup bool + _ [3]byte } type BpfFlowId BpfFlowIdT @@ -247,6 +250,7 @@ type BpfMapSpecs struct { FilterMap *ebpf.MapSpec `ebpf:"filter_map"` GlobalCounters *ebpf.MapSpec `ebpf:"global_counters"` PacketRecord *ebpf.MapSpec `ebpf:"packet_record"` + PeerFilterMap *ebpf.MapSpec `ebpf:"peer_filter_map"` } // BpfObjects contains all objects after they have been loaded into the kernel. @@ -275,6 +279,7 @@ type BpfMaps struct { FilterMap *ebpf.Map `ebpf:"filter_map"` GlobalCounters *ebpf.Map `ebpf:"global_counters"` PacketRecord *ebpf.Map `ebpf:"packet_record"` + PeerFilterMap *ebpf.Map `ebpf:"peer_filter_map"` } func (m *BpfMaps) Close() error { @@ -286,6 +291,7 @@ func (m *BpfMaps) Close() error { m.FilterMap, m.GlobalCounters, m.PacketRecord, + m.PeerFilterMap, ) } diff --git a/pkg/ebpf/bpf_x86_bpfel.o b/pkg/ebpf/bpf_x86_bpfel.o index 6c80da7da..94057787c 100644 Binary files a/pkg/ebpf/bpf_x86_bpfel.o and b/pkg/ebpf/bpf_x86_bpfel.o differ diff --git a/pkg/tracer/flow_filter.go b/pkg/tracer/flow_filter.go index b29e2dcfb..10f5d6c8b 100644 --- a/pkg/tracer/flow_filter.go +++ b/pkg/tracer/flow_filter.go @@ -22,6 +22,7 @@ type FilterConfig struct { FilterIcmpType int FilterIcmpCode int FilterPeerIP string + FilterPeerCIDR string FilterAction string FilterTCPFlags string FilterDrops bool @@ -55,6 +56,17 @@ func (f *Filter) ProgramFilter() error { return fmt.Errorf("failed to get filter value: %w", err) } + if val.DoPeerCIDR_lookup { + peerKey, err := f.getPeerFilterKey(config) + if err != nil { + return fmt.Errorf("failed to get peer filter key: %w", err) + } + err = f.objects.PeerFilterMap.Update(peerKey, true, cilium.UpdateAny) + if err != nil { + return fmt.Errorf("failed to update peer filter map: %w", err) + } + log.Infof("Programmed filter with PeerCIDR: %v", peerKey) + } err = f.objects.FilterMap.Update(key, val, cilium.UpdateAny) if err != nil { return fmt.Errorf("failed to update filter map: %w", err) @@ -81,7 +93,32 @@ func (f *Filter) getFilterKey(config *FilterConfig) (ebpf.BpfFilterKeyT, error) } pfLen, _ := ipNet.Mask.Size() key.PrefixLen = uint32(pfLen) + return key, nil +} +func (f *Filter) getPeerFilterKey(config *FilterConfig) (ebpf.BpfFilterKeyT, error) { + key := ebpf.BpfFilterKeyT{} + if config.FilterPeerCIDR != "" { + ip, ipNet, err := net.ParseCIDR(config.FilterPeerCIDR) + if err != nil { + return key, fmt.Errorf("failed to parse FlowFilterPeerCIDR: %w", err) + } + if ip.To4() != nil { + copy(key.IpData[:], ip.To4()) + } else { + copy(key.IpData[:], ip.To16()) + } + pfLen, _ := ipNet.Mask.Size() + key.PrefixLen = uint32(pfLen) + } else if config.FilterPeerIP != "" { + ip := net.IP(config.FilterPeerIP) + copy(key.IpData[:], ip) + if ip.To4() != nil { + key.PrefixLen = 32 + } else { + key.PrefixLen = 128 + } + } return key, nil } @@ -129,15 +166,6 @@ func (f *Filter) getFilterValue(config *FilterConfig) (ebpf.BpfFilterValueT, err val.IcmpType = uint8(config.FilterIcmpType) val.IcmpCode = uint8(config.FilterIcmpCode) - if config.FilterPeerIP != "" { - ip := net.ParseIP(config.FilterPeerIP) - if ip.To4() != nil { - copy(val.Ip[:], ip.To4()) - } else { - copy(val.Ip[:], ip.To16()) - } - } - switch config.FilterTCPFlags { case "SYN": val.TcpFlags = ebpf.BpfTcpFlagsTSYN_FLAG @@ -170,6 +198,9 @@ func (f *Filter) getFilterValue(config *FilterConfig) (ebpf.BpfFilterValueT, err if config.FilterSample != 0 { val.Sample = config.FilterSample } + if config.FilterPeerCIDR != "" || config.FilterPeerIP != "" { + val.DoPeerCIDR_lookup = true + } return val, nil } diff --git a/pkg/tracer/tracer.go b/pkg/tracer/tracer.go index 2b355230b..e321049de 100644 --- a/pkg/tracer/tracer.go +++ b/pkg/tracer/tracer.go @@ -36,6 +36,8 @@ const ( aggregatedFlowsMap = "aggregated_flows" additionalFlowMetrics = "additional_flow_metrics" dnsLatencyMap = "dns_flows" + flowFilterMap = "filter_map" + flowPeerFilterMap = "peer_filter_map" // constants defined in flows.c as "volatile const" constSampling = "sampling" constTraceMessages = "trace_messages" @@ -133,7 +135,7 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) { spec.Maps[additionalFlowMetrics].MaxEntries = 1 } // remove pinning from all maps - maps2Name := []string{"aggregated_flows", "additional_flow_metrics", "direct_flows", "dns_flows", "filter_map", "global_counters", "packet_record"} + maps2Name := []string{"aggregated_flows", "additional_flow_metrics", "direct_flows", "dns_flows", "filter_map", "peer_filter_map", "global_counters", "packet_record"} for _, m := range maps2Name { spec.Maps[m].Pinning = 0 } @@ -164,6 +166,9 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) { enableFlowFiltering := 0 if cfg.EnableFlowFilter { enableFlowFiltering = 1 + } else { + spec.Maps[flowFilterMap].MaxEntries = 1 + spec.Maps[flowPeerFilterMap].MaxEntries = 1 } enableNetworkEventsMonitoring := 0 if cfg.EnableNetworkEventsMonitoring { @@ -312,6 +317,10 @@ func NewFlowFetcher(cfg *FlowFetcherConfig) (*FlowFetcher, error) { if err != nil { return nil, fmt.Errorf("failed to load %s: %w", mPath, err) } + objects.BpfMaps.PeerFilterMap, err = cilium.LoadPinnedMap(mPath, opts) + if err != nil { + return nil, fmt.Errorf("failed to load %s: %w", mPath, err) + } log.Infof("BPFManager mode: loading global counters pinned maps") mPath = path.Join(pinDir, "global_counters") objects.BpfMaps.GlobalCounters, err = cilium.LoadPinnedMap(mPath, opts) @@ -736,6 +745,9 @@ func (m *FlowFetcher) Close() error { if err := m.objects.FilterMap.Close(); err != nil { errs = append(errs, err) } + if err := m.objects.PeerFilterMap.Close(); err != nil { + errs = append(errs, err) + } if len(errs) == 0 { m.objects = nil } @@ -1056,6 +1068,7 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, AggregatedFlows: newObjects.AggregatedFlows, DnsFlows: newObjects.DnsFlows, FilterMap: newObjects.FilterMap, + PeerFilterMap: newObjects.PeerFilterMap, GlobalCounters: newObjects.GlobalCounters, }, } @@ -1106,6 +1119,7 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, AggregatedFlows: newObjects.AggregatedFlows, DnsFlows: newObjects.DnsFlows, FilterMap: newObjects.FilterMap, + PeerFilterMap: newObjects.PeerFilterMap, GlobalCounters: newObjects.GlobalCounters, }, } @@ -1156,6 +1170,7 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, AggregatedFlows: newObjects.AggregatedFlows, DnsFlows: newObjects.DnsFlows, FilterMap: newObjects.FilterMap, + PeerFilterMap: newObjects.PeerFilterMap, GlobalCounters: newObjects.GlobalCounters, }, } @@ -1207,6 +1222,7 @@ func kernelSpecificLoadAndAssign(oldKernel, rtKernel, supportNetworkEvents bool, AggregatedFlows: newObjects.AggregatedFlows, DnsFlows: newObjects.DnsFlows, FilterMap: newObjects.FilterMap, + PeerFilterMap: newObjects.PeerFilterMap, GlobalCounters: newObjects.GlobalCounters, }, } @@ -1319,8 +1335,9 @@ func NewPacketFetcher(cfg *FlowFetcherConfig) (*PacketFetcher, error) { RhNetworkEventsMonitoring: nil, }, BpfMaps: ebpf.BpfMaps{ - PacketRecord: newObjects.PacketRecord, - FilterMap: newObjects.FilterMap, + PacketRecord: newObjects.PacketRecord, + FilterMap: newObjects.FilterMap, + PeerFilterMap: newObjects.PeerFilterMap, }, }