Skip to content

Commit

Permalink
add basic filter framework: skb_checker
Browse files Browse the repository at this point in the history
  • Loading branch information
jschwinger233 committed Mar 5, 2023
1 parent 8474ca6 commit 02af0a2
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 7 deletions.
2 changes: 1 addition & 1 deletion internal/bpf/bpf.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package bpf

//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -no-strip -target native -type skb_meta -type skb_data Skbdump ./skbdump.c -- -I./headers -Wall
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -no-strip -target native -type skb_meta -type skb_data Skbdump ./skbdump.c -- -I./headers -I. -Wall
78 changes: 78 additions & 0 deletions internal/bpf/headers/endian.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#ifndef __BPF_ENDIAN__
#define __BPF_ENDIAN__

/*
* Isolate byte #n and put it into byte #m, for __u##b type.
* E.g., moving byte #6 (nnnnnnnn) into byte #1 (mmmmmmmm) for __u64:
* 1) xxxxxxxx nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx
* 2) nnnnnnnn xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx mmmmmmmm xxxxxxxx 00000000
* 3) 00000000 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn
* 4) 00000000 00000000 00000000 00000000 00000000 00000000 nnnnnnnn 00000000
*/
#define ___bpf_mvb(x, b, n, m) ((__u##b)(x) << (b - (n + 1) * 8) >> (b - 8) << (m * 8))

#define ___bpf_swab16(x) ((__u16)(___bpf_mvb(x, 16, 0, 1) | ___bpf_mvb(x, 16, 1, 0)))

#define ___bpf_swab32(x) ((__u32)(___bpf_mvb(x, 32, 0, 3) | ___bpf_mvb(x, 32, 1, 2) | ___bpf_mvb(x, 32, 2, 1) | ___bpf_mvb(x, 32, 3, 0)))

#define ___bpf_swab64(x) ((__u64)(___bpf_mvb(x, 64, 0, 7) | ___bpf_mvb(x, 64, 1, 6) | ___bpf_mvb(x, 64, 2, 5) | ___bpf_mvb(x, 64, 3, 4) | ___bpf_mvb(x, 64, 4, 3) | ___bpf_mvb(x, 64, 5, 2) | ___bpf_mvb(x, 64, 6, 1) | ___bpf_mvb(x, 64, 7, 0)))

/* LLVM's BPF target selects the endianness of the CPU
* it compiles on, or the user specifies (bpfel/bpfeb),
* respectively. The used __BYTE_ORDER__ is defined by
* the compiler, we cannot rely on __BYTE_ORDER from
* libc headers, since it doesn't reflect the actual
* requested byte order.
*
* Note, LLVM's BPF target has different __builtin_bswapX()
* semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE
* in bpfel and bpfeb case, which means below, that we map
* to cpu_to_be16(). We could use it unconditionally in BPF
* case, but better not rely on it, so that this header here
* can be used from application and BPF program side, which
* use different targets.
*/
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define __bpf_ntohs(x) __builtin_bswap16(x)
#define __bpf_htons(x) __builtin_bswap16(x)
#define __bpf_constant_ntohs(x) ___bpf_swab16(x)
#define __bpf_constant_htons(x) ___bpf_swab16(x)
#define __bpf_ntohl(x) __builtin_bswap32(x)
#define __bpf_htonl(x) __builtin_bswap32(x)
#define __bpf_constant_ntohl(x) ___bpf_swab32(x)
#define __bpf_constant_htonl(x) ___bpf_swab32(x)
#define __bpf_be64_to_cpu(x) __builtin_bswap64(x)
#define __bpf_cpu_to_be64(x) __builtin_bswap64(x)
#define __bpf_constant_be64_to_cpu(x) ___bpf_swab64(x)
#define __bpf_constant_cpu_to_be64(x) ___bpf_swab64(x)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define __bpf_ntohs(x) (x)
#define __bpf_htons(x) (x)
#define __bpf_constant_ntohs(x) (x)
#define __bpf_constant_htons(x) (x)
#define __bpf_ntohl(x) (x)
#define __bpf_htonl(x) (x)
#define __bpf_constant_ntohl(x) (x)
#define __bpf_constant_htonl(x) (x)
#define __bpf_be64_to_cpu(x) (x)
#define __bpf_cpu_to_be64(x) (x)
#define __bpf_constant_be64_to_cpu(x) (x)
#define __bpf_constant_cpu_to_be64(x) (x)
#else
#error "Fix your compiler's __BYTE_ORDER__?!"
#endif

