#ifndef __ZENITH_XDP_COMMON_H__
#define __ZENITH_XDP_COMMON_H__
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
struct {
__uint(type, BPF_MAP_TYPE_XSKMAP);
__uint(max_entries, 64);
__uint(key_size, sizeof(u32));
__uint(value_size, sizeof(u32));
} xsk_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 256);
__uint(key_size, sizeof(u32));
__uint(value_size, sizeof(u64));
} stats_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 128);
__uint(key_size, sizeof(u32));
__uint(value_size, sizeof(u64));
} config_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__uint(key_size, sizeof(u32));
__uint(value_size, 80);
} expectation_map SEC(".maps");
#define STATS_RX_PACKETS 0
#define STATS_RX_VALID 1
#define STATS_RX_DROP_SHORT 2
#define STATS_RX_DROP_BAD_ETH 3
#define STATS_RX_DROP_BAD_IP 4
#define STATS_RX_DROP_NO_XSK 5
#define STATS_REDIRECTED 6
#define STATS_RX_DROP_PROTO 7
#define CONFIG_KEY_MTU 0
#define CONFIG_KEY_PROTO_WHITELIST 1
#define CONFIG_KEY_FAIL_CLOSED 2
#define CONFIG_KEY_WHITELIST_ENABLED 3
#define CONFIG_KEY_EXPECTATION 10
#ifndef IPPROTO_ICMPV6
#define IPPROTO_ICMPV6 58
#endif
#define DEFAULT_PROTO_WHITELIST \
((1ULL << IPPROTO_TCP) | (1ULL << IPPROTO_UDP) | \
(1ULL << IPPROTO_ICMP) | (1ULL << IPPROTO_ICMPV6))
static __always_inline void
update_stats(u32 stat_id, u64 inc)
{
u64 *val;
val = bpf_map_lookup_elem(&stats_map, &stat_id);
if (val)
__sync_fetch_and_add(val, inc);
}
static __always_inline bool
check_eth_header(struct xdp_md *ctx, void *data, void *data_end)
{
struct ethhdr *eth;
if ((void *)(data + sizeof(struct ethhdr)) > data_end)
return false;
eth = data;
switch (eth->h_proto) {
case bpf_htons(ETH_P_IP):
case bpf_htons(ETH_P_IPV6):
case bpf_htons(ETH_P_ARP):
case bpf_htons(ETH_P_VLAN):
return true;
default:
return false;
}
}
static __always_inline bool
check_ipv4_header(void *l3_hdr, void *data_end)
{
struct iphdr *iph = l3_hdr;
if ((void *)(iph + 1) > data_end)
return false;
if (iph->version != 4)
return false;
if (iph->ihl < 5)
return false;
u32 ip_len = iph->ihl * 4;
if ((void *)((u8 *)iph + ip_len) > data_end)
return false;
u32 daddr = iph->daddr;
if (daddr == 0xFFFFFFFF)
return false;
return true;
}
static __always_inline bool
check_ipv6_header(void *l3_hdr, void *data_end)
{
struct ipv6hdr *ip6h = l3_hdr;
if ((void *)(ip6h + 1) > data_end)
return false;
if (ip6h->version != 6)
return false;
return true;
}
static __always_inline bool
is_ipv6_extension_header(u8 nexthdr)
{
switch (nexthdr) {
case 0:
case 43:
case 44:
case 50:
case 51:
case 60:
return true;
default:
return false;
}
}
static __always_inline u64
get_config_u64(u32 key)
{
u64 *val;
val = bpf_map_lookup_elem(&config_map, &key);
if (val)
return *val;
return 0;
}
static __always_inline u32
get_config_u32(u32 key)
{
return (u32)get_config_u64(key);
}
static __always_inline bool
proto_whitelist_allowed(u8 proto)
{
u64 bitmap = get_config_u64(CONFIG_KEY_PROTO_WHITELIST);
u32 whitelist_enabled = get_config_u32(CONFIG_KEY_WHITELIST_ENABLED);
if (whitelist_enabled == 0 && bitmap == 0)
bitmap = DEFAULT_PROTO_WHITELIST;
if (proto >= 64)
return false;
return (bitmap & (1ULL << proto)) != 0;
}
#endif