Files
Frey Alfredsson 9337d2ff8a Adding a basic TC eBPF Qdisc classifier example
This example demonstrates how to write a simple eBPF Qdisc classifier
that classifies flows depending on their destination TCP port. The
example script, runner.sh shows how you can use the eBPF Qdisc
classifier and implement the same functionality using u32. The script
creates two network namespaces called Left and Right, representing two
different hosts. The script then illustrates the classifiers in action
using iperf3 by starting clients on the Left namespace that connect to
iperf3 servers on the Right namespace. The Qdisc classifiers give TCP
ports 8080 and 8081 a high rate limit, while TCP port 8082 represents
all other traffic capped at 20 Mbps.

Signed-off-by: Frey Alfredsson <freysteinn@freysteinn.com>
2021-03-17 02:26:58 +01:00

71 lines
1.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright 2021 Frey Alfredsson <freysteinn@freysteinn.com> */
/* Based on code by Jesper Dangaard Brouer <brouer@redhat.com> */
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <linux/pkt_sched.h>
#include <linux/pkt_cls.h>
#include "../include/xdp/parsing_helpers.h"
/*
* This example eBPF code mirrors the TC u32 rules set in the runner.sh
* script, where the script gives different rate limits depending on if the TCP
* traffic is for ports 8080 or 8081. It must be loaded with the direct-action
* flag on TC to function, as this is a Qdisc classifier, not a Qdisc action. The
* runner.sh script shows an example of how it is loaded and used.
*/
SEC("classifier")
int cls_filter(struct __sk_buff *skb)
{
void *data_end = (void *)(unsigned long long)skb->data_end;
void *data = (void *)(unsigned long long)skb->data;
struct hdr_cursor nh;
struct ethhdr *eth;
int eth_type;
int ip_type;
int tcp_type;
struct iphdr *iphdr;
struct ipv6hdr *ipv6hdr;
struct tcphdr *tcphdr;
skb->tc_classid = 0x30; /* Default class */
nh.pos = data;
/* Parse Ethernet and IP/IPv6 headers */
eth_type = parse_ethhdr(&nh, data_end, &eth);
if (eth_type == bpf_htons(ETH_P_IP)) {
ip_type = parse_iphdr(&nh, data_end, &iphdr);
if (ip_type != IPPROTO_TCP)
goto out;
}
else if (eth_type == bpf_htons(ETH_P_IPV6)) {
ip_type = parse_ip6hdr(&nh, data_end, &ipv6hdr);
if (ip_type != IPPROTO_TCP)
goto out;
} else {
goto out;
}
/* Classify TCP ports 8080 and 8081 */
tcp_type = parse_tcphdr(&nh, data_end, &tcphdr);
if (tcphdr + 1 > data_end) {
goto out;
}
switch (tcphdr->dest) {
case bpf_htons(8080):
skb->tc_classid = 0x10; /* Handles are always in hex */
break;
case bpf_htons(8081):
skb->tc_classid = 0x20;
}
out:
return TC_ACT_OK;
}
char _license[] SEC("license") = "GPL";