#define bpf_htons(x) \
(__builtin_constant_p(x) ? __bpf_constant_htons(x) : __bpf_htons(x))
#define bpf_ntohs(x) \
(__builtin_constant_p(x) ? __bpf_constant_ntohs(x) : __bpf_ntohs(x))
#define bpf_htonl(x) \
(__builtin_constant_p(x) ? __bpf_constant_htonl(x) : __bpf_htonl(x))
#define bpf_ntohl(x) \
(__builtin_constant_p(x) ? __bpf_constant_ntohl(x) : __bpf_ntohl(x))
#define bpf_cpu_to_be64(x) \
(__builtin_constant_p(x) ? __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x))
#define bpf_be64_to_cpu(x) \
(__builtin_constant_p(x) ? __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x))

#endif /* __BPF_ENDIAN__ */
16 changes: 16 additions & 0 deletions internal/bpf/headers/skbdump.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,19 @@
#ifndef MAX_DATA_SIZE
#define MAX_DATA_SIZE (1024-4)
#endif

#ifndef ETH_P_IP
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
#endif

#ifndef ETH_P_IPV6
#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
#endif

#ifndef ETH_P_ARP
#define ETH_P_ARP 0x0806 /* Address Resolution packet */
#endif

#ifndef ETH_P_8021Q
#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
#endif
69 changes: 69 additions & 0 deletions internal/bpf/skb_checker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "vmlinux.h"
#include "bpf_helpers.h"
#include "endian.h"

#define MAX_LAYER 6

static __always_inline
bool check_eth(struct ethhdr *eth)
{
return true;
}

static __always_inline
bool check_ipv4(struct iphdr *ip)
{
return bpf_ntohl(ip->daddr) == 167837953; // 10.1.1.1
}

static __always_inline
bool check_icmp(struct icmphdr *icmp)
{
return true;
}

struct skb_checker {
void *cursor;
void *data_end;
};

static __always_inline
bool check_next_layer(struct skb_checker *checker, __u32 *this_proto)
{
__u16 l2_proto = (__u16)(*this_proto >> 16);
__u8 l3_proto = (__u8)(*this_proto & 0xff);

struct ethhdr *eth = checker->cursor;
struct iphdr *ip = checker->cursor;
struct icmphdr *icmp = checker->cursor;

switch (l3_proto) {
case (__u32)IPPROTO_ICMP:
if ((void *)icmp + sizeof(*icmp) <= checker->data_end) {
*this_proto = (__u32)IPPROTO_MAX;
return check_icmp(icmp);
}
return true;
}

switch (bpf_ntohs(l2_proto)) {
case 0:
if ((void *)eth + sizeof(*eth) <= checker->data_end) {
*this_proto = ((__u32)eth->h_proto) << 16;
checker->cursor += sizeof(*eth);
return check_eth(eth);

}
return true;

case ETH_P_IP:
if ((void *)ip + sizeof(*ip) <= checker->data_end) {
*this_proto = (__u32)ip->protocol;
checker->cursor += sizeof(*ip);
return check_ipv4(ip);
}
return true;
}

return false;
}
27 changes: 21 additions & 6 deletions internal/bpf/skbdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "bpf_helpers.h"
#include "skbdump.h"
#include "skb_data.h"
#include "skb_checker.h"


char __license[] SEC("license") = "Dual MIT/GPL";
Expand All @@ -27,11 +28,25 @@ struct bpf_map_def SEC("maps") meta_queue = {
.max_entries = MAX_QUEUE_SIZE,
};

static __always_inline void
handle_skb(struct __sk_buff *skb, bool ingress)
static __always_inline
void handle_skb(struct __sk_buff *skb, bool ingress)
{
bpf_skb_pull_data(skb, 0);

struct skb_checker checker;
__builtin_memset(&checker, 0, sizeof(checker));
checker.cursor = (void *)(long)skb->data;
checker.data_end = (void *)(long)skb->data_end;

__u32 this_proto = 0;
for (int layer=0; layer<MAX_LAYER; layer++) {
if (!check_next_layer(&checker, &this_proto))
return;

if (this_proto == (__u32)IPPROTO_MAX)
break;
}

struct skb_meta meta = {};
__builtin_memset(&meta, 0, sizeof(meta));
meta.is_ingress = ingress;
Expand All @@ -45,13 +60,13 @@ handle_skb(struct __sk_buff *skb, bool ingress)
SEC("tc")
int on_egress(struct __sk_buff *skb)
{
handle_skb(skb, false);
return TC_ACT_OK;
handle_skb(skb, false);
return TC_ACT_OK;
}

SEC("tc")
int on_ingress(struct __sk_buff *skb)
{
handle_skb(skb, true);
return TC_ACT_OK;
handle_skb(skb, true);
return TC_ACT_OK;
}
Binary file modified internal/bpf/skbdump_bpfel_x86.o
Binary file not shown.

0 comments on commit 02af0a2

Please sign in to comment.