Skip to content

Commit

Permalink
Remove CFG_RX_GUE configuration option
Browse files Browse the repository at this point in the history
It's always set and I can't think of a good reason for it not to be
set. If you don't want to decap packets on an interface then don't
attach the decap program to that interface.

Signed-off-by: toby cabot <[email protected]>
  • Loading branch information
caboteria committed Dec 7, 2023
1 parent 00e2607 commit ad8009a
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 141 deletions.
2 changes: 1 addition & 1 deletion headers/struct_tc.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ make_service(struct service *ref,
////////////////////////////////
// Configuration

#define CFG_RX_GUE 1 /* check TABLE_DECAP to match and decapsulate decapsulate GUE */
#define CFG_RX_GUE 1 /* unimplemented */
#define CFG_RX_DNAT 2 /* unimplemented */
#define CFG_RX_FWD 4 /* Forward packet after FIB lookup */
#define CFG_RX_DUMP 8 /* Dump intercepted packet */
Expand Down
1 change: 0 additions & 1 deletion src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,6 @@ Example for reading Ingress and Egress configuration:

###### Ingress flags
```
#define CFG_RX_GUE 1 /* check TABLE_DECAP to match and decapsulate decapsulate GUE */
#define CFG_RX_DUMP 8 /* DUMP intercepted packet */
```
###### Egress flags
Expand Down
273 changes: 135 additions & 138 deletions src/bpf/pfc_decap_tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,176 +78,173 @@ int pfc_decap(struct __sk_buff *skb)

// start processing

// check packet for DECAP
if (cfg->flags & CFG_RX_GUE) {
int ret = 0;
struct endpoint src_ep = { 0 };
// get source EP
parse_src_ep(&src_ep, &hdr);
// Is this a GUE packet? There are two ways that we can
// tell. First, if there's an entry in map_decap for the
// source IP and port then it's probably a GUE packet. If that
// lookup fails then we check the dest port, i.e., is the
// packet being sent to port 6080? If it is then it's probably
// a GUE packet. In both cases we verify the packet to make
// sure that it's legit.
if (!bpf_map_lookup_elem(&map_decap, &src_ep)) {
debug_print(debug, "decap map lookup failed\n");
struct endpoint dest_ep = { 0 };
parse_dest_ep(&dest_ep, &hdr);

// We already failed the decap map lookup so if the port
// check fails, too, then it's definitely not a GUE packet
// and we don't want to try to decap it.
ASSERT1(bpf_ntohs(dest_ep.port) == 6080, debug_action(TC_ACT_UNSPEC, debug), debug_print(debug, "Decap map lookup failed and dest port not 6080: %u\n", bpf_ntohs(dest_ep.port)));
debug_print(debug, "Packet probably GUE based on dest port\n");
}

// The packet is probably GUE but we need to verify.
int ret = 0;
struct endpoint src_ep = { 0 };
// get source EP
parse_src_ep(&src_ep, &hdr);
// Is this a GUE packet? There are two ways that we can
// tell. First, if there's an entry in map_decap for the
// source IP and port then it's probably a GUE packet. If that
// lookup fails then we check the dest port, i.e., is the
// packet being sent to port 6080? If it is then it's probably
// a GUE packet. In both cases we verify the packet to make
// sure that it's legit.
if (!bpf_map_lookup_elem(&map_decap, &src_ep)) {
debug_print(debug, "decap map lookup failed\n");
struct endpoint dest_ep = { 0 };
parse_dest_ep(&dest_ep, &hdr);

// We already failed the decap map lookup so if the port
// check fails, too, then it's definitely not a GUE packet
// and we don't want to try to decap it.
ASSERT1(bpf_ntohs(dest_ep.port) == 6080, debug_action(TC_ACT_UNSPEC, debug), debug_print(debug, "Decap map lookup failed and dest port not 6080: %u\n", bpf_ntohs(dest_ep.port)));
debug_print(debug, "Packet probably GUE based on dest port\n");
}

void *data_end = (void *)(long)skb->data_end;
// control or data
debug_print(debug, " gueh: %u\n", hdr.gueh);
debug_print(debug, " &gueh[1]: %u\n", (void*)&hdr.gueh[1]);
// The packet is probably GUE but we need to verify.

// This check is redundant with the one in parse_headers()
// but the verifier fails if I don't have it here, also.
if ((void *)(long)hdr.gueh + sizeof(struct guehdr) > (void *)(long)data_end) {
bpf_print("ERROR: (GUE) Invalid packet size\n");
return debug_action(TC_ACT_SHOT, debug);
}
void *data_end = (void *)(long)skb->data_end;
// control or data
debug_print(debug, " gueh: %u\n", hdr.gueh);
debug_print(debug, " &gueh[1]: %u\n", (void*)&hdr.gueh[1]);

ASSERT1(hdr.gueh->version == 0, debug_action(TC_ACT_SHOT, debug), bpf_print("ERROR: Unsupported GUE version %u\n", hdr.gueh->version));
// This check is redundant with the one in parse_headers()
// but the verifier fails if I don't have it here, also.
if ((void *)(long)hdr.gueh + sizeof(struct guehdr) > (void *)(long)data_end) {
bpf_print("ERROR: (GUE) Invalid packet size\n");
return debug_action(TC_ACT_SHOT, debug);
}

if (hdr.gueh->control) {
if (hdr.gueh->hlen == 6) {
debug_print(debug, "GUE Control: IDs + KEY\n");
struct guepinghdr *gueext = (struct guepinghdr *)&hdr.gueh[1];
ASSERT1((void*)&gueext[1] <= data_end, debug_action(TC_ACT_SHOT, debug), bpf_print("ERROR: (GUEext) Invalid packet size\n"));
ASSERT1(hdr.gueh->version == 0, debug_action(TC_ACT_SHOT, debug), bpf_print("ERROR: Unsupported GUE version %u\n", hdr.gueh->version));

ASSERT1(service_verify(&gueext->ext) == 0, debug_action(TC_ACT_SHOT, debug), bpf_print("ERROR: (GUEext) Service verify failure\n"));
if (hdr.gueh->control) {
if (hdr.gueh->hlen == 6) {
debug_print(debug, "GUE Control: IDs + KEY\n");
struct guepinghdr *gueext = (struct guepinghdr *)&hdr.gueh[1];
ASSERT1((void*)&gueext[1] <= data_end, debug_action(TC_ACT_SHOT, debug), bpf_print("ERROR: (GUEext) Invalid packet size\n"));

return debug_action(update_tunnel_from_guec(bpf_ntohl(gueext->tunnelid), &hdr), debug);
} else {
ASSERT(0, debug_action(TC_ACT_SHOT, debug), "ERROR: Unexpected GUE control HLEN %u\n", hdr.gueh->hlen);
}
ASSERT1(service_verify(&gueext->ext) == 0, debug_action(TC_ACT_SHOT, debug), bpf_print("ERROR: (GUEext) Service verify failure\n"));

return debug_action(TC_ACT_SHOT, debug);
return debug_action(update_tunnel_from_guec(bpf_ntohl(gueext->tunnelid), &hdr), debug);
} else {
debug_print(debug, "GUE Data: Decap\n");
ASSERT(0, debug_action(TC_ACT_SHOT, debug), "ERROR: Unexpected GUE control HLEN %u\n", hdr.gueh->hlen);
}

return debug_action(TC_ACT_SHOT, debug);
} else {
debug_print(debug, "GUE Data: Decap\n");

ASSERT(hdr.gueh->hlen != 0, debug_action(TC_ACT_UNSPEC, debug), "Linux GUE (no ext fields)\n"); // FIXME: remove when linux infra not used anymore
ASSERT(hdr.gueh->hlen == 5, debug_action(TC_ACT_SHOT, debug), "Unexpected GUE data HLEN %u\n", hdr.gueh->hlen);
ASSERT(hdr.gueh->hlen != 0, debug_action(TC_ACT_UNSPEC, debug), "Linux GUE (no ext fields)\n"); // FIXME: remove when linux infra not used anymore
ASSERT(hdr.gueh->hlen == 5, debug_action(TC_ACT_SHOT, debug), "Unexpected GUE data HLEN %u\n", hdr.gueh->hlen);

struct gueexthdr *gueext = (struct gueexthdr *)&hdr.gueh[1];
if ((void*)&gueext[1] > data_end) {
bpf_print("ERROR: (GUEext) Invalid packet size\n");
struct gueexthdr *gueext = (struct gueexthdr *)&hdr.gueh[1];
if ((void*)&gueext[1] > data_end) {
bpf_print("ERROR: (GUEext) Invalid packet size\n");
return debug_action(TC_ACT_SHOT, debug);
}

// check service identity
ASSERT1(service_verify(gueext) == 0, debug_action(TC_ACT_SHOT, debug), bpf_print("service_verify failed"));

// get verify structure
struct verify *verify = bpf_map_lookup_elem(&map_verify, (struct identity *)&gueext->gidsid);
ASSERT(verify != 0, debug_action(TC_ACT_UNSPEC, debug), "ERROR: Service id %u not found!\n", bpf_ntohl(gueext->gidsid));

struct service svc = {{ 0 }, {{ 0 }, 0, {{ 0 }, 0 }}, 0 };
__builtin_memcpy(&svc.key, verify, sizeof(*verify));
svc.identity = *(struct identity *)&gueext->gidsid;
svc.hash = pktnum;

// Decap the packet
ASSERT(TC_ACT_OK == gue_decap_v4(skb), debug_action(TC_ACT_SHOT, debug), "GUE Decap Failed!\n");

// Pull (i.e. "linearize") the packet if needed. We
// did this above with the encapsulated packet, but
// when we decap the packet we evidently get a new skb
// that might not have enough linear bytes to parse
// the header so we need to do this again.
pull_amount = (skb->len > TOTAL_EP_HEADER_SIZE) ? TOTAL_EP_HEADER_SIZE : skb->len;
if ((void *)(long)skb->data + pull_amount > (void *)(long)skb->data_end) {
if (debug) {
bpf_print("*** AFTER DECAP Pulling packet headers\n");
bpf_print(" skb len: %u\n", skb->len);
bpf_print(" pull amount: %u\n", pull_amount);
bpf_print(" data: %u\n", skb->data);
bpf_print(" data_end: %u\n", skb->data_end);
}
if (bpf_skb_pull_data(skb, pull_amount) < 0) {
bpf_print("failure to pull data\n");
return debug_action(TC_ACT_SHOT, debug);
}
}

// check service identity
ASSERT1(service_verify(gueext) == 0, debug_action(TC_ACT_SHOT, debug), bpf_print("service_verify failed"));

// get verify structure
struct verify *verify = bpf_map_lookup_elem(&map_verify, (struct identity *)&gueext->gidsid);
ASSERT(verify != 0, debug_action(TC_ACT_UNSPEC, debug), "ERROR: Service id %u not found!\n", bpf_ntohl(gueext->gidsid));
if (verify->encap.ifindex) { // EPIC
if (cfg->flags & CFG_RX_FWD) {
__u32 ifindex = bpf_ntohl(verify->encap.ifindex);

struct service svc = {{ 0 }, {{ 0 }, 0, {{ 0 }, 0 }}, 0 };
__builtin_memcpy(&svc.key, verify, sizeof(*verify));
svc.identity = *(struct identity *)&gueext->gidsid;
svc.hash = pktnum;
// Lookup dest mac struct from TABLE-PROXY
struct mac *mac_remote = bpf_map_lookup_elem(&map_proxy, &ifindex);
ASSERT(mac_remote != 0, debug_action(TC_ACT_UNSPEC, debug), "ERROR: Proxy MAC for ifindex %u not found!\n", ifindex);

// Decap the packet
ASSERT(TC_ACT_OK == gue_decap_v4(skb), debug_action(TC_ACT_SHOT, debug), "GUE Decap Failed!\n");
debug_print(debug, "Set D-MAC: ifindex %u -> MAC %x\n", ifindex, bpf_ntohl(*(__u32*)&(mac_remote->value[2])));
ret = bpf_skb_store_bytes(skb, 0, mac_remote->value, 6, BPF_F_INVALIDATE_HASH);
if (ret < 0) {
bpf_print("bpf_skb_store_bytes: %d\n", ret);
}

// Pull (i.e. "linearize") the packet if needed. We
// did this above with the encapsulated packet, but
// when we decap the packet we evidently get a new skb
// that might not have enough linear bytes to parse
// the header so we need to do this again.
pull_amount = (skb->len > TOTAL_EP_HEADER_SIZE) ? TOTAL_EP_HEADER_SIZE : skb->len;
if ((void *)(long)skb->data + pull_amount > (void *)(long)skb->data_end) {
if (debug) {
bpf_print("*** AFTER DECAP Pulling packet headers\n");
bpf_print(" skb len: %u\n", skb->len);
bpf_print(" pull amount: %u\n", pull_amount);
bpf_print(" data: %u\n", skb->data);
bpf_print(" data_end: %u\n", skb->data_end);
}
if (bpf_skb_pull_data(skb, pull_amount) < 0) {
bpf_print("failure to pull data\n");
return debug_action(TC_ACT_SHOT, debug);
dump_pkt(skb);
bpf_print("Redirecting to container ifindex %u TX\n", ifindex);
}
}

if (verify->encap.ifindex) { // EPIC
if (cfg->flags & CFG_RX_FWD) {
__u32 ifindex = bpf_ntohl(verify->encap.ifindex);
return debug_action(bpf_redirect(ifindex, 0), debug);
}

// Lookup dest mac struct from TABLE-PROXY
struct mac *mac_remote = bpf_map_lookup_elem(&map_proxy, &ifindex);
ASSERT(mac_remote != 0, debug_action(TC_ACT_UNSPEC, debug), "ERROR: Proxy MAC for ifindex %u not found!\n", ifindex);
if (debug) {
dump_pkt(skb);
}
} else { // PureLB
struct encap_key skey = { { 0 } , 0 };
struct endpoint dep = { 0 };
ASSERT(parse_ep(skb, &skey.ep, &dep) != TC_ACT_SHOT, debug_action(TC_ACT_UNSPEC, debug), "ERROR: SRC EP parsing failed!\n");

// update TABLE-ENCAP
debug_print(debug, "updating encap table key: %x:%x:%x", skey.ep.ip, skey.ep.port, skey.ep.proto);
debug_print(debug, "updating encap table val: %u:%u:%u", bpf_ntohs(svc.identity.service_id), bpf_ntohs(svc.identity.group_id), bpf_ntohl(svc.key.tunnel_id));
ASSERT(bpf_map_update_elem(&map_encap, &skey, &svc, BPF_ANY) == 0, debug_action(TC_ACT_UNSPEC, debug), "ERROR: map_encap update failed\n");

if (cfg->flags & CFG_RX_FWD) {
// flags: 0, BPF_FIB_LOOKUP_DIRECT 1, BPF_FIB_LOOKUP_OUTPUT 2
struct bpf_fib_lookup fib_params = { 0 };
ret = fib_lookup(skb, &fib_params, skb->ifindex, 0);
if (ret == TC_ACT_OK) {
// Update destination MAC
ret = bpf_skb_store_bytes(skb, 0, &fib_params.dmac, 6, BPF_F_INVALIDATE_HASH);
if (ret < 0) {
bpf_print("bpf_skb_store_bytes(D-MAC): %d\n", ret);
}

debug_print(debug, "Set D-MAC: ifindex %u -> MAC %x\n", ifindex, bpf_ntohl(*(__u32*)&(mac_remote->value[2])));
ret = bpf_skb_store_bytes(skb, 0, mac_remote->value, 6, BPF_F_INVALIDATE_HASH);
// Update source MAC
ret = bpf_skb_store_bytes(skb, 6, &fib_params.smac, 6, BPF_F_INVALIDATE_HASH);
if (ret < 0) {
bpf_print("bpf_skb_store_bytes: %d\n", ret);
bpf_print("bpf_skb_store_bytes(S-MAC): %d\n", ret);
}

if (debug) {
dump_pkt(skb);
bpf_print("Redirecting to container ifindex %u TX\n", ifindex);
}

return debug_action(bpf_redirect(ifindex, 0), debug);
}

if (debug) {
dump_pkt(skb);
}
} else { // PureLB
struct encap_key skey = { { 0 } , 0 };
struct endpoint dep = { 0 };
ASSERT(parse_ep(skb, &skey.ep, &dep) != TC_ACT_SHOT, debug_action(TC_ACT_UNSPEC, debug), "ERROR: SRC EP parsing failed!\n");

// update TABLE-ENCAP
debug_print(debug, "updating encap table key: %x:%x:%x", skey.ep.ip, skey.ep.port, skey.ep.proto);
debug_print(debug, "updating encap table val: %u:%u:%u", bpf_ntohs(svc.identity.service_id), bpf_ntohs(svc.identity.group_id), bpf_ntohl(svc.key.tunnel_id));
ASSERT(bpf_map_update_elem(&map_encap, &skey, &svc, BPF_ANY) == 0, debug_action(TC_ACT_UNSPEC, debug), "ERROR: map_encap update failed\n");

if (cfg->flags & CFG_RX_FWD) {
// flags: 0, BPF_FIB_LOOKUP_DIRECT 1, BPF_FIB_LOOKUP_OUTPUT 2
struct bpf_fib_lookup fib_params = { 0 };
ret = fib_lookup(skb, &fib_params, skb->ifindex, 0);
if (ret == TC_ACT_OK) {
// Update destination MAC
ret = bpf_skb_store_bytes(skb, 0, &fib_params.dmac, 6, BPF_F_INVALIDATE_HASH);
if (ret < 0) {
bpf_print("bpf_skb_store_bytes(D-MAC): %d\n", ret);
}

// Update source MAC
ret = bpf_skb_store_bytes(skb, 6, &fib_params.smac, 6, BPF_F_INVALIDATE_HASH);
if (ret < 0) {
bpf_print("bpf_skb_store_bytes(S-MAC): %d\n", ret);
}

if (debug) {
dump_pkt(skb);
bpf_print("Redirecting to interface ifindex %u TX\n", fib_params.ifindex);
}

return debug_action(bpf_redirect(fib_params.ifindex, 0), debug);
bpf_print("Redirecting to interface ifindex %u TX\n", fib_params.ifindex);
}
}

if (debug) {
dump_pkt(skb);
return debug_action(bpf_redirect(fib_params.ifindex, 0), debug);
}
}

return debug_action(TC_ACT_UNSPEC, debug);
if (debug) {
dump_pkt(skb);
}
}

return debug_action(TC_ACT_UNSPEC, debug);
}

return debug_action(TC_ACT_UNSPEC, debug);
Expand Down
1 change: 0 additions & 1 deletion src/cli/cli_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ void print_decap(__u8 direction, unsigned int key, struct config *value) {
printf("CFG %-16s %-5u %s Decap %-16s %s%s%s%s\n",
if_indextoname(key, ifname), key,
(direction == CFG_IDX_RX) ? "Ingress" : "Egress ", value->name,
(value->flags & CFG_RX_GUE) ? " GUE-DECAP(1)" : "",
(value->flags & CFG_RX_FWD) ? " FWD(4)" : "",
(value->flags & CFG_RX_DUMP) ? " DUMP(8)" : "");
}
Expand Down

0 comments on commit ad8009a

Please sign in to comment.