Modify outer IP header of GENEVE encapsulated packets

129 views Asked by At

For my project, I want to insert a timestamp option into outer IP header of a GENEVE encapsulated packet. I tried with a BPF program which attached into egress TC hook of a GENEVE vport of OVS. My BPF program is below but it inserts option field into inner ip header. So, I have 2 questions:

  1. Can use BPF to insert IP option into IP outer header?
  2. If it is possible, How to do it?
#include <linux/pkt_cls.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <arpa/inet.h>

#ifndef __section
# define __section(NAME)                  \
        __attribute__((section(NAME), used))
#endif

#ifndef __inline
# define __inline                         \
        inline __attribute__((always_inline))
#endif

#ifndef lock_xadd
# define lock_xadd(ptr, val)              \
        ((void)__sync_fetch_and_add(ptr, val))
#endif

#ifndef BPF_FUNC
# define BPF_FUNC(NAME, ...)              \
        (*NAME)(__VA_ARGS__) = (void *)BPF_FUNC_##NAME
#endif

#define OPT_LEN 4
#define IP_HDL 20

static int BPF_FUNC(skb_adjust_room, struct __sk_buff *skb, __s32 len_diff, __u32 mode, __u64 flags);
//static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, uint16_t vlan_tci);

__section("egress")
int push_tun_opt(struct __sk_buff *skb) {
    struct ethhdr *eth;
    struct iphdr *iph;
    __be32 *opt;
    volatile void *data, *data_end;
    int ret = TC_ACT_OK;
    //skb_vlan_push(skb,0x8100,0x1);
    skb_adjust_room(skb, size(OPT_LEN), BPF_ADJ_ROOM_NET, BPF_F_ADJ_ROOM_ENCAP_L3_IPV4);
    data = (void *)(long)skb->data;
    data_end = (void *)(long)skb->data_end;
    eth = (void *)data;
    iph = (void *)(eth+1);
    opt = (void *)(iph+1);
    if ((void *)(opt+1) > data_end)
        goto out;
    *opt = 0x1234abcd;
out:
    return ret;
}

char __license[] __section("license") = "GPL";

Packet before insertion Before

Packet after insertion After

BPF program with none flags

#include <linux/pkt_cls.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <arpa/inet.h>
#include <uapi/linux/bpf.h>

#ifndef __section
# define __section(NAME)                  \
        __attribute__((section(NAME), used))
#endif

#ifndef __inline
# define __inline                         \
        inline __attribute__((always_inline))
#endif

#ifndef lock_xadd
# define lock_xadd(ptr, val)              \
        ((void)__sync_fetch_and_add(ptr, val))
#endif

#ifndef BPF_FUNC
# define BPF_FUNC(NAME, ...)              \
        (*NAME)(__VA_ARGS__) = (void *)BPF_FUNC_##NAME
#endif

#define OPT_LEN 4
#define IP_HDL 20

static int BPF_FUNC(skb_adjust_room, struct __sk_buff *skb, __s32 len_diff, __u32 mode, __u64 flags);
//static int BPF_FUNC(skb_vlan_push, struct __sk_buff *skb, uint16_t proto, uint16_t vlan_tci);
static int BPF_FUNC(skb_store_bytes, struct __sk_buff *skb, __s32 offset, const void *from, __u32 len, __u64 flags);

__section("egress")
int push_tun_opt(struct __sk_buff *skb) {
    struct ethhdr *eth;
    struct iphdr *iph;
    __be32 *opt;
    volatile void *data, *data_end;
    
    int ret = TC_ACT_OK;
    //skb_vlan_push(skb,0x8100,0x1);
    skb_adjust_room(skb, OPT_LEN, BPF_ADJ_ROOM_NET, 0);
    data = (void *)(long)skb->data;
    data_end = (void *)(long)skb->data_end;
    eth = (void *)data;
    iph = (void *)(eth+1);
    opt = (void *)(iph+1);
    if ((void *)(opt+1) > data_end)
        goto out;

    *opt = 0x1234abcd;
    //skb_store_bytes(skb, sizeof(struct ethhdr) + sizeof(struct iphdr), &opt, OPT_LEN, BPF_F_RECOMPUTE_CSUM);

out:
    return ret;
}

char __license[] __section("license") = "GPL";

geneve interface geneve interface Edit 1: I added 2 images: a ping packet is encapsulated in GENEVE tunnel before and after using tc-bpf program.

Edit 2: I added BPF program with 0 flags.

0

There are 0 answers