-
Notifications
You must be signed in to change notification settings - Fork 103
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
samples/bpf: start basic TC redirect benchmark
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
- Loading branch information
1 parent
6c18692
commit 286256d
Showing
3 changed files
with
223 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* TC (Traffic Control) eBPF redirect benchmark | ||
* | ||
* NOTICE: TC loading is different from XDP loading. TC bpf objects | ||
* use the 'tc' cmdline tool from iproute2 for loading and | ||
* attaching bpf programs. | ||
* | ||
* Copyright(c) 2017 Jesper Dangaard Brouer, Red Hat Inc. | ||
*/ | ||
#include <uapi/linux/bpf.h> | ||
#include <uapi/linux/if_ether.h> | ||
#include <uapi/linux/if_packet.h> | ||
#include <uapi/linux/if_vlan.h> | ||
#include <uapi/linux/ip.h> | ||
#include <uapi/linux/in.h> | ||
#include <uapi/linux/tcp.h> | ||
#include <uapi/linux/udp.h> | ||
|
||
#include <uapi/linux/pkt_cls.h> | ||
|
||
#include "bpf_helpers.h" | ||
|
||
/* Notice: TC and iproute2 bpf-loader uses another elf map layout */ | ||
struct bpf_elf_map { | ||
__u32 type; | ||
__u32 size_key; | ||
__u32 size_value; | ||
__u32 max_elem; | ||
__u32 flags; | ||
__u32 id; | ||
__u32 pinning; | ||
}; | ||
|
||
/* TODO: Describe what this PIN_GLOBAL_NS value 2 means??? | ||
* | ||
* A file is automatically created here: | ||
* /sys/fs/bpf/tc/globals/egress_ifindex | ||
*/ | ||
#define PIN_GLOBAL_NS 2 | ||
|
||
struct bpf_elf_map SEC("maps") egress_ifindex = { | ||
.type = BPF_MAP_TYPE_ARRAY, | ||
.size_key = sizeof(int), | ||
.size_value = sizeof(int), | ||
.pinning = PIN_GLOBAL_NS, | ||
.max_elem = 1, | ||
}; | ||
|
||
static void swap_src_dst_mac(void *data) | ||
{ | ||
unsigned short *p = data; | ||
unsigned short dst[3]; | ||
|
||
dst[0] = p[0]; | ||
dst[1] = p[1]; | ||
dst[2] = p[2]; | ||
p[0] = p[3]; | ||
p[1] = p[4]; | ||
p[2] = p[5]; | ||
p[3] = dst[0]; | ||
p[4] = dst[1]; | ||
p[5] = dst[2]; | ||
} | ||
|
||
/* Notice this section name is used when attaching TC filter | ||
* | ||
* Like: | ||
* $TC qdisc add dev $DEV clsact | ||
* $TC filter add dev $DEV ingress bpf da obj $BPF_OBJ sec ingress_redirect | ||
* $TC filter show dev $DEV ingress | ||
* $TC filter del dev $DEV ingress | ||
* | ||
* Does TC redirect respect IP-forward settings? | ||
* | ||
*/ | ||
SEC("ingress_redirect") | ||
int _ingress_redirect(struct __sk_buff *skb) | ||
{ | ||
void *data = (void *)(long)skb->data; | ||
void *data_end = (void *)(long)skb->data_end; | ||
struct ethhdr *eth = data; | ||
int key = 0, *ifindex; | ||
|
||
if (data + sizeof(*eth) > data_end) | ||
return TC_ACT_OK; | ||
|
||
/* Keep ARP resolution working */ | ||
if (eth->h_proto == htons(ETH_P_ARP)) | ||
return TC_ACT_OK; | ||
|
||
/* Lookup what ifindex to redirect packets to */ | ||
ifindex = bpf_map_lookup_elem(&egress_ifindex, &key); | ||
if (!ifindex) | ||
return TC_ACT_OK; | ||
|
||
if (*ifindex == 0) | ||
return TC_ACT_OK; // or TC_ACT_SHOT ? | ||
|
||
/* FIXME: with mlx5 we need to update MAC-addr else the HW | ||
* will drop the frames silently. | ||
*/ | ||
|
||
/* Swap src and dst mac-addr if ingress==egress */ | ||
if (*ifindex == 5) | ||
swap_src_dst_mac(data); | ||
|
||
//return bpf_redirect(*ifindex, BPF_F_INGRESS); // __bpf_rx_skb | ||
return bpf_redirect(*ifindex, 0); // __bpf_tx_skb / __dev_xmit_skb | ||
} | ||
|
||
char _license[] SEC("license") = "GPL"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* Copyright(c) 2017 Jesper Dangaard Brouer, Red Hat, Inc. | ||
*/ | ||
static const char *__doc__= | ||
" TC redirect benchmark\n\n" | ||
" You must attach bpf object via TC cmdline tool\n" | ||
; | ||
|
||
#include <errno.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <stdbool.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
#include <locale.h> | ||
|
||
#include <getopt.h> | ||
#include <net/if.h> | ||
#include <time.h> | ||
|
||
#include "libbpf.h" | ||
|
||
static int verbose = 1; | ||
static const char *mapfile = "/sys/fs/bpf/tc/globals/egress_ifindex"; | ||
|
||
static const struct option long_options[] = { | ||
{"help", no_argument, NULL, 'h' }, | ||
{"egress", required_argument, NULL, 'o' }, | ||
{0, 0, NULL, 0 } | ||
}; | ||
|
||
static void usage(char *argv[]) | ||
{ | ||
int i; | ||
printf("\nDOCUMENTATION:\n%s\n", __doc__); | ||
printf("\n"); | ||
printf(" Usage: %s (options-see-below)\n", | ||
argv[0]); | ||
printf(" Listing options:\n"); | ||
for (i = 0; long_options[i].name != 0; i++) { | ||
printf(" --%-12s", long_options[i].name); | ||
if (long_options[i].flag != NULL) | ||
printf(" flag (internal value:%d)", | ||
*long_options[i].flag); | ||
else | ||
printf(" short-option: -%c", | ||
long_options[i].val); | ||
printf("\n"); | ||
} | ||
printf("\n"); | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
int longindex = 0, opt, fd = -1; | ||
int egress_ifindex = 0; | ||
int ret = EXIT_SUCCESS; | ||
int key = 0; | ||
|
||
/* Parse commands line args */ | ||
while ((opt = getopt_long(argc, argv, "ho:", | ||
long_options, &longindex)) != -1) { | ||
switch (opt) { | ||
case 'o': | ||
egress_ifindex = atoi(optarg); | ||
break; | ||
case 'h': | ||
default: | ||
usage(argv); | ||
return EXIT_FAILURE; | ||
} | ||
} | ||
|
||
fd = bpf_obj_get(mapfile); | ||
if (fd < 0) { | ||
fprintf(stderr, "ERROR: cannot open bpf_obj_get(%s): %s(%d)\n", | ||
mapfile, strerror(errno), errno); | ||
ret = EXIT_FAILURE; | ||
goto out; | ||
} | ||
|
||
/* Only update/set egress port when set via cmdline */ | ||
if (egress_ifindex) { | ||
ret = bpf_map_update_elem(fd, &key, &egress_ifindex, 0); | ||
if (ret) { | ||
perror("ERROR: bpf_map_update_elem"); | ||
ret = EXIT_FAILURE; | ||
goto out; | ||
} | ||
if (verbose) | ||
printf("Change egress redirect ifindex to: %d\n", | ||
egress_ifindex); | ||
} else { | ||
/* Read info from map */ | ||
ret = bpf_map_lookup_elem(fd, &key, &egress_ifindex); | ||
if (ret) { | ||
perror("ERROR: bpf_map_lookup_elem"); | ||
ret = EXIT_FAILURE; | ||
goto out; | ||
} | ||
if (verbose) | ||
printf("Current egress redirect ifindex: %d\n", | ||
egress_ifindex); | ||
} | ||
out: | ||
if (fd != -1) | ||
close(fd); | ||
return ret; | ||
} |