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  }