From 5123133160ceb5f40f7b0511ab886d39998c25b0 Mon Sep 17 00:00:00 2001 From: Simone Magnani Date: Sat, 24 Feb 2024 13:10:50 +0100 Subject: [PATCH] simplified example by removing xdp and batch hash map delete Signed-off-by: Simone Magnani --- examples/README.md | 4 +- examples/shared_xdp_tc/bpf_bpfeb.o | Bin 7536 -> 0 bytes examples/shared_xdp_tc/bpf_bpfel.o | Bin 7536 -> 0 bytes examples/{shared_xdp_tc => tcx}/bpf_bpfeb.go | 0 examples/tcx/bpf_bpfeb.o | Bin 0 -> 7216 bytes examples/{shared_xdp_tc => tcx}/bpf_bpfel.go | 0 examples/tcx/bpf_bpfel.o | Bin 0 -> 7216 bytes examples/{shared_xdp_tc => tcx}/main.go | 94 ++++++------------ .../{shared_xdp_tc/xdp_tcx.c => tcx/tcx.c} | 81 ++++++++------- 9 files changed, 77 insertions(+), 102 deletions(-) delete mode 100644 examples/shared_xdp_tc/bpf_bpfeb.o delete mode 100644 examples/shared_xdp_tc/bpf_bpfel.o rename examples/{shared_xdp_tc => tcx}/bpf_bpfeb.go (100%) create mode 100644 examples/tcx/bpf_bpfeb.o rename examples/{shared_xdp_tc => tcx}/bpf_bpfel.go (100%) create mode 100644 examples/tcx/bpf_bpfel.o rename examples/{shared_xdp_tc => tcx}/main.go (51%) rename examples/{shared_xdp_tc/xdp_tcx.c => tcx/tcx.c} (53%) diff --git a/examples/README.md b/examples/README.md index 12e6b73d7..444ff3cab 100644 --- a/examples/README.md +++ b/examples/README.md @@ -16,8 +16,8 @@ Like kprobes, but with better performance and usability, for kernels 5.5 and later. * [tcp_connect](fentry/) - Trace outgoing IPv4 TCP connections. * [tcp_close](tcprtt/) - Log RTT of IPv4 TCP connections using eBPF CO-RE helpers. -* TC and XDP - Attach a program to a network interface to process incoming (XDP) and outgoing (TC) packets. - * [shared_xdp_tc](./shared_xdp_tc/) - monitor and periodically reset the number of incoming and outgoing packets for each network flow identified with the traditional 5-tuple session identifier (IP addresses, L4 Ports, IP protocol). +* TCx - Attach a program to Linux TC (Traffic Control) to process incoming and outgoing packets. + * [tcx](./tcx/) - monitor the number of incoming and outgoing packets for each network flow identified with the traditional 5-tuple session identifier (IP addresses, L4 Ports, IP protocol). * XDP - Attach a program to a network interface to process incoming packets. * [xdp](xdp/) - Print packet counts by IPv4 source address. * Add your use case(s) here! diff --git a/examples/shared_xdp_tc/bpf_bpfeb.o b/examples/shared_xdp_tc/bpf_bpfeb.o deleted file mode 100644 index 0c8e967aabc23faa5eef45114aed1d5525a3dd11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7536 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 NJIw~w#?g-7^KZASz?}d9 diff --git a/examples/shared_xdp_tc/bpf_bpfel.o b/examples/shared_xdp_tc/bpf_bpfel.o deleted file mode 100644 index 3dcbae5bb3acd73ea02e2c3239df6d88caca9b85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7536 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 pIeE7NHign4Pu8E?p4-: : Proto: => Ingress: Egress: -// Every nth calls to this function, the entire content of the Hash map is erased -// (lru map would automatically remove old keys, but can also remove additional keys -// so we use hash map to keep constant behaviour) -func handleMapContents(m *ebpf.Map) { +func formatMapContent(m *ebpf.Map) (string, error) { var ( - sb strings.Builder - key bpfSessionKey - val bpfSessionValue - keys []bpfSessionKey + sb strings.Builder + key bpfSessionKey + val bpfSessionValue ) - currIter++ - needsErase := currIter%eraseEvery == 0 - - if needsErase { - keys = make([]bpfSessionKey, 0) - } iter := m.Iterate() for iter.Next(&key, &val) { - sb.WriteString(fmt.Sprintf("\t%s:%d - %s:%d Proto:%s => Ingress:%d Egress:%d\n", - intToIp(key.Saddr), portToLE(key.Sport), intToIp(key.Daddr), portToLE(key.Dport), + sb.WriteString(fmt.Sprintf("\t%15s:%5d - %15s:%5d Proto:%3s => Ingress:%10d Egress:%10d\n", + intToIp(key.Saddr), portToLittleEndian(key.Sport), + intToIp(key.Daddr), portToLittleEndian(key.Dport), protoMap[key.Proto], val.InCount, val.EgCount)) - if needsErase { - keys = append(keys, key) - } - } - if iter.Err() != nil { - log.Printf("Error reading map: %s", iter.Err()) - return } - log.Printf("Map contents:\n%s", sb.String()) - - if !needsErase { - return - } - - n, err := m.BatchDelete(keys, nil) - if err != nil { - log.Printf("Error erasing map: %s", err) - return - } - log.Printf("Successfully Erased Map content (%d elements) at Iteration n. %d\n", n, currIter) + return sb.String(), iter.Err() } -// intToIp convert an int32 value retrieved from the network -// traffic (big endian) into a netip.Addr +// intToIp convert an int32 value retrieved from the network traffic (big endian) into a netip.Addr func intToIp(val uint32) netip.Addr { a4 := [4]byte{} binary.LittleEndian.PutUint32(a4[:], val) return netip.AddrFrom4(a4) } -// portToLE convert a uint16 value retrieved from the network -// traffic (big endian) into a little endian -func portToLE(val uint16) uint16 { +// portToLittleEndian convert a uint16 value retrieved from the network traffic (big endian) into a little endian +func portToLittleEndian(val uint16) uint16 { p2 := [2]byte{} binary.LittleEndian.PutUint16(p2[:], val) return binary.LittleEndian.Uint16(p2[:]) diff --git a/examples/shared_xdp_tc/xdp_tcx.c b/examples/tcx/tcx.c similarity index 53% rename from examples/shared_xdp_tc/xdp_tcx.c rename to examples/tcx/tcx.c index eacdf2d6e..bdabed9b5 100644 --- a/examples/shared_xdp_tc/xdp_tcx.c +++ b/examples/tcx/tcx.c @@ -1,6 +1,7 @@ //go:build ignore #include "common.h" +#include "bpf_endian.h" char __license[] SEC("license") = "Dual MIT/GPL"; @@ -8,23 +9,21 @@ char __license[] SEC("license") = "Dual MIT/GPL"; struct session_key { __u32 saddr; // IP source address __u32 daddr; // IP dest address - __u16 sport; // Source port (if ICMP then 0) - __u16 dport; // Dest port (if ICMP then 0) + __u16 sport; // Source port (set to 0 if ICMP) + __u16 dport; // Dest port (set to 0 if ICMP) __u8 proto; // Protocol ID }; // Session value struct session_value { - __u32 in_count; - __u32 eg_count; + __u32 in_count; // Ingress packet count + __u32 eg_count; // Egress packet count }; #define MAX_MAP_ENTRIES 16 -/* -Define an Hash map for storing packet Ingress and Egress count by 5-tuple session identifier -User-space logic is responsible for cleaning the map, if potentially new entries needs to be monitored. -*/ +// Define an Hash map for storing packet Ingress and Egress count by 5-tuple session identifier +// User-space logic is responsible for cleaning the map, if potentially new entries needs to be monitored. struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, MAX_MAP_ENTRIES); @@ -32,11 +31,9 @@ struct { __type(value, struct session_value); } stats_map SEC(".maps"); -/* -Attempt to parse the 5-tuple session identifierfrom the packet. -Returns 0 if there is no IPv4 header field or if L4 is not a UDP, TCP or ICMP packet; otherwise returns non-zero. -*/ -static __always_inline int parse_session_identifier(void *data, void *data_end, struct session_key *key, __u8 is_ingress) { +// Attempt to parse the 5-tuple session identifier from the packet. +// Returns 0 if there is no IPv4 header field or if L4 is not a UDP, TCP or ICMP packet; otherwise returns non-zero. +static __always_inline int parse_session_identifier(void *data, void *data_end, struct session_key *key) { // First, parse the ethernet header. struct ethhdr *eth = data; if ((void *)(eth + 1) > data_end) { @@ -89,31 +86,41 @@ static __always_inline int parse_session_identifier(void *data, void *data_end, key->saddr = (__u32)(ip->saddr); key->daddr = (__u32)(ip->daddr); - // In case the function is called from Egress hook, swap IP addresses and L4 ports before - // doing the map lookup - if (!is_ingress) { - __u32 tmp = key->saddr; - key->saddr = key->daddr; - key->daddr = tmp; - __u16 tmp2 = key->sport; - key->sport = key->dport; - key->dport = tmp2; - } return 1; } -/* -Main program logic shared by either XDP and TC hook. The function attempts to update the entry -in the LRU map corresponding to the 5-tuple identifier; it increases either the ingress or egress -packet counter value. In case of a non IP, TCP, UDP, ICMP packet, the program ignores the packet. -*/ -static __always_inline int prog_logic(void *data, void *data_end, __u8 is_ingress, int ret_code) { +// Function to swap addresses and ports from a session identifier, used when parsing packets in the Egress hook. +// This is done to align the session identifiers between Ingress and Egress, so that they point to the same +// entry in the Hash map. +static __always_inline void swap_key(struct session_key *key) { + __u32 tmp = key->saddr; + __u16 tmp2 = key->sport; + + key->saddr = key->daddr; + key->sport = key->dport; + key->daddr = tmp; + key->dport = tmp2; + + return; +} + +// Main program logic shared by Ingress and Egress TC hooks. The function attempts to update the entry +// in the Hash map corresponding to the 5-tuple identifier; it increases either the ingress or egress +// packet counter value. In case of a non IP, TCP, UDP, ICMP packet, the program ignores the packet. +// This function would work also with data and data_end retrieved from a xdp_md structure, and XDP_PASS as return type. +static __always_inline int prog_func(void *data, void *data_end, __u8 is_ingress, int ret_code) { struct session_key key = {}; - if (!parse_session_identifier(data, data_end, &key, is_ingress)) { + if (!parse_session_identifier(data, data_end, &key)) { // Not an IPv4 packet, so don't count it. goto done; } + // In case the function is called from Egress hook, swap addresses + // and L4 port before doing the map lookup + if (!is_ingress) { + swap_key(&key); + } + struct session_value *val = bpf_map_lookup_elem(&stats_map, &key); if (!val) { // No entry in the map for this 5-tuple identifier yet, so set the initial value to 1. @@ -132,18 +139,18 @@ static __always_inline int prog_logic(void *data, void *data_end, __u8 is_ingres } done: - // Return code corresponds to the OK action within either XDP or TC + // Return code corresponds to the PASS action in TC return ret_code; } -// XDP Ingress hook -SEC("xdp") -int ingress_prog_func(struct xdp_md *ctx) { - return prog_logic((void *)(long)ctx->data, (void *)(long)ctx->data_end, 0, XDP_PASS); +// TC Ingress hook +SEC("tc") +int ingress_prog_func(struct __sk_buff *skb) { + return prog_func((void *)(long)skb->data, (void *)(long)skb->data_end, 1, TC_ACT_OK); } // TC Egress hook SEC("tc") -int egress_prog_func(struct __sk_buff *ctx) { - return prog_logic((void *)(long)ctx->data, (void *)(long)ctx->data_end, 1, TC_ACT_OK); +int egress_prog_func(struct __sk_buff *skb) { + return prog_func((void *)(long)skb->data, (void *)(long)skb->data_end, 0, TC_ACT_OK); }