ebpf: fix gre encapsulation in xdp_lb

The xdp_lb was not handling correctly the GRE load balancing
and it was not supporting the GRE + ERSPAN that is used by
some aggregator devices.
pull/6059/head
Eric Leblond 5 years ago committed by Victor Julien
parent eb4c71fdd6
commit b9351339a2

@ -40,8 +40,8 @@
/* Hashing initval */
#define INITVAL 15485863
/* Increase CPUMAP_MAX_CPUS if ever you have more than 64 CPUs */
#define CPUMAP_MAX_CPUS 64
/* Increase CPUMAP_MAX_CPUS if ever you have more than 128 CPUs */
#define CPUMAP_MAX_CPUS 128
struct vlan_hdr {
__u16 h_vlan_TCI;
@ -134,7 +134,7 @@ static int __always_inline hash_ipv6(void *data, void *data_end)
static int __always_inline filter_gre(struct xdp_md *ctx, void *data, __u64 nh_off, void *data_end)
{
struct iphdr *iph = data + nh_off;
__be16 proto;
__u16 proto;
struct gre_hdr {
__be16 flags;
__be16 proto;
@ -158,6 +158,11 @@ static int __always_inline filter_gre(struct xdp_md *ctx, void *data, __u64 nh_o
if (grhdr->flags & GRE_SEQ)
nh_off += 4;
/* Update offset to skip ERPSAN header if we have one */
if (proto == __constant_htons(ETH_P_ERSPAN)) {
nh_off += 8;
}
if (data + nh_off > data_end)
return XDP_PASS;
if (bpf_xdp_adjust_head(ctx, 0 + nh_off))
@ -166,18 +171,32 @@ static int __always_inline filter_gre(struct xdp_md *ctx, void *data, __u64 nh_o
data = (void *)(long)ctx->data;
data_end = (void *)(long)ctx->data_end;
/* we have now data starting at Ethernet header */
struct ethhdr *eth = data;
proto = eth->h_proto;
/* we want to hash on IP so we need to get to ip hdr */
nh_off = sizeof(*eth);
if (data + nh_off > data_end)
return XDP_PASS;
/* we need to increase offset and update protocol
* in the case we have VLANs */
if (proto == __constant_htons(ETH_P_8021Q)) {
struct vlan_hdr *vhdr = (struct vlan_hdr *)(data);
struct vlan_hdr *vhdr = (struct vlan_hdr *)(data + nh_off);
if ((void *)(vhdr + 1) > data_end)
return XDP_PASS;
proto = vhdr->h_vlan_encapsulated_proto;
nh_off += sizeof(struct vlan_hdr);
}
if (data + nh_off > data_end)
return XDP_PASS;
/* proto should now be IP style */
if (proto == __constant_htons(ETH_P_IP)) {
return hash_ipv4(data, data_end);
return hash_ipv4(data + nh_off, data_end);
} else if (proto == __constant_htons(ETH_P_IPV6)) {
return hash_ipv6(data, data_end);
return hash_ipv6(data + nh_off, data_end);
} else
return XDP_PASS;
}

Loading…
Cancel
Save