Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing support for iterating over per-CPU maps #1291

Closed
HouzuoGuo opened this issue Jan 3, 2024 · 2 comments
Closed

Missing support for iterating over per-CPU maps #1291

HouzuoGuo opened this issue Jan 3, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@HouzuoGuo
Copy link

Describe the bug

(Disclaimer: I'm new to eBPF)

When iterating over a `BPF_MAP_TYPE_LRU_PERCPU_HASH`, the iterator `Map.Iterate(...)` yields nothing.

How to reproduce

(Partial snippet)


struct {
  __uint(type, BPF_MAP_TYPE_LRU_PERCPU_HASH);
  // __uint(type, BPF_MAP_TYPE_LRU_HASH);
  __type(key, __u32);
  __type(value, __u64);
  __uint(max_entries, 128);
} src_data_len SEC(".maps");

static __always_inline int parse_addr(struct xdp_md *ctx, __u32 *out_src,
                                      __u16 *out_len) {
...

SEC("xdp")
int count_packets(struct xdp_md *ctx) {
...
  __u32 src_ip;
  __u16 src_len;
  __u64 new_len = 0;
  if (!parse_addr(ctx, &src_ip, &src_len)) {
    return XDP_PASS;
  }
  __u64 *existing_len = bpf_map_lookup_elem(&src_data_len, &src_ip);
  new_len += src_len;
  if (existing_len) {
    new_len += *existing_len;
  }
  bpf_map_update_elem(&src_data_len, &src_ip, &new_len, BPF_ANY);
...

	for {
		select {
		case <-ticker.C:
			var totalPacketCount, totalPacketLen []uint64
			var srcIP []byte
			var ipTrafficLen uint64

			if err := objs.PktCount.Lookup(uint32(0), &totalPacketCount); err != nil {
				log.Fatal(err)
			}
			if err = objs.PktSize.Lookup(uint32(0), &totalPacketLen); err != nil {
				log.Fatal(err)
			}
			srcTrafficIter := objs.SrcDataLen.Iterate()
			for srcTrafficIter.Next(&srcIP, &ipTrafficLen) {
                                // Yields nothing from BPF_MAP_TYPE_LRU_PERCPU_HASH.
				srcIPAddr := net.IPv4(srcIP[0], srcIP[1], srcIP[2], srcIP[3])
				log.Printf("source IP %s: %v bytes of traffic", srcIPAddr, ipTrafficLen)
			}
			for cpu := range totalPacketCount {
				log.Printf("cpu %d: Seen %d packets in %d bytes", cpu, totalPacketCount[cpu], totalPacketLen[cpu])
			}
		case <-sigInt:
			return
		}
	}


### Version information

github.com/cilium/ebpf v0.12.3
@HouzuoGuo HouzuoGuo added the bug Something isn't working label Jan 3, 2024
@lmb
Copy link
Collaborator

lmb commented Jan 8, 2024

You're not checking srcTrafficIter.Err(). Otherwise you'd see the following error:

look up next key: per-cpu value requires a slice or a pointer to slice

Here is a diff to one of the examples which shows how to use it:

diff --git a/examples/xdp/bpf_bpfeb.o b/examples/xdp/bpf_bpfeb.o
index f90c8b99..9ab3a59f 100644
Binary files a/examples/xdp/bpf_bpfeb.o and b/examples/xdp/bpf_bpfeb.o differ
diff --git a/examples/xdp/bpf_bpfel.o b/examples/xdp/bpf_bpfel.o
index 35dba4b8..e708d827 100644
Binary files a/examples/xdp/bpf_bpfel.o and b/examples/xdp/bpf_bpfel.o differ
diff --git a/examples/xdp/main.go b/examples/xdp/main.go
index 123513b1..99796157 100644
--- a/examples/xdp/main.go
+++ b/examples/xdp/main.go
@@ -72,10 +72,10 @@ func formatMapContents(m *ebpf.Map) (string, error) {
 	var (
 		sb  strings.Builder
 		key netip.Addr
-		val uint32
+		val = make([]uint32, ebpf.MustPossibleCPU())
 	)
 	iter := m.Iterate()
-	for iter.Next(&key, &val) {
+	for iter.Next(&key, val) {
 		sourceIP := key // IPv4 source address in network byte order.
 		packetCount := val
 		sb.WriteString(fmt.Sprintf("\t%s => %d\n", sourceIP, packetCount))
diff --git a/examples/xdp/xdp.c b/examples/xdp/xdp.c
index 2f36c161..ac414b66 100644
--- a/examples/xdp/xdp.c
+++ b/examples/xdp/xdp.c
@@ -9,7 +9,7 @@ char __license[] SEC("license") = "Dual MIT/GPL";
 
 /* Define an LRU hash map for storing packet count by source IPv4 address */
 struct {
-	__uint(type, BPF_MAP_TYPE_LRU_HASH);
+	__uint(type, BPF_MAP_TYPE_LRU_PERCPU_HASH);
 	__uint(max_entries, MAX_MAP_ENTRIES);
 	__type(key, __u32); // source IPv4 address
 	__type(value, __u32); // packet count

Output:

2024/01/08 12:15:10 Attached XDP program to iface "lo" (index 1)
2024/01/08 12:15:10 Press Ctrl-C to exit and remove the program
2024/01/08 12:15:11 Map contents:
2024/01/08 12:15:12 Map contents:
2024/01/08 12:15:13 Map contents:
	127.0.0.1 => [0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0]
2024/01/08 12:15:14 Map contents:
	127.0.0.1 => [2 2 4 0 5 0 0 0 0 0 0 0 0 2 0 0]
2024/01/08 12:15:15 Map contents:
	127.0.0.1 => [2 2 4 0 5 0 0 0 0 0 0 0 0 2 0 0]

@lmb lmb closed this as completed Jan 8, 2024
@HouzuoGuo
Copy link
Author

That's very cool, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants