Skip to content

Commit

Permalink
Simplified example, counting ingress/egress packets
Browse files Browse the repository at this point in the history
Signed-off-by: Simone Magnani <simonemagnani.96@gmail.com>
  • Loading branch information
smagnani96 committed Jun 19, 2024
1 parent ef23432 commit af08538
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 348 deletions.
2 changes: 1 addition & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Please see our [guide on what makes a good example](https://ebpf-go.dev/contribu
* [tcp_connect](fentry/) - Trace outgoing IPv4 TCP connections.
* [tcp_close](tcprtt/) - Log RTT of IPv4 TCP connections using eBPF CO-RE helpers.
* 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).
* [tcx](./tcx/) - Print packet counts for ingress and egress.
* XDP - Attach a program to a network interface to process incoming packets.
* [xdp](xdp/) - Print packet counts by IPv4 source address.

Expand Down
149 changes: 14 additions & 135 deletions examples/headers/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@ typedef __u32 __wsum;

#include "bpf_helpers.h"

// compatibility with kernel definitions
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define __LITTLE_ENDIAN_BITFIELD
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define __BIG_ENDIAN_BITFIELD
#else
# error "Fix your compiler's __BYTE_ORDER__?!"
#endif

enum bpf_map_type {
BPF_MAP_TYPE_UNSPEC = 0,
BPF_MAP_TYPE_HASH = 1,
Expand Down Expand Up @@ -73,6 +64,19 @@ enum xdp_action {
XDP_REDIRECT = 4,
};

enum tc_action {
TC_ACT_UNSPEC = -1,
TC_ACT_OK = 0,
TC_ACT_RECLASSIFY = 1,
TC_ACT_SHOT = 2,
TC_ACT_PIPE = 3,
TC_ACT_STOLEN = 4,
TC_ACT_QUEUED = 5,
TC_ACT_REPEAT = 6,
TC_ACT_REDIRECT = 7,
TC_ACT_JUMP = 0x10000000
};

struct xdp_md {
__u32 data;
__u32 data_end;
Expand All @@ -84,10 +88,7 @@ struct xdp_md {

typedef __u16 __sum16;

#define ETH_P_IP 0x0800
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define ETH_P_IP 0x0800

struct ethhdr {
unsigned char h_dest[6];
Expand All @@ -109,128 +110,6 @@ struct iphdr {
__be32 daddr;
};

/*struct __sk_buff https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf.h */
#define __bpf_md_ptr(type, name) \
union { \
type name; \
__u64 :64; \
} __attribute__((aligned(8)))

struct __sk_buff {
__u32 len;
__u32 pkt_type;
__u32 mark;
__u32 queue_mapping;
__u32 protocol;
__u32 vlan_present;
__u32 vlan_tci;
__u32 vlan_proto;
__u32 priority;
__u32 ingress_ifindex;
__u32 ifindex;
__u32 tc_index;
__u32 cb[5];
__u32 hash;
__u32 tc_classid;
__u32 data;
__u32 data_end;
__u32 napi_id;

/* Accessed by BPF_PROG_TYPE_sk_skb types from here to ... */
__u32 family;
__u32 remote_ip4; /* Stored in network byte order */
__u32 local_ip4; /* Stored in network byte order */
__u32 remote_ip6[4]; /* Stored in network byte order */
__u32 local_ip6[4]; /* Stored in network byte order */
__u32 remote_port; /* Stored in network byte order */
__u32 local_port; /* stored in host byte order */
/* ... here. */

__u32 data_meta;
__bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
__u64 tstamp;
__u32 wire_len;
__u32 gso_segs;
__bpf_md_ptr(struct bpf_sock *, sk);
__u32 gso_size;
};

/*TCP Header https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h */
struct tcphdr {
__be16 source;
__be16 dest;
__be32 seq;
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__be16 window;
__sum16 check;
__be16 urg_ptr;
};

/*UDP Header https://github.com/torvalds/linux/blob/master/include/uapi/linux/udp.h */
struct udphdr {
__be16 source;
__be16 dest;
__be16 len;
__sum16 check;
};

/*ICMP Header https://github.com/torvalds/linux/blob/master/include/uapi/linux/icmp.h */
struct icmphdr {
__u8 type;
__u8 code;
__sum16 checksum;
union {
struct {
__be16 id;
__be16 sequence;
} echo;
__be32 gateway;
struct {
__be16 __unused;
__be16 mtu;
} frag;
__u8 reserved[4];
} un;
};

enum tc_action {
TC_ACT_UNSPEC = -1,
TC_ACT_OK = 0,
TC_ACT_RECLASSIFY = 1,
TC_ACT_SHOT = 2,
TC_ACT_PIPE = 3,
TC_ACT_STOLEN = 4,
TC_ACT_QUEUED = 5,
TC_ACT_REPEAT = 6,
TC_ACT_REDIRECT = 7,
TC_ACT_JUMP = 0x10000000
};

enum {
BPF_ANY = 0,
BPF_NOEXIST = 1,
Expand Down
23 changes: 6 additions & 17 deletions examples/tcx/bpf_bpfeb.go

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

Binary file modified examples/tcx/bpf_bpfeb.o
Binary file not shown.
23 changes: 6 additions & 17 deletions examples/tcx/bpf_bpfel.go

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

Binary file modified examples/tcx/bpf_bpfel.o
Binary file not shown.
61 changes: 20 additions & 41 deletions examples/tcx/main.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,22 @@
// This program demonstrates attaching an eBPF program to a network interface
// with Linux TC. The program parses the IPv4 source address
// from packets and writes the Ingress and Egress packet count to an Hash map.
// The userspace program (Go code in this file) prints the content of the map to stdout.
// with Linux TC (Traffic Control). The program counts ingress and egress
// packets using two ARRAY maps.
// The userspace program (Go code in this file) prints the contents
// of the two maps to stdout every second.
// This example depends on bpf_link, available in Linux kernel version 5.7 or newer.
package main

import (
"encoding/binary"
"fmt"
"log"
"net"
"net/netip"
"os"
"strings"
"time"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
)

// mapping between integer value and L4 protocol string
var protoMap = map[uint8]string{
1: "ICMP",
6: "TCP",
17: "UDP",
}

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go bpf tcx.c -- -I../headers
func main() {
if len(os.Args) < 2 {
Expand Down Expand Up @@ -72,49 +64,36 @@ func main() {
log.Printf("Attached TCx program to EGRESS iface %q (index %d)", iface.Name, iface.Index)
log.Printf("Press Ctrl-C to exit and remove the program")

// Print the contents of the BPF hash map.
// Print the contents of the counters maps.
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for range ticker.C {
s, err := formatMapContent(objs.StatsMap)
s, err := formatCounters(objs.IngressPktCount, objs.EgressPktCount)
if err != nil {
log.Printf("Error reading map: %s", err)
continue
}

log.Printf("Map contents:\n%s", s)
log.Printf("Packet Count: %s\n", s)
}
}

// formatMapContent prints the content of the map into a string.
func formatMapContent(m *ebpf.Map) (string, error) {
func formatCounters(ingressMap, egressMap *ebpf.Map) (string, error) {
var (
sb strings.Builder
key bpfSessionKey
val bpfSessionValue
ingressPacketCount uint64
egressPacketCount uint64
key int32
)

iter := m.Iterate()
for iter.Next(&key, &val) {
sb.WriteString(fmt.Sprintf("\t%15s:%5d - %15s:%5d Proto:%4s => Ingress:%10d Egress:%10d\n",
intToIp(key.Saddr), portToLittleEndian(key.Sport),
intToIp(key.Daddr), portToLittleEndian(key.Dport),
protoMap[key.Proto], val.InCount, val.EgCount))
// retrieve value from the ingress map
if err := ingressMap.Lookup(&key, &ingressPacketCount); err != nil {
return "", err
}

return sb.String(), iter.Err()
}

// 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)
}
// retrieve value from the egress map
if err := egressMap.Lookup(&key, &egressPacketCount); err != nil {
return "", err
}

// 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[:])
return fmt.Sprintf("%10v Ingress, %10v Egress", ingressPacketCount, egressPacketCount), nil
}
Loading

0 comments on commit af08538

Please sign in to comment.