Skip to content

Instantly share code, notes, and snippets.

@astoycos
Last active February 18, 2024 02:09
Show Gist options
  • Save astoycos/4e7a7de8520f8c1f274ec101fb96b76a to your computer and use it in GitHub Desktop.
Save astoycos/4e7a7de8520f8c1f274ec101fb96b76a to your computer and use it in GitHub Desktop.
XDP_REDIRECT_EX
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