Skip to content

Commit

Permalink
samples/bpf: start basic TC redirect benchmark
Browse files Browse the repository at this point in the history
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
  • Loading branch information
netoptimizer committed Jun 20, 2017
1 parent 6c18692 commit 286256d
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 0 deletions.
5 changes: 5 additions & 0 deletions kernel/samples/bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ TARGETS += xdp_bench02_drop_pattern

TARGETS += bpf_tail_calls01

# TC bpf targets uses bpf-elf-loader included in tc/iproute2. Thus,
# it is unnecessary to link "user" binary with bpf_load.c. TODO, if
# somone cares, makefile should have separate target for TC.
TARGETS += tc_bench01_redirect

# Experimental target
TARGETS += xdp_rxhash

Expand Down
110 changes: 110 additions & 0 deletions kernel/samples/bpf/tc_bench01_redirect_kern.c
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";
108 changes: 108 additions & 0 deletions kernel/samples/bpf/tc_bench01_redirect_user.c
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;
}

0 comments on commit 286256d

Please sign in to comment.