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

bpf: clean-room implementation of parts of the code #2048

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

bpf: clean-room implementation of parts of the code

  • Loading branch information...
pothos committed Jun 18, 2019
commit 62c95df8d3041ab3037998d62fdd2fe480228097
@@ -33,8 +33,8 @@ import (

const (
// tags of the XDP program, need to be changed if the XDP program changes
realTag = "d3b98a39bdd3181e" // as shown by running bpftool prog show
mockTag = "fcaaae5bb109d90c" // sha-1 of the ELF object truncated to 16 characters
realTag = "b9f0924afa5cb3fe" // as shown by running bpftool prog show
mockTag = "b9984a4a5af84b1d" // sha-1 of the ELF object truncated to 16 characters
)

var (
@@ -1,54 +1,39 @@
// from kernel headers
#include <asm/byteorder.h>
#ifndef _BPF_H
#define _BPF_H 1
#include <linux/bpf.h>
#include <stdint.h>
#include <endian.h>

#ifndef __section
# define __section(NAME) \
__attribute__((section(NAME), used))
#ifndef __always_inline
#define __always_inline __attribute__((always_inline))
#endif

#ifndef __inline
# define __inline \
inline __attribute__((always_inline))
#endif
#define __section(s) __attribute__((section(s)))

#ifndef BPF_FUNC
# define BPF_FUNC(NAME, ...) \
(*NAME)(__VA_ARGS__) = (void *)BPF_FUNC_##NAME
#endif
#define bpf_htons(x) htobe16(x)

#if __BYTE_ORDER == __LITTLE_ENDIAN
# define __bpf_ntohs(x) __builtin_bswap16(x)
# define __bpf_htons(x) __builtin_bswap16(x)
# define __bpf_ntohl(x) __builtin_bswap32(x)
# define __bpf_htonl(x) __builtin_bswap32(x)
#elif __BYTE_ORDER == __BIG_ENDIAN
# define __bpf_ntohs(x) (x)
# define __bpf_htons(x) (x)
# define __bpf_ntohl(x) (x)
# define __bpf_htonl(x) (x)
#else
# error "Fix your __BYTE_ORDER?!"
#endif
#define bpf_htonl(x) htobe32(x)

#define bpf_ntohs(x) be16toh(x)

#define bpf_ntohl(x) be32toh(x)

struct bpf_elf_map;

struct sk_buff;

struct bpf_sock_ops;

#define bpf_htons(x) \
(__builtin_constant_p(x) ? \
__constant_htons(x) : __bpf_htons(x))
#define bpf_ntohs(x) \
(__builtin_constant_p(x) ? \
__constant_ntohs(x) : __bpf_ntohs(x))

#define bpf_htonl(x) \
(__builtin_constant_p(x) ? \
__constant_htonl(x) : __bpf_htonl(x))
#define bpf_ntohl(x) \
(__builtin_constant_p(x) ? \
__constant_ntohl(x) : __bpf_ntohl(x))

static void *BPF_FUNC(map_lookup_elem, void *map, const void *key);
static int BPF_FUNC(skb_load_bytes, void *ctx, int off, void *to, int len);
static int BPF_FUNC(map_update_elem, void *map, const void *key,
const void *value, uint32_t flags);
static int BPF_FUNC(sock_hash_update, struct bpf_sock_ops *skops, void *map, void *key, uint64_t flags);
static int BPF_FUNC(msg_redirect_hash, struct sk_msg_md *md, void *map, void *key, uint64_t flags);
struct sk_msg_md;

static void *(*bpf_map_lookup_elem) (struct bpf_elf_map *map, const void *key) = (void *) BPF_FUNC_map_lookup_elem;

static int (*bpf_map_update_elem) (struct bpf_elf_map *map, const void *key, const void *value, __u64 flags) = (void *) BPF_FUNC_map_update_elem;

static int (*bpf_skb_load_bytes) (const struct sk_buff *skb, __u32 offset, void *to, __u32 len) = (void *) BPF_FUNC_skb_load_bytes;

static int (*bpf_sock_hash_update) (struct bpf_sock_ops *skops, struct bpf_elf_map *map, void *key, __u64 flags) = (void *) BPF_FUNC_sock_hash_update;

static int (*bpf_msg_redirect_hash) (struct sk_msg_md *msg, struct bpf_elf_map *map, void *key, __u64 flags) = (void *) BPF_FUNC_msg_redirect_hash;

#endif
@@ -15,8 +15,8 @@ var _ = func() error {
g := packr.New(gk, "")
hgr, err := resolver.NewHexGzip(map[string]string{
"3a3318092d59d7ebee003ff8276d55d5": "1f8b08000000000000ff8c533f8b134114ffed1fcddde50a39afd8c2c242100e5c96130b0f8b5ce01424101043ca711c3626246b4276c1bf90ca3e8da0b58ddf2065fc207e881482762b33f3c6ecce6e880f765edeeffdfbbd9799c555e7b1eb3830e2e037b6d656bebbdbdf2d3a8fe06045b838fb934bfde16ca3f4ca83aac34f74f44f17b821edd340d93dbf8905e0f4dc235c7c05f8cd470a0f7c79e6b9e9b53ed79ab5b57e4375fa9e8eea925ff683aa7f4a7c7ea91ae2a9e6232e34bff5371dd7f0804d9ee7815b9e73e56bde9f003c9136b4fd99fc27008e01f8259665b99c71318cef9d8791e6aaf6fafe190e3e361d991bd06764535fa6244c9d1ebed4f83c7815ec0164efeb15fcaec2abf1c70abf56c17f18fe80f2de2ad86a756116bfcd90f0590ac127233165e9548c59c26708e7f1241db3247df5cfa52dc6189b8c44fc3a8d5550180fd960ce9318619acd33fe1261fa2e91bad36e47ecfe7fec679f74d59eaad2a2ff7f60e1f61b70e8b337dadad1cfb7ec704fbe7d070e2c5beefdb0a6cf6de26feed921cd69f20ddea0fef60e221af4ce1efe0f77e43fa7fca685dbfbbb2ade9982bca0c0c8c2edf92f77cc1fd5ccdfa899bf5fd35bca92fa2f0bbc8bfb33eff46f000000ffff22181f7828050000",
"58007a7c4b4be5bdad56373b1cb409c0": "1f8b08000000000000ff9454cf6b135110fe5eb69a4de3a10a95102b54e85197a4a2564f6db1a54845148a070fcbbaae2634bfc82e9854a18288e2452fa21efdf107788bb7f5cff0e0a1c71c3cf4660fe2ca7b33cb6ede26940e64bf7cdfcecc7b33f3f6edae6daee784406c027f90b0c4be4d25ff97f9390d81f034698e4358ca01ffa2288a7ded73845be232648a012777cbfbcae7497918517c09c4f788d7af53de477384355a55c6cfabf803e5e7eefc55187ea6bcf91c70104551492be285aa0dd8c2f4d83cfd4fb4ae5b3e5abe599c51bcff95e27f158019ce2fdf0f72ec5710b8f691b8b4d9bcc02e20e27e84cf09ef1a80ecde6393f224fd23c730207e6b49d33f8cf6d57dfd9bf006f537fcc2f518c0308aa23035afb40da692fad62567fd1de32900270035cb64caa3560460727fa4cfb8f3b4d271dc9a7761d1aa109f615decdc81f9b428e41a25fec5b63f2e91666fd4d3c05bcdf725eb7b9afe8c7553d3fbac2f697a97f50d4ddf66bd37668f068c8cb6a26a3e9ed1ab4a3f96d1cf2a3d9b27cffe0b9acec741f55ece63a8f11f22e1050073a9f73227acc0eb05f05a0f3aed7a2bf06175bd86df76b7db1d1faed3a8bb6d3ba64d6754b39b4e07b66ddb8dbaebb57c4fc55a5ecd7ed8759a1e2c3fe806ce7d587ebf29717375b5625f25b8427089e022417591b19aeded51ed9e9a47d64a7ceedf6bba3e4ec13f7d72cb13d69bd2f8c221f1fa193735bf933c2fdd7e7251fc39291f23151f7f5fe7797dbd0715be07360ed9ffda84f81ec717355defdf6dd6b46b07af72a3fb8f4dafffe684fa4dde685c6781cfb15ebf3b666d69df599c4f7d17662a3ebe87fe070000fffffa67146d30070000",
"ad15098d1cedf7524395e290eb19dcab": "1f8b08000000000000ff9c54416b135110fede6ed3b4564b5ba996a2506a11096689d506a90763a12a5810841c6559b72f4d306937bb8b5411d483078f1e3c78f54fe82d1e7becd1833fc243d01cc4c8ce9b75b76f37b4f8203b99efcdcc37dfbcb7fb6a73ebae2104e225f00b8997ac83b1e47f8d9fa720d03ba7b0cf940b388e0a747614def3952d1ac03480f29ccaeefaa7950dce90dd318109000f2f25f50c0075739df0749de5145f79aeaaf8ba8b2acf009600b8a5c130f2ddc5df647b9f92fcc170385cd044bee57a3d71947f5e94549fddf364e7c5346653fc757119e3cc4b7d6cb37e97f5af316f41f55dde3cabeaada97af5c22ce5a7e3aa14374d7e0153ff749dac7e51ab5fa07ed371258a53055bab2b64bf1bc04cc463aa3877bd4f737b5afa493658ec67e6d83fe11c05cd4d1c99eb078e8fd445e74baa0e8bb9774ff07e64ff0c456ecc1dcf719bb2bc6a55943f13e7be788489975322ba6d0bfc8b57cdc829a4adf7f434d1d448df31fe55c3df307ea8e192f19b399c26cc0c768b348c67f022e105ac687887717d2d139eadff85ade0f9c348fc88e3426a9faa5aa1dc0fe13aed96bb67379c563b701ad2f6f6fc3040c7f102ec6f7bb6dc0da50fcb976dcf97e546ab1db9b66ddbed962b7703495b966cda0ddfe9485841e887ce1358c1f34e64b736362af6b56acce2f95295b09fdde0bdd85e675bc94ef3ff569dce21bbaef077efa386eb7750f04f3fb1da08be31cdaf1c93afdfd5092dee2a80c91c9e018b5a627f9275c6f9f17b7291f9f519bc66defbc7f47f7b44fe01e74f69b83ebf078ce9afc73706f483d6f5df1ba17f811b8d754ef2fdd6f53fcee1261e16f423d5f7782a3ffe9efc0d0000ffffa30396e248070000",
"58007a7c4b4be5bdad56373b1cb409c0": "1f8b08000000000000ff94544d6b1351143d6f124dd2b8a8626588152a74e14287b44a29ba498b2d452aa250145c0ce3389ad07c9119d054a18208c1951b21eefc5af80fb21c972efd012e5c66e1a23bb31047e6bd3bcee44e42e985e4e49cdc8f77ef7d33fb1bdb9b9a10884ce0376216dbd76cfcbb42df3310f0cf28cdb24e4bdc11d7a049ae745d03fe064110c59ae7417e2b08530ea8985d3a903ecf4ac340e5d3a1f84fc56bd7559dc7f30aabea1461fc828c1f493f7bef8f44ffa3ca9bd3805110043a6bea95ec15d8c1ccc43cdd0faaae5d3a5abe399c95bcfb59c5ff2800b3943ffc7fa0915f41e0ea3bc5439bcb09ec03229a87ff52e1dd0c104eef495ee589e7a71c7d4ff15bab4cef8fcfd57efd4be10d355fff13f59301864110f8897d256d908dfbdb0c39e96f094f013801c85dc65b1eb722803ccd27f49974bfd6da965d752e2d1b65c56749177b77907f5e14610d9d3eff4d9b5c2f696fe477063d56b447fa7ba6bf20fd80e95dd2f9de3ba46f317d97f47b139acd2093d2d664cfc753fa92d48fa5f473524fe7c991ff22d3bf100adac788f1ef22e60500f389ffc39c303ce7a907a7f9b0ddaa353d1746c7a9bb2d7bb7d576615bf59add3223dab0c635b361b5619aa659afd94ed37564ace154cd471dabe1c070bd8e673d80e1761b216eafaf97cd55052b0aae2858ba4cb84c584e0ff788765fee236d17e8def799ced729e8c3375799522fcbf8e261f1ec8ee799df49da17b72135154da8407d46f1d1f37591eaf31954a8eed621e7df9812dfa3f822d3f9fc6e93c61fe5be367efec878ff37a7f4afd341a33e0b748f79fff694d7c837121712cf453e111fbd87fe050000ffff540f646340070000",
"ad15098d1cedf7524395e290eb19dcab": "1f8b08000000000000ff94544d6b1361107ede6df3d568698562080aa11491609628a2110fd6821f604110025e645dd73726b86937bb8bc42a8882d09378d1b3f827eaad7fc11fe0c19fe0a1680fe2cafbce2c09ef6e2c0e64a7f3ccd73333db7d7563f3a625045211f885893591c6fce4ef757e2e4060af081defd628c03d4931fb23d225012c0268bd3ea7edd1e818e9f0b8d64f2ca00ce0ee098a57f52c005deb8cc6f798cc8bfa6162d65dd5751bd47754a77c0b5088d7a478affe9bf23e739e051c26495233867c0b9a63053440dad7ab1f24c49bf01551c0b2e22796515475c349dd4b8acf9b456d1730477b98f237b57f41db83704deb88eb7fb38025004f9b3f337c0ffec1b7cbd74aefb0ff90fc1f38ae0adaafbeced752ee6d05fb95fe9388dc98eb81ebf565eb82dd267b29cdddb987f2cbaa5057adf12f954f79850c79a79f73786fc4468c370cdc67bc63e092f1dd9c9e737c8b69b9aa672866f092c60b5833f01dc64d59d578b6fe17d682f7df17135bf53835e5d755ed588e6378ae3ff0b69d9e3bf023b7279d603b8c230cdd20c2f871e0c8ad5886b043e907a16cf506be321dc771fc8127b722a95db6ec3bbdd01d4ad8511cc6ee23d8d1f3a1d29b1b1b6de70aa90ea9cb69cb209454cf7976915ce7dbd955feb774f5feb3b2cbe0470337cf27f8675e6a7d46bf79c36e1f916fbea365234e7db52a397dee33ff06db159e33cd4fff3f4e737f7307dfb9efed23f85f9b917fd6225d3570737f7718b30cbcc380796373fe5b33e61f33a174ce0abfd7e6fc0f727a2be933f8638a77712a3ffd8efc0d0000ffff58459930a0060000",
})
if err != nil {
panic(err)
@@ -48,7 +48,7 @@ int calico_sk_msg(struct sk_msg_md *msg)
key.envoy_side = 1;
}

err = msg_redirect_hash(msg, &calico_sock_map, &key, flags);
err = bpf_msg_redirect_hash(msg, &calico_sock_map, &key, flags);

// If the packet couldn't be redirected, pass it to the rest of the
// stack.
@@ -28,15 +28,15 @@ static inline struct endpoint_info *lookup_endpoint(uint32_t ip)
__builtin_memcpy(key.lpm.data, &ip, sizeof(key.addr));
key.lpm.prefixlen = 32;

return map_lookup_elem(&endpoints, &key);
return bpf_map_lookup_elem(&endpoints, &key);
}

static inline int has_endpoint(uint32_t ip)
{
return lookup_endpoint(ip) != NULL;
}

static inline void bpf_sock_ops_ipv4(struct bpf_sock_ops *skops)
static inline void sockops_established(struct bpf_sock_ops *skops)
{
struct sock_key key = {};
__u32 sip4, dip4, sport, dport;
@@ -85,24 +85,16 @@ static inline void bpf_sock_ops_ipv4(struct bpf_sock_ops *skops)
key.envoy_side = 0;
}

sock_hash_update(skops, &calico_sock_map, &key, BPF_ANY);
bpf_sock_hash_update(skops, &calico_sock_map, &key, BPF_ANY);
}

__section("sockops")
int calico_sockops(struct bpf_sock_ops *skops)
{
__u32 family, op;

family = skops->family;
op = skops->op;

switch (op) {
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
bpf_sock_ops_ipv4(skops);
break;
default:
break;
if (skops->family == AF_INET &&
(skops->op == BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB ||
skops->op == BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB)) {
sockops_established(skops);
}

return 0;
@@ -23,33 +23,13 @@

#include "../include/bpf.h"

static __always_inline void *xdp_data(const struct xdp_md *xdp)
{
return (void *)(unsigned long)xdp->data;
}

static __always_inline void *xdp_data_end(const struct xdp_md *xdp)
{
return (void *)(unsigned long)xdp->data_end;
}

static __always_inline bool xdp_no_room(const void *needed, const void *limit)
{
return needed > limit;
}

struct lpm_v4_key {
struct prefilter_key {
struct bpf_lpm_trie_key lpm;
__u8 addr[4];
};

struct lpm_val {
__u32 ref_count;
__u8 ip[4];
};

struct failsafe_key {
__u8 proto;
__u8 pad;
__u8 protocol;
__u16 port;
};

@@ -63,11 +43,11 @@ struct failsafe_value {
// Key: the CIDR, formatted for LPM lookup
// Value: reference count, used only by felix
struct bpf_elf_map calico_prefilter_v4 __section(ELF_SECTION_MAPS) = {
.type = BPF_MAP_TYPE_LPM_TRIE,
.size_key = sizeof(struct lpm_v4_key),
.size_value = sizeof(struct lpm_val),
.flags = BPF_F_NO_PREALLOC,
.max_elem = 512000, // arbitrary
.type = BPF_MAP_TYPE_LPM_TRIE,
.size_key = sizeof(struct prefilter_key),
.size_value = sizeof(__u32),
.max_elem = 512000, // arbitrary
.flags = BPF_F_NO_PREALLOC,
};

// calico_failsafe_ports contains one entry per port/proto that we should NOT
@@ -77,132 +57,69 @@ struct bpf_elf_map calico_prefilter_v4 __section(ELF_SECTION_MAPS) = {
// Key: the protocol and port
// Value: not used
struct bpf_elf_map calico_failsafe_ports __section(ELF_SECTION_MAPS) = {
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(struct failsafe_key),
.size_value = sizeof(struct failsafe_value),
.flags = BPF_F_NO_PREALLOC,
.max_elem = 65535 * 2, // number of ports for TCP and UDP
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(struct failsafe_key),
.size_value = sizeof(struct failsafe_value),
.max_elem = 131070, // number of ports for TCP and UDP
.flags = BPF_F_NO_PREALLOC,
};

static __always_inline
__u16 get_dest_port_ipv4_udp(struct xdp_md *ctx, __u64 nh_off)
__section("pre-filter")
int xdp_enter(struct xdp_md *xdp)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct iphdr *iph = data + nh_off;
struct udphdr *udph;
__u16 dport;

if (iph + 1 > data_end) {
return 0;
}
if (!(iph->protocol == IPPROTO_UDP)) {
return 0;
}
void *data = (void *)(__u64) xdp->data;
void *data_end = (void *)(__u64) xdp->data_end;
struct ethhdr *ethernet_header = data;
struct iphdr *ip_header = data + sizeof(struct ethhdr);
__u16 h_proto;

udph = (void *)(iph + 1);
if (udph + 1 > data_end) {
return 0;
if (ethernet_header + 1 > data_end) {
return XDP_DROP;
}

dport = bpf_ntohs(udph->dest);
return dport;
}
h_proto = ethernet_header->h_proto;
if (h_proto == bpf_htons(ETH_P_IP)) { // filter IPv4
struct prefilter_key key = {};
__u32 *ref_count;

static __always_inline
__u16 get_dest_port_ipv4_tcp(struct xdp_md *ctx, __u64 nh_off)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct iphdr *iph = data + nh_off;
struct tcphdr *tcph;
__u16 dport;

if (iph + 1 > data_end) {
return 0;
}
if (!(iph->protocol == IPPROTO_TCP)) {
return 0;
}
if (ip_header + 1 > data_end) {
return XDP_DROP;
}

tcph = (void *)(iph + 1);
if (tcph + 1 > data_end) {
return 0;
}
__builtin_memcpy(&key.lpm.data, &ip_header->saddr, sizeof(key.ip));
key.lpm.prefixlen = 32;
ref_count = bpf_map_lookup_elem(&calico_prefilter_v4, &key);
if (ref_count) { // maybe drop if source address in CIDR
struct failsafe_key protocol_and_port = {};

dport = bpf_ntohs(tcph->dest);
return dport;
}
if (ip_header->protocol == IPPROTO_TCP) {
struct tcphdr *tcp_header = (void *)(ip_header + 1);

if (tcp_header + 1 > data_end) {
return XDP_DROP;
}

static __always_inline int check_v4(struct xdp_md *xdp)
{
void *data_end = xdp_data_end(xdp);
void *data = xdp_data(xdp);
struct iphdr *ipv4_hdr = data + sizeof(struct ethhdr);
struct lpm_v4_key pfx;
__u16 dest_port;
protocol_and_port.port = bpf_ntohs(tcp_header->dest);
} else if (ip_header->protocol == IPPROTO_UDP) {
struct udphdr *udp_header = (void *)(ip_header + 1);

if (xdp_no_room(ipv4_hdr + 1, data_end)) {
return XDP_DROP;
}
if (udp_header + 1 > data_end) {
return XDP_DROP;
}

__builtin_memcpy(pfx.lpm.data, &ipv4_hdr->saddr, sizeof(pfx.addr));
pfx.lpm.prefixlen = 32;

if (map_lookup_elem(&calico_prefilter_v4, &pfx)) {
// check failsafe ports
switch (ipv4_hdr->protocol) {
case IPPROTO_TCP:
dest_port = get_dest_port_ipv4_tcp(xdp, sizeof(struct ethhdr));
break;
case IPPROTO_UDP:
dest_port = get_dest_port_ipv4_udp(xdp, sizeof(struct ethhdr));
break;
default:
protocol_and_port.port = bpf_ntohs(udp_header->dest);
} else {
return XDP_DROP;
}

struct failsafe_key key = {};
}

key.proto = ipv4_hdr->protocol;
key.port = dest_port;
if (map_lookup_elem(&calico_failsafe_ports, &key)) {
return XDP_PASS;
protocol_and_port.protocol = ip_header->protocol;
if (!bpf_map_lookup_elem(&calico_failsafe_ports, &protocol_and_port)) {
return XDP_DROP; // but only drop if not in failsafe ports
}
}

// no failsafe ports matched, drop
return XDP_DROP;
}

return XDP_PASS;
}


static __always_inline int check_prefilter(struct xdp_md *xdp)
{
void *data_end = xdp_data_end(xdp);
void *data = xdp_data(xdp);
struct ethhdr *eth = data;
__u16 proto;

if (xdp_no_room(eth + 1, data_end)) {
return XDP_DROP;
}

proto = eth->h_proto;
if (proto == bpf_htons(ETH_P_IP)) {
return check_v4(xdp);
} else {
/* other traffic can continue */
return XDP_PASS;
}
}

__section("pre-filter")
int xdp_enter(struct xdp_md *xdp)
{
return check_prefilter(xdp);
}

char ____license[] __section("license") = "Apache-2.0";
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.