github.com/cilium/cilium@v1.16.2/bpf/lib/vxlan.h (about) 1 /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ 2 /* Copyright Authors of Cilium */ 3 4 #pragma once 5 6 #include <linux/in.h> 7 #include <linux/ip.h> 8 #include <linux/udp.h> 9 #include <linux/if_ether.h> 10 #include "lib/csum.h" 11 12 /* 13 * Returns the VNI in the native host's endian format of a xvlan encap'd packet. 14 * 15 * The caller must ensure the skb associated with these data buffers are infact 16 * a vxlan encapsulated packet before invoking this function. 17 * 18 * This can be done by calling 'vxlan_skb_is_vxlan_v4' 19 * 20 */ 21 static __always_inline __u32 22 vxlan_get_vni(const void *data, const void *data_end, 23 const struct iphdr *ipv4) 24 { 25 int l3_size = ipv4->ihl * 4; 26 struct vxlanhdr *hdr; 27 28 if (data + sizeof(struct ethhdr) + l3_size + sizeof(struct udphdr) 29 + sizeof(struct vxlanhdr) > data_end) 30 return 0; 31 32 hdr = (struct vxlanhdr *)(data + sizeof(struct ethhdr) + l3_size + 33 sizeof(struct udphdr)); 34 35 return tunnel_vni_to_sec_identity(hdr->vx_vni); 36 } 37 38 /* 39 * Points 'inner' to the inner IPv4 header of a IPv4 VXLan excapsulated 40 * packet. 41 * 42 * The caller should be sure the VXLan packet is encapsulating IPv4 traffic 43 * before calling this method. 44 * 45 * Returns 'true' if 'inner' now points to a bounds-checked inner IPv4 header. 46 * Returns 'false' if an error occurred. 47 */ 48 static __always_inline bool 49 vxlan_get_inner_ipv4(const void *data, const void *data_end, 50 const struct iphdr *ipv4, struct iphdr **inner) { 51 int l3_size = ipv4->ihl * 4; 52 53 if (data + sizeof(struct ethhdr) + l3_size + sizeof(struct udphdr) 54 + sizeof(struct vxlanhdr) + sizeof(struct ethhdr) + 55 sizeof(struct iphdr) > data_end) 56 return false; 57 58 *inner = (struct iphdr *)(data + sizeof(struct ethhdr) 59 + l3_size + sizeof(struct udphdr) + sizeof(struct vxlanhdr) 60 + sizeof(struct ethhdr)); 61 62 return true; 63 } 64 65 /* 66 * Rewrites the current VNI in the VXLan header to the provided and updates 67 * the l4 checksum if necessary. 68 * 69 * The VNI is in host endian format when supplied to this function. 70 * 71 * The caller must ensure the skb associated with these data buffers are infact 72 * a vxlan encapsulated packet before invoking this function. 73 * 74 * This can be done by calling 'vxlan_skb_is_vxlan_v4' 75 */ 76 static __always_inline bool 77 vxlan_rewrite_vni(void *ctx, const void *data, const void *data_end, 78 const struct iphdr *ipv4, __u32 vni) 79 { 80 struct csum_offset csum = {0}; 81 int l3_size = ipv4->ihl * 4; 82 int l4_off = sizeof(struct ethhdr) + l3_size; 83 struct udphdr *udp = NULL; 84 struct vxlanhdr *vx = NULL; 85 __be32 old_vni = 0; 86 87 if (data + sizeof(struct ethhdr) + l3_size + sizeof(struct udphdr) 88 + sizeof(struct vxlanhdr) > data_end) 89 return false; 90 91 udp = (struct udphdr *)(data + sizeof(struct ethhdr) + l3_size); 92 93 vx = (struct vxlanhdr *)(data + sizeof(struct ethhdr) + l3_size 94 + sizeof(struct udphdr)); 95 96 old_vni = vx->vx_vni; 97 vx->vx_vni = bpf_htonl(vni << 8); 98 99 /* per rfc768 if UDP's checksum is zero this indicates no checksum was 100 * computed at all, so don't bother recomputing if its zero. 101 */ 102 if (udp->check) { 103 csum_l4_offset_and_flags(IPPROTO_UDP, &csum); 104 if (csum_l4_replace(ctx, l4_off, &csum, old_vni, vx->vx_vni, 105 BPF_F_PSEUDO_HDR | sizeof(__u16)) < 0) 106 return false; 107 } 108 109 return true; 110 }