From 4b1e0f8bcfcbe4027ad4ce53b4a806d19f8c7aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 7 Apr 2022 16:53:02 -0700 Subject: [PATCH] clatd bpf - add try_make_readable() of the ethernet/ip header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now rely on the skb->mark = 0xDeadC1a7 setting side effect for non offloadable packets, but for this to work reliably, we *must* be able to read the ip header. Test: TreeHugger, and on a gs101-based pixel Signed-off-by: Maciej Żenczykowski Change-Id: Ic2b15335099404047d136a92ce7aeeb1f11ccfa3 --- bpf_progs/clatd.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c index 55165b1036..8971f6b538 100644 --- a/bpf_progs/clatd.c +++ b/bpf_progs/clatd.c @@ -46,18 +46,24 @@ DEFINE_BPF_MAP_GRW(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 16, AID_SYSTEM) static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet) { - const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0; - void* data = (void*)(long)skb->data; - const void* data_end = (void*)(long)skb->data_end; - const struct ethhdr* const eth = is_ethernet ? data : NULL; // used iff is_ethernet - const struct ipv6hdr* const ip6 = is_ethernet ? (void*)(eth + 1) : data; - // Require ethernet dst mac address to be our unicast address. if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE; // Must be meta-ethernet IPv6 frame if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_PIPE; + const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0; + + // Not clear if this is actually necessary considering we use DPA (Direct Packet Access), + // but we need to make sure we can read the IPv6 header reliably so that we can set + // skb->mark = 0xDeadC1a7 for packets we fail to offload. + try_make_readable(skb, l2_header_size + sizeof(struct ipv6hdr)); + + void* data = (void*)(long)skb->data; + const void* data_end = (void*)(long)skb->data_end; + const struct ethhdr* const eth = is_ethernet ? data : NULL; // used iff is_ethernet + const struct ipv6hdr* const ip6 = is_ethernet ? (void*)(eth + 1) : data; + // Must have (ethernet and) ipv6 header if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_PIPE; @@ -214,13 +220,16 @@ DEFINE_BPF_PROG("schedcls/egress4/clat_ether", AID_ROOT, AID_SYSTEM, sched_cls_e DEFINE_BPF_PROG("schedcls/egress4/clat_rawip", AID_ROOT, AID_SYSTEM, sched_cls_egress4_clat_rawip) (struct __sk_buff* skb) { + // Must be meta-ethernet IPv4 frame + if (skb->protocol != htons(ETH_P_IP)) return TC_ACT_PIPE; + + // Possibly not needed, but for consistency with nat64 up above + try_make_readable(skb, sizeof(struct iphdr)); + void* data = (void*)(long)skb->data; const void* data_end = (void*)(long)skb->data_end; const struct iphdr* const ip4 = data; - // Must be meta-ethernet IPv4 frame - if (skb->protocol != htons(ETH_P_IP)) return TC_ACT_PIPE; - // Must have ipv4 header if (data + sizeof(*ip4) > data_end) return TC_ACT_PIPE;