From nobody Mon Jun 8 04:12:09 2026 Received: from out-174.mta1.migadu.com (out-174.mta1.migadu.com [95.215.58.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8E7B3EB810 for ; Tue, 2 Jun 2026 15:10:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780413011; cv=none; b=YYPo2pGi+AZ+s5KJI3RNjsQBc5orz4VQjqQozvrjBJSPbwAew4kGp2mq03UXLf2RddCMyYIzLbKyIiBXgDXNlu6lTuD5nlX/C3qtdsOHZvx2ESIYDbnlxA06wYXquXwu5gKm+cbrjX6merKM/QcldZQrJysJ72peszPlhTZag1w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780413011; c=relaxed/simple; bh=DXp2X70flAXfG/kzP8CdrTOeSuh4Viz320NCs6owwFI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EZDSO1JktWQ6vO5vmm1wRDvdCf1tCemWgwsHbTNzljjt9TkvdtEX5Wy4eeK7yfvCJOzlSA37eRJ8HRqtmTGBvQBTWhRXMJd7S2I9KydFfOCyoWWcfn7bzyLQI6e5pLbU11Ld3qgb5cZR+BITSQuyxgy89bIHwx38Hhep8qbyXu4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=p+INKBX0; arc=none smtp.client-ip=95.215.58.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="p+INKBX0" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1780413008; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=t6+rTtBYw3wQtorJ+PDFHLzmGteg47Xmh+985+kjaOo=; b=p+INKBX0/O7gwKDM+gqG7sz2bBKHwqacmIXloXhTr1PqC1uMcZIuQeUuTKAoAR6j7j519N CMzYtZV/JFYUBAbx9Y6VlVAYlcVqyIZHhNK4njhHJcjfR8uNIAG3w1TzIN8JYxs2yZrBYZ cHxJwBTLgCOi06TeBFLi7+p/OQu0/98= From: Leon Hwang To: bpf@vger.kernel.org Cc: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrii Nakryiko , Eduard Zingerman , Alexei Starovoitov , Daniel Borkmann , Martin KaFai Lau , Kumar Kartikeya Dwivedi , Song Liu , Yonghong Song , Jiri Olsa , Shuah Khan , Guillaume Nault , Leon Hwang , Ido Schimmel , Fernando Fernandez Mancera , Peter Oskolkov , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-patches-bot@fb.com, Leon Hwang Subject: [PATCH bpf v4 1/2] bpf: Update transport_header when encapsulating UDP tunnel in lwt Date: Tue, 2 Jun 2026 23:09:30 +0800 Message-ID: <20260602150931.49629-2-leon.hwang@linux.dev> In-Reply-To: <20260602150931.49629-1-leon.hwang@linux.dev> References: <20260602150931.49629-1-leon.hwang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" Currently, bpf_lwt_push_ip_encap() does not update skb->transport_header. When a driver, e.g. ice, reuses the stale skb->transport_header to offload checksum computation to NIC hardware, VxLAN packets encapsulated by bpf_lwt_push_encap() helper may be dropped due to incorrect checksum. Update skb->transport_header in bpf_lwt_push_ip_encap() whenever the encapsulated packet uses UDP, so checksum offload works correctly. Fixes: 52f278774e79 ("bpf: implement BPF_LWT_ENCAP_IP mode in bpf_lwt_push_= encap") Cc: Leon Hwang Signed-off-by: Leon Hwang --- net/core/lwt_bpf.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c index f71ef82a5f3d..bf588f508b79 100644 --- a/net/core/lwt_bpf.c +++ b/net/core/lwt_bpf.c @@ -599,6 +599,7 @@ static int handle_gso_encap(struct sk_buff *skb, bool i= pv4, int encap_len) =20 int bpf_lwt_push_ip_encap(struct sk_buff *skb, void *hdr, u32 len, bool in= gress) { + bool is_udp_tunnel; struct iphdr *iph; bool ipv4; int err; @@ -612,10 +613,16 @@ int bpf_lwt_push_ip_encap(struct sk_buff *skb, void *= hdr, u32 len, bool ingress) ipv4 =3D true; if (unlikely(len < iph->ihl * 4)) return -EINVAL; + is_udp_tunnel =3D iph->protocol =3D=3D IPPROTO_UDP; + if (unlikely(is_udp_tunnel && len < iph->ihl * 4 + sizeof(struct udphdr)= )) + return -EINVAL; } else if (iph->version =3D=3D 6) { ipv4 =3D false; if (unlikely(len < sizeof(struct ipv6hdr))) return -EINVAL; + is_udp_tunnel =3D ((struct ipv6hdr *)iph)->nexthdr =3D=3D NEXTHDR_UDP; + if (unlikely(is_udp_tunnel && len < sizeof(struct ipv6hdr) + sizeof(stru= ct udphdr))) + return -EINVAL; } else { return -EINVAL; } @@ -637,6 +644,11 @@ int bpf_lwt_push_ip_encap(struct sk_buff *skb, void *h= dr, u32 len, bool ingress) if (ingress) skb_postpush_rcsum(skb, iph, len); skb_reset_network_header(skb); + if (is_udp_tunnel) { + size_t iph_sz =3D ipv4 ? iph->ihl * 4 : sizeof(struct ipv6hdr); + + skb_set_transport_header(skb, skb_network_offset(skb) + iph_sz); + } memcpy(skb_network_header(skb), hdr, len); bpf_compute_data_pointers(skb); skb_clear_hash(skb); --=20 2.54.0 From nobody Mon Jun 8 04:12:09 2026 Received: from out-186.mta1.migadu.com (out-186.mta1.migadu.com [95.215.58.186]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9EB553ED12B for ; Tue, 2 Jun 2026 15:10:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.186 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780413020; cv=none; b=e3uLVrQBFIipG19vW5ASjT8Rl7pJJJuEgsVpe4RdM0r3D+1h6cc6j9lcq3WhdyMI99tMup1L2YxOYvnVKKe/0gI/cZGjr+gcIdFYq3cyhYqk8QeqkyGZKG98QvSkRhp9ueknNORYJ7j9Xy7wsVyCR4OIhz9tcC8ytCWKmzOsHx0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780413020; c=relaxed/simple; bh=aNiYV6eks9AWxansqt7a9QeRU2sU+D70Y0WnA0lziDo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WhXdZ2c25WZWWi1+1xs8Em18vyIpklR+/LeiOU/3XlkRt7vjtQCldnfUPBbCuSaXWpcbRikBwjY0ve0o0GUwbIFh10MNJ3EzcgPV6Fmko+pDigzpNjcoIbCL2K9+Q646miu811/4ro7qjKnrvOoDo3UQXLLGLjYGkAD8Aq6cpNI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=jdT7PDDu; arc=none smtp.client-ip=95.215.58.186 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="jdT7PDDu" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1780413016; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7aJ8UsRt56L+UYhTOTDwNHFuUJw1GXfsMzTmYDtBGsY=; b=jdT7PDDuoUBBQo9vX8UK2mlR1YlfyHkCkQhFNYNlUGZdj34nr6omYD6XEFaIAK/vlB6BTz PgRUACgK7aud4KT0vuQLD27IY4pnwlc3tjudNIQskuVSZ8bJMZcJ0Z5Jaa3gHVyX9uMdaR 95cPZ+P7W9aIUmfzH5YL2btFrv+XyPc= From: Leon Hwang To: bpf@vger.kernel.org Cc: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrii Nakryiko , Eduard Zingerman , Alexei Starovoitov , Daniel Borkmann , Martin KaFai Lau , Kumar Kartikeya Dwivedi , Song Liu , Yonghong Song , Jiri Olsa , Shuah Khan , Guillaume Nault , Leon Hwang , Ido Schimmel , Fernando Fernandez Mancera , Peter Oskolkov , linux-kernel@vger.kernel.org, netdev@vger.kernel.org, linux-kselftest@vger.kernel.org, kernel-patches-bot@fb.com, Leon Hwang Subject: [PATCH bpf v4 2/2] selftests/bpf: Add tests to verify the fix of encapsulating VxLAN in lwt Date: Tue, 2 Jun 2026 23:09:31 +0800 Message-ID: <20260602150931.49629-3-leon.hwang@linux.dev> In-Reply-To: <20260602150931.49629-1-leon.hwang@linux.dev> References: <20260602150931.49629-1-leon.hwang@linux.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" Add two tests to verify the transport header of skb has been set when encapsulate VxLAN using bpf_lwt_push_encap() helper. 1. VxLAN over IPv4. 2. VxLAN over IPv6. Without the fix, the tests would fail: lwt_ip_encap_vxlan:FAIL:transport_hdr offset unexpected transport_hdr offs= et: actual 70 !=3D expected 20 #208 lwt_ip_encap_vxlan_ipv4:FAIL lwt_ip_encap_vxlan:FAIL:transport_hdr offset unexpected transport_hdr offs= et: actual 110 !=3D expected 40 #209 lwt_ip_encap_vxlan_ipv6:FAIL The unexpected offsets are: outer encap headers (IPv4: iphdr+udp+vxlan+eth =3D 50 bytes, IPv6: ipv6hdr+udp+vxlan+eth =3D 70= bytes) plus the inner IP header (20 or 40 bytes), because without the fix transport_header still points at the inner transport layer instead of the outer UDP header. Assisted-by: Claude:claude-sonnet-4-6 Cc: Leon Hwang Signed-off-by: Leon Hwang --- .../selftests/bpf/prog_tests/lwt_ip_encap.c | 145 ++++++++++++++++ .../selftests/bpf/progs/test_lwt_ip_encap.c | 155 ++++++++++++++++-- 2 files changed, 290 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/lwt_ip_encap.c b/tools/= testing/selftests/bpf/prog_tests/lwt_ip_encap.c index b6391af5f6f9..6606f0ed9a9a 100644 --- a/tools/testing/selftests/bpf/prog_tests/lwt_ip_encap.c +++ b/tools/testing/selftests/bpf/prog_tests/lwt_ip_encap.c @@ -3,6 +3,7 @@ =20 #include "network_helpers.h" #include "test_progs.h" +#include "test_lwt_ip_encap.skel.h" =20 #define BPF_FILE "test_lwt_ip_encap.bpf.o" =20 @@ -32,6 +33,9 @@ #define IP6_ADDR_8 "fb08::1" #define IP6_ADDR_GRE "fb10::1" =20 +#define IP4_ADDR_VXLAN "172.16.17.100" +#define IP6_ADDR_VXLAN "fb11::1" + #define IP6_ADDR_SRC IP6_ADDR_1 #define IP6_ADDR_DST IP6_ADDR_4 =20 @@ -538,3 +542,144 @@ void test_lwt_ip_encap_ipv4(void) if (test__start_subtest("ingress")) lwt_ip_encap(IPV4_ENCAP, INGRESS, ""); } + +/* + * VxLAN Setup/topology: + * + * NS1 (IP*_ADDR_1) NS2 NS3 (IP*_ADDR_4) + * [ping src] + * | top route + * veth1 (LWT encap) <<-- veth2 veth3 <<-- veth4 (ping ds= t) + * | ^ + * (bottom route) | (inner pkt) + * v bottom route | + * veth5 -->> veth6 veth7 -->> veth8 (vxlan d= ecap) + * (IP*_ADDR_VXLA= N) + * + * Add the VxLAN endpoint addresses to NS3's veth8, create standard + * VxLAN decap devices bound to those addresses, and install routes so + * NS1/NS2 can reach the endpoints via the bottom route. NS2 here is to + * make sure the LWT-encap VxLAN packets are routed to NS3 correctly. + */ +static int setup_vxlan_routes(const char *ns3, const char *ns1, const char= *ns2) +{ + struct nstoken *nstoken; + + nstoken =3D open_netns(ns3); + if (!ASSERT_OK_PTR(nstoken, "open ns3 for vxlan")) + return -1; + + SYS(fail_close, "ip a add %s/32 dev veth8", IP4_ADDR_VXLAN); + SYS(fail_close, "ip -6 a add %s/128 dev veth8", IP6_ADDR_VXLAN); + /* + * Standard VxLAN devices to decap the encapsulated packets. The inner + * Ethernet frame uses a broadcast dst MAC so the IP stack accepts it + * without ARP or FDB configuration. + */ + SYS(fail_close, "ip link add vxlan4 type vxlan id 1 dstport 4789 local %s= dev veth8 nolearning noudpcsum", + IP4_ADDR_VXLAN); + SYS(fail_close, "ip link set vxlan4 up"); + SYS(fail_close, "ip link add vxlan6 type vxlan id 1 dstport 4789 local %s= dev veth8 nolearning udp6zerocsumrx", + IP6_ADDR_VXLAN); + SYS(fail_close, "ip link set vxlan6 up"); + close_netns(nstoken); + + SYS(fail, "ip -n %s route add %s/32 dev veth5 via %s", + ns1, IP4_ADDR_VXLAN, IP4_ADDR_6); + SYS(fail, "ip -n %s route add %s/32 dev veth7 via %s", + ns2, IP4_ADDR_VXLAN, IP4_ADDR_8); + SYS(fail, "ip -n %s -6 route add %s/128 dev veth5 via %s", + ns1, IP6_ADDR_VXLAN, IP6_ADDR_6); + SYS(fail, "ip -n %s -6 route add %s/128 dev veth7 via %s", + ns2, IP6_ADDR_VXLAN, IP6_ADDR_8); + return 0; + +fail_close: + close_netns(nstoken); +fail: + return -1; +} + +static void lwt_ip_encap_vxlan(bool ipv4_encap) +{ + char ns1[NETNS_NAME_SIZE] =3D NETNS_BASE "-1-"; + char ns2[NETNS_NAME_SIZE] =3D NETNS_BASE "-2-"; + char ns3[NETNS_NAME_SIZE] =3D NETNS_BASE "-3-"; + const char *sec =3D ipv4_encap ? "encap_vxlan" : "encap_vxlan6"; + int expected_offset =3D ipv4_encap ? (int)sizeof(struct iphdr) + : (int)sizeof(struct ipv6hdr); + struct test_lwt_ip_encap *skel =3D NULL; + int thdr_offset, err; + + if (!ASSERT_OK(create_ns(ns1, NETNS_NAME_SIZE), "create ns1")) + goto out; + if (!ASSERT_OK(create_ns(ns2, NETNS_NAME_SIZE), "create ns2")) + goto out; + if (!ASSERT_OK(create_ns(ns3, NETNS_NAME_SIZE), "create ns3")) + goto out; + + if (!ASSERT_OK(setup_network(ns1, ns2, ns3, ""), "setup network")) + goto out; + + if (!ASSERT_OK(setup_vxlan_routes(ns3, ns1, ns2), "setup vxlan routes")) + goto out; + + skel =3D test_lwt_ip_encap__open(); + if (!ASSERT_OK_PTR(skel, "test_lwt_ip_encap__open")) + goto out; + + bpf_program__set_autoload(skel->progs.bpf_lwt_encap_gre, false); + bpf_program__set_autoload(skel->progs.bpf_lwt_encap_gre6, false); + bpf_program__set_autoload(skel->progs.bpf_lwt_encap_vxlan, false); + bpf_program__set_autoload(skel->progs.bpf_lwt_encap_vxlan6, false); + bpf_program__set_autoload(skel->progs.fexit_lwt_push_ip_encap, true); + skel->rodata->tgt_ip_version =3D ipv4_encap ? 4 : 6; + + err =3D test_lwt_ip_encap__load(skel); + if (!ASSERT_OK(err, "test_lwt_ip_encap__load")) + goto out; + + err =3D test_lwt_ip_encap__attach(skel); + if (!ASSERT_OK(err, "test_lwt_ip_encap__attach")) + goto out; + + /* Remove the direct NS2->DST route so packets must go via LWT encap. */ + SYS(out, "ip -n %s route del %s/32 dev veth3", ns2, IP4_ADDR_DST); + SYS(out, "ip -n %s -6 route del %s/128 dev veth3", ns2, IP6_ADDR_DST); + + if (ipv4_encap) + SYS(out, "ip -n %s route add %s encap bpf xmit obj %s sec %s dev veth1", + ns1, IP4_ADDR_DST, BPF_FILE, sec); + else + SYS(out, "ip -n %s -6 route add %s encap bpf xmit obj %s sec %s dev veth= 1", + ns1, IP6_ADDR_DST, BPF_FILE, sec); + + skel->bss->fexit_triggered =3D false; + + if (ipv4_encap) + SYS(out, "ip netns exec %s ping -c 1 -W1 %s", ns1, IP4_ADDR_DST); + else + SYS(out, "ip netns exec %s ping6 -c 1 -W1 %s", ns1, IP6_ADDR_DST); + + if (!ASSERT_TRUE(skel->bss->fexit_triggered, "fexit_triggered")) + goto out; + + thdr_offset =3D (int)skel->bss->transport_hdr - (int)skel->bss->network_h= dr; + ASSERT_EQ(thdr_offset, expected_offset, "transport_hdr offset"); + +out: + test_lwt_ip_encap__destroy(skel); + SYS_NOFAIL("ip netns del %s", ns1); + SYS_NOFAIL("ip netns del %s", ns2); + SYS_NOFAIL("ip netns del %s", ns3); +} + +void test_lwt_ip_encap_vxlan_ipv4(void) +{ + lwt_ip_encap_vxlan(IPV4_ENCAP); +} + +void test_lwt_ip_encap_vxlan_ipv6(void) +{ + lwt_ip_encap_vxlan(IPV6_ENCAP); +} diff --git a/tools/testing/selftests/bpf/progs/test_lwt_ip_encap.c b/tools/= testing/selftests/bpf/progs/test_lwt_ip_encap.c index d6cb986e7533..4a934fccf8f5 100644 --- a/tools/testing/selftests/bpf/progs/test_lwt_ip_encap.c +++ b/tools/testing/selftests/bpf/progs/test_lwt_ip_encap.c @@ -1,11 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 -#include +#include "vmlinux.h" #include -#include -#include -#include #include #include +#include =20 struct grehdr { __be16 flags; @@ -64,13 +62,13 @@ int bpf_lwt_encap_gre6(struct __sk_buff *skb) hdr.ip6hdr.nexthdr =3D 47; /* IPPROTO_GRE */ hdr.ip6hdr.hop_limit =3D 0x40; /* fb01::1 */ - hdr.ip6hdr.saddr.s6_addr[0] =3D 0xfb; - hdr.ip6hdr.saddr.s6_addr[1] =3D 1; - hdr.ip6hdr.saddr.s6_addr[15] =3D 1; + hdr.ip6hdr.saddr.in6_u.u6_addr8[0] =3D 0xfb; + hdr.ip6hdr.saddr.in6_u.u6_addr8[1] =3D 1; + hdr.ip6hdr.saddr.in6_u.u6_addr8[15] =3D 1; /* fb10::1 */ - hdr.ip6hdr.daddr.s6_addr[0] =3D 0xfb; - hdr.ip6hdr.daddr.s6_addr[1] =3D 0x10; - hdr.ip6hdr.daddr.s6_addr[15] =3D 1; + hdr.ip6hdr.daddr.in6_u.u6_addr8[0] =3D 0xfb; + hdr.ip6hdr.daddr.in6_u.u6_addr8[1] =3D 0x10; + hdr.ip6hdr.daddr.in6_u.u6_addr8[15] =3D 1; =20 hdr.greh.protocol =3D skb->protocol; =20 @@ -82,4 +80,141 @@ int bpf_lwt_encap_gre6(struct __sk_buff *skb) return BPF_LWT_REROUTE; } =20 +#define VXLAN_PORT 4789 +#define VXLAN_FLAGS 0x08000000 +#define VXLAN_VNI 1 + +#define ETH_ALEN 6 /* Octets in one ethernet addr */ +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ + +static const __u8 bcast[ETH_ALEN] =3D { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +static const __u8 srcmac[ETH_ALEN] =3D { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, +}; + +SEC("encap_vxlan") +int bpf_lwt_encap_vxlan(struct __sk_buff *skb) +{ + struct encap_hdr { + struct iphdr iph; + struct udphdr udph; + struct vxlanhdr vxh; + struct ethhdr eth; + } __attribute__((__packed__)) hdr; + int err; + + memset(&hdr, 0, sizeof(hdr)); + + hdr.iph.ihl =3D 5; + hdr.iph.version =3D 4; + hdr.iph.ttl =3D 0x40; + hdr.iph.protocol =3D 17; /* IPPROTO_UDP */ + hdr.iph.tot_len =3D bpf_htons(skb->len + sizeof(hdr)); +#if __BYTE_ORDER__ =3D=3D __ORDER_LITTLE_ENDIAN__ + hdr.iph.saddr =3D 0x640510ac; /* 172.16.5.100 */ + hdr.iph.daddr =3D 0x641110ac; /* 172.16.17.100 */ +#elif __BYTE_ORDER__ =3D=3D __ORDER_BIG_ENDIAN__ + hdr.iph.saddr =3D 0xac100564; /* 172.16.5.100 */ + hdr.iph.daddr =3D 0xac101164; /* 172.16.17.100 */ +#else +#error "Fix your compiler's __BYTE_ORDER__?!" +#endif + + hdr.udph.source =3D bpf_htons(VXLAN_PORT); + hdr.udph.dest =3D bpf_htons(VXLAN_PORT); + hdr.udph.len =3D bpf_htons(skb->len + sizeof(hdr.udph) + sizeof(hdr.vx= h) + + sizeof(hdr.eth)); + + hdr.vxh.vx_flags =3D bpf_htonl(VXLAN_FLAGS); + hdr.vxh.vx_vni =3D bpf_htonl(VXLAN_VNI << 8); + + __builtin_memcpy(hdr.eth.h_dest, bcast, ETH_ALEN); + __builtin_memcpy(hdr.eth.h_source, srcmac, ETH_ALEN); + hdr.eth.h_proto =3D bpf_htons(ETH_P_IP); + + err =3D bpf_lwt_push_encap(skb, BPF_LWT_ENCAP_IP, &hdr, sizeof(hdr)); + if (err) + return BPF_DROP; + + return BPF_LWT_REROUTE; +} + +SEC("encap_vxlan6") +int bpf_lwt_encap_vxlan6(struct __sk_buff *skb) +{ + struct encap_hdr { + struct ipv6hdr ip6hdr; + struct udphdr udph; + struct vxlanhdr vxh; + struct ethhdr eth; + } __attribute__((__packed__)) hdr; + int err; + + memset(&hdr, 0, sizeof(hdr)); + + hdr.ip6hdr.version =3D 6; + hdr.ip6hdr.nexthdr =3D 17; /* IPPROTO_UDP */ + hdr.ip6hdr.hop_limit =3D 0x40; + hdr.ip6hdr.payload_len =3D bpf_htons(skb->len + sizeof(hdr.udph) + sizeof= (hdr.vxh) + + sizeof(hdr.eth)); + /* fb05::1 */ + hdr.ip6hdr.saddr.in6_u.u6_addr8[0] =3D 0xfb; + hdr.ip6hdr.saddr.in6_u.u6_addr8[1] =3D 0x05; + hdr.ip6hdr.saddr.in6_u.u6_addr8[15] =3D 1; + /* fb11::1 */ + hdr.ip6hdr.daddr.in6_u.u6_addr8[0] =3D 0xfb; + hdr.ip6hdr.daddr.in6_u.u6_addr8[1] =3D 0x11; + hdr.ip6hdr.daddr.in6_u.u6_addr8[15] =3D 1; + + hdr.udph.source =3D bpf_htons(VXLAN_PORT); + hdr.udph.dest =3D bpf_htons(VXLAN_PORT); + hdr.udph.len =3D bpf_htons(skb->len + sizeof(hdr.udph) + sizeof(hdr.vx= h) + + sizeof(hdr.eth)); + + hdr.vxh.vx_flags =3D bpf_htonl(VXLAN_FLAGS); + hdr.vxh.vx_vni =3D bpf_htonl(VXLAN_VNI << 8); + + __builtin_memcpy(hdr.eth.h_dest, bcast, ETH_ALEN); + __builtin_memcpy(hdr.eth.h_source, srcmac, ETH_ALEN); + hdr.eth.h_proto =3D bpf_htons(ETH_P_IPV6); + + err =3D bpf_lwt_push_encap(skb, BPF_LWT_ENCAP_IP, &hdr, sizeof(hdr)); + if (err) + return BPF_DROP; + + return BPF_LWT_REROUTE; +} + +volatile const int tgt_ip_version; + +__u16 transport_hdr =3D 0; +__u16 network_hdr =3D 0; +bool fexit_triggered =3D false; + +SEC("?fexit/bpf_lwt_push_ip_encap") +int BPF_PROG(fexit_lwt_push_ip_encap, struct sk_buff *skb, void *hdr, u32 = len, bool ingress, + int retval) +{ + struct iphdr *iph; + + if (retval || fexit_triggered) + return 0; + + iph =3D (typeof(iph)) (skb->head + skb->network_header); + if (iph->version !=3D tgt_ip_version) + return 0; + + if ((iph->version =3D=3D 4 && iph->protocol =3D=3D 17 /* IPPROTO_UDP */) = || + (iph->version =3D=3D 6 && ((struct ipv6hdr *)iph)->nexthdr =3D=3D 17 = /* IPPROTO_UDP */)) { + fexit_triggered =3D true; + transport_hdr =3D skb->transport_header; + network_hdr =3D skb->network_header; + } + return 0; +} + char _license[] SEC("license") =3D "GPL"; --=20 2.54.0