Skip to content

Commit 502b92b

Browse files
committed
xdp: handle vxlan tunnels
Ticket: 7674
1 parent 508c06f commit 502b92b

1 file changed

Lines changed: 92 additions & 0 deletions

File tree

ebpf/xdp_filter.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
* also be used as workaround of some hardware offload issue */
6666
#define VLAN_TRACKING 1
6767

68+
/* vxlan port configurable */
69+
#define VXLAN_PORT 4789
70+
6871
struct vlan_hdr {
6972
__u16 h_vlan_TCI;
7073
__u16 h_vlan_encapsulated_proto;
@@ -623,6 +626,92 @@ static int __always_inline filter_gre(
623626
return XDP_PASS;
624627
}
625628

629+
struct vxlanhdr {
630+
__be16 flags;
631+
__be16 gdp;
632+
__u8 vni0;
633+
__u8 vni1;
634+
__u8 vni2;
635+
__u8 res;
636+
};
637+
638+
static int __always_inline filter_vxlan(
639+
struct xdp_md *ctx, void *data, __u64 nh_off, void *data_end, struct iphdr *iph)
640+
{
641+
__u16 vlan0 = 0;
642+
__u16 vlan1;
643+
__u16 h_proto;
644+
struct flowtunnel_keys tuple;
645+
struct flowtunnel_id *value;
646+
647+
struct vxlanhdr *vh = (struct vxlanhdr *)(data + nh_off);
648+
649+
tuple.tunnel = 6; // DECODE_TUNNEL_VXLAN
650+
tuple.src = iph->saddr;
651+
tuple.dst = iph->daddr;
652+
tuple.session = vh->vni2 | (vh->vni1 << 8) | (vh->vni0 << 16);
653+
value = bpf_map_lookup_elem(&flow_table_tunnels, &tuple);
654+
if (!value) {
655+
// unknown tunnel
656+
return XDP_PASS;
657+
}
658+
vlan1 = 0x8000 | value->tunnel_id;
659+
nh_off += sizeof(*vh);
660+
661+
struct ethhdr *eth = data + nh_off;
662+
nh_off += sizeof(*eth);
663+
h_proto = eth->h_proto;
664+
665+
if (h_proto == __constant_htons(ETH_P_8021Q) || h_proto == __constant_htons(ETH_P_8021AD)) {
666+
struct vlan_hdr *vhdr;
667+
668+
if (data + nh_off + sizeof(struct vlan_hdr) > data_end)
669+
return XDP_PASS;
670+
vhdr = data + nh_off;
671+
nh_off += sizeof(struct vlan_hdr);
672+
h_proto = vhdr->h_vlan_encapsulated_proto;
673+
#if VLAN_TRACKING
674+
vlan0 = vhdr->h_vlan_TCI & 0x0fff;
675+
#endif
676+
}
677+
678+
if (h_proto == __constant_htons(ETH_P_IP))
679+
return filter_ipv4_final(ctx, data, nh_off, data_end, vlan0, vlan1);
680+
else if (h_proto == __constant_htons(ETH_P_IPV6))
681+
return filter_ipv6(ctx, data, nh_off, data_end, vlan0, vlan1);
682+
return XDP_PASS;
683+
}
684+
685+
static int __always_inline is_vxlan(void *data, __u64 nh_off, void *data_end)
686+
{
687+
if (data + nh_off + sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct vxlanhdr) +
688+
sizeof(struct ethhdr) >
689+
data_end) {
690+
return 0;
691+
}
692+
struct udphdr *uh = (struct udphdr *)(data + nh_off + sizeof(struct iphdr));
693+
if (uh->dest != __constant_ntohs(VXLAN_PORT)) {
694+
return 0;
695+
}
696+
struct vxlanhdr *vh =
697+
(struct vxlanhdr *)(data + nh_off + sizeof(struct iphdr) + sizeof(struct udphdr));
698+
// check vni is present and reserved is 0
699+
if ((vh->flags & 0xDEFF) == 8 && vh->res == 0) {
700+
return 0;
701+
}
702+
// check ethernet type is handled
703+
struct ethhdr *eth = (struct ethhdr *)(data + nh_off + sizeof(struct iphdr) +
704+
sizeof(struct udphdr) + sizeof(struct vxlanhdr));
705+
if (eth->h_proto == __constant_htons(ETH_P_8021Q) ||
706+
eth->h_proto == __constant_htons(ETH_P_8021AD) ||
707+
eth->h_proto == __constant_htons(ETH_P_IP) ||
708+
eth->h_proto == __constant_htons(ETH_P_IPV6)) {
709+
return 1;
710+
}
711+
712+
return 0;
713+
}
714+
626715
static int __always_inline filter_ipv4(
627716
struct xdp_md *ctx, void *data, __u64 nh_off, void *data_end, __u16 vlan0, __u16 vlan1)
628717
{
@@ -633,6 +722,9 @@ static int __always_inline filter_ipv4(
633722
if (iph->protocol == IPPROTO_GRE) {
634723
nh_off += sizeof(struct iphdr);
635724
return filter_gre(ctx, data, nh_off, data_end, iph);
725+
} else if (iph->protocol == IPPROTO_UDP && is_vxlan(data, nh_off, data_end)) {
726+
nh_off += sizeof(struct iphdr) + sizeof(struct udphdr);
727+
return filter_vxlan(ctx, data, nh_off, data_end, iph);
636728
}
637729
return filter_ipv4_final(ctx, data, nh_off, data_end, vlan0, vlan1);
638730
}

0 commit comments

Comments
 (0)