Last active
February 18, 2024 02:09
-
-
Save astoycos/4e7a7de8520f8c1f274ec101fb96b76a to your computer and use it in GitHub Desktop.
XDP_REDIRECT_EX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SEC("xdp") | |
int xdp_nodeport_redirect(struct xdp_md *ctx) | |
{ | |
void *data_end = (void *)(long)ctx->data_end; | |
void *data = (void *)(long)ctx->data; | |
struct bpf_fib_lookup fib_params = {}; | |
struct ethhdr *eth = data; | |
struct tcphdr *tcph; | |
u16 h_proto; | |
u64 nh_off; | |
u64 tcp_off; | |
nh_off = sizeof(*eth); | |
struct iphdr *iph = data + nh_off; | |
tcp_off = nh_off + sizeof(*iph); | |
if (data + tcp_off > data_end) | |
return XDP_PASS; | |
tcp_off = nh_off + sizeof(*iph); | |
h_proto = eth->h_proto; | |
if (h_proto == bpf_htons(ETH_P_IP)) | |
{ | |
if (iph->protocol != IPPROTO_TCP) | |
return XDP_PASS; | |
tcph = data + tcp_off; | |
// Check header length. | |
if (tcph + 1 > (struct tcphdr *)data_end) | |
{ | |
return XDP_PASS; | |
} | |
struct V4_key key = { | |
.address = 0, | |
.dport = port_cast_16(tcph->dest), | |
.backend_slot = 0, | |
}; | |
struct lb4_service *svc = lb4_lookup_service(&key); | |
if (!svc) | |
{ | |
return XDP_PASS; | |
} | |
// This is how we know the service lookup was actually for a nodeport | |
if (svc->flags != 1 && svc->count != 0) | |
{ | |
return XDP_PASS; | |
} | |
// Lookup clusterIP of the service | |
__u32 backend_id = svc->backend_id; | |
struct lb4_backend *backend; | |
backend = __lb4_lookup_backend(backend_id); | |
if (!backend) | |
{ | |
return XDP_PASS; | |
} | |
key.address = backend->address; | |
key.dport = backend->port; | |
// Proxy straight to backend, to do that lookup backend with same logic as connect 4 prog | |
backend = __service_lookup(&key); | |
if (!backend) { | |
return XDP_PASS; | |
} | |
// Now we have an endpoint to route to | |
// Basically perform a DNAT here and then | |
// route to destination if we can | |
// // swap_src_dst_mac(eth); | |
iph->saddr = iph->daddr; | |
iph->daddr = backend->address; | |
tcph->source = tcph->dest; | |
tcph->dest = port_cast_32(backend->port); | |
/* populate the fib_params fields to prepare for the lookup */ | |
fib_params.family = AF_INET; | |
fib_params.tos = iph->tos; | |
fib_params.l4_protocol = iph->protocol; | |
fib_params.sport = 0; | |
fib_params.dport = 0; | |
fib_params.tot_len = bpf_ntohs(iph->tot_len); | |
fib_params.ipv4_src = 0; | |
fib_params.ipv4_dst = iph->daddr; | |
const char debug_str[] = "Hello, world, from BPF! I am in the XDP program. dst IP is %x dest port is %d new dst IP is %x"; | |
bpf_trace_printk(debug_str, sizeof(debug_str), iph->daddr, bpf_ntohs(tcph->dest), backend->address); | |
fib_params.ifindex = ctx->ingress_ifindex; | |
/* this is where the FIB lookup happens. If the lookup is successful */ | |
/* it will populate the fib_params.ifindex with the egress interface index */ | |
int rc = bpf_fib_lookup(ctx, &fib_params, sizeof(fib_params), 0); | |
const char debug_str2[] = "Looking for route to dst IP %x returned %d"; | |
bpf_trace_printk(debug_str2, sizeof(debug_str2), iph->daddr, rc); | |
switch (rc) { | |
case BPF_FIB_LKUP_RET_SUCCESS: /* lookup successful */ | |
/* we are a router, so we need to decrease the ttl */ | |
//if (h_proto == bpf_htons(ETH_P_IP)) | |
ip_decrease_ttl(iph); | |
const char debug_str4[] = "Redirect to eth src %x and eth dst %x route srcip %x"; | |
bpf_trace_printk(debug_str4, sizeof(debug_str4), fib_params.smac, fib_params.dmac, fib_params.ipv4_src); | |
/* set the correct new source and destionation mac addresses */ | |
/* can be found in fib_params.dmac and fib_params.smac */ | |
__builtin_memcpy(eth->h_dest, fib_params.dmac, ETH_ALEN); | |
__builtin_memcpy(eth->h_source, fib_params.smac, ETH_ALEN); | |
/* and done, now we set the action to bpf_redirect_map with fib_params.ifindex which is the egress port as paramater */ | |
//int rrc = bpf_redirect(fib_params.ifindex, 0); | |
//const char debug_str3[] = "Redirect to link %d returned %d"; | |
//bpf_trace_printk(debug_str3, sizeof(debug_str3), fib_params.ifindex, rrc); | |
return XDP_TX; | |
break; | |
case BPF_FIB_LKUP_RET_BLACKHOLE: /* dest is blackholed; can be dropped */ | |
case BPF_FIB_LKUP_RET_UNREACHABLE: /* dest is unreachable; can be dropped */ | |
case BPF_FIB_LKUP_RET_PROHIBIT: /* dest not allowed; can be dropped */ | |
return XDP_DROP; | |
case BPF_FIB_LKUP_RET_NOT_FWDED: /* packet is not forwarded */ | |
case BPF_FIB_LKUP_RET_FWD_DISABLED: /* fwding is not enabled on ingress */ | |
case BPF_FIB_LKUP_RET_UNSUPP_LWT: /* fwd requires encapsulation */ | |
case BPF_FIB_LKUP_RET_NO_NEIGH: /* no neighbor entry for nh */ | |
case BPF_FIB_LKUP_RET_FRAG_NEEDED: /* fragmentation required to fwd */ | |
/* PASS */ | |
break; | |
} | |
} | |
return XDP_PASS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment