xdp: tooling and dependencies

Setup gVisor so that an AF_XDP dispatcher can be implemented.

Specifically:

- xdp_loader: a binary for testing XDP programs
- Two basic XDP programs
- Update the cilium/ebpf dep
- Genrule for building BPF programs
- Install clang on buildkite to support building BPF programs

PiperOrigin-RevId: 464562411
This commit is contained in:
Kevin Krakauer
2022-08-01 10:11:57 -07:00
committed by gVisor bot
parent 1d3b90268d
commit 03b6826243
8 changed files with 245 additions and 4 deletions
+3 -3
View File
@@ -15,11 +15,11 @@ http_file(
# Bazel/starlark utilities.
http_archive(
name = "bazel_skylib",
sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz",
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz",
],
sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728",
)
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
@@ -1484,8 +1484,8 @@ go_repository(
go_repository(
name = "com_github_cilium_ebpf",
importpath = "github.com/cilium/ebpf",
sum = "h1:QlHdikaxALkqWasW8hAC1mfR0jdmvbfaBdBPFmRSglA=",
version = "v0.4.0",
sum = "h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4=",
version = "v0.9.1",
)
go_repository(
+21
View File
@@ -72,3 +72,24 @@ def default_net_util():
def coreutil():
return [] # Nothing needed.
def bpf_program(name, src, bpf_object, visibility, hdrs):
"""Generates BPF object files from .c source code.
Args:
name: target name for BPF program.
src: BPF program souce code in C.
bpf_object: name of generated bpf object code.
visibility: target visibility.
hdrs: header files, but currently unsupported.
"""
if hdrs != []:
fail("hdrs attribute is unsupported")
native.genrule(
name = name,
srcs = [src],
visibility = visibility,
outs = [bpf_object],
cmd = "clang -O2 -Wall -Werror -target bpf -c $< -o $@",
)
+5 -1
View File
@@ -8,7 +8,7 @@ change for Google-internal and bazel-compatible rules.
load("//tools/go_stateify:defs.bzl", "go_stateify")
load("//tools/go_marshal:defs.bzl", "go_marshal", "marshal_deps", "marshal_test_deps")
load("//tools/nogo:defs.bzl", "nogo_test")
load("//tools/bazeldefs:defs.bzl", _BuildSettingInfo = "BuildSettingInfo", _amd64_config = "amd64_config", _arch_config = "arch_config", _arm64_config = "arm64_config", _bool_flag = "bool_flag", _build_test = "build_test", _bzl_library = "bzl_library", _coreutil = "coreutil", _default_net_util = "default_net_util", _more_shards = "more_shards", _most_shards = "most_shards", _proto_library = "proto_library", _select_arch = "select_arch", _select_system = "select_system", _short_path = "short_path", _transition_allowlist = "transition_allowlist", _version = "version")
load("//tools/bazeldefs:defs.bzl", _BuildSettingInfo = "BuildSettingInfo", _amd64_config = "amd64_config", _arch_config = "arch_config", _arm64_config = "arm64_config", _bool_flag = "bool_flag", _bpf_program = "bpf_program", _build_test = "build_test", _bzl_library = "bzl_library", _coreutil = "coreutil", _default_net_util = "default_net_util", _more_shards = "more_shards", _most_shards = "most_shards", _proto_library = "proto_library", _select_arch = "select_arch", _select_system = "select_system", _short_path = "short_path", _transition_allowlist = "transition_allowlist", _version = "version")
load("//tools/bazeldefs:cc.bzl", _cc_binary = "cc_binary", _cc_flags_supplier = "cc_flags_supplier", _cc_grpc_library = "cc_grpc_library", _cc_library = "cc_library", _cc_proto_library = "cc_proto_library", _cc_test = "cc_test", _cc_toolchain = "cc_toolchain", _gbenchmark = "gbenchmark", _gbenchmark_internal = "gbenchmark_internal", _grpcpp = "grpcpp", _gtest = "gtest", _vdso_linker_option = "vdso_linker_option")
load("//tools/bazeldefs:go.bzl", _gazelle = "gazelle", _go_binary = "go_binary", _go_embed_data = "go_embed_data", _go_grpc_and_proto_libraries = "go_grpc_and_proto_libraries", _go_library = "go_library", _go_path = "go_path", _go_proto_library = "go_proto_library", _go_rule = "go_rule", _go_test = "go_test", _gotsan_flag_values = "gotsan_flag_values", _gotsan_values = "gotsan_values", _select_goarch = "select_goarch", _select_goos = "select_goos")
load("//tools/bazeldefs:pkg.bzl", _pkg_deb = "pkg_deb", _pkg_tar = "pkg_tar")
@@ -52,6 +52,9 @@ go_proto_library = _go_proto_library
gotsan_values = _gotsan_values
gotsan_flag_values = _gotsan_flag_values
# BPF rules.
bpf_program = _bpf_program
# Packaging rules.
pkg_deb = _pkg_deb
pkg_tar = _pkg_tar
@@ -117,6 +120,7 @@ def go_binary(name, nogo = True, pure = False, static = False, x_defs = None, **
name = name + "_nogo_library",
srcs = kwargs.get("srcs", []),
deps = kwargs.get("deps", []),
embedsrcs = kwargs.get("embedsrcs", []),
testonly = 1,
)
nogo_test(
+20
View File
@@ -0,0 +1,20 @@
load("//tools:defs.bzl", "go_binary")
package(licenses = ["notice"])
go_binary(
name = "xdp_loader",
srcs = [
"main.go",
],
embedsrcs = [
"//tools/xdp/bpf:drop_ebpf.o", # keep
"//tools/xdp/bpf:pass_ebpf.o", # keep
],
visibility = ["//:sandbox"],
deps = [
"@com_github_cilium_ebpf//:go_default_library",
"@com_github_cilium_ebpf//link:go_default_library",
"@org_golang_x_sys//unix:go_default_library",
],
)
+19
View File
@@ -0,0 +1,19 @@
load("//tools:defs.bzl", "bpf_program")
package(licenses = ["notice"])
bpf_program(
name = "pass_ebpf",
src = "pass.ebpf.c",
hdrs = [],
bpf_object = "pass_ebpf.o",
visibility = ["//:sandbox"],
)
bpf_program(
name = "drop_ebpf",
src = "drop.ebpf.c",
hdrs = [],
bpf_object = "drop_ebpf.o",
visibility = ["//:sandbox"],
)
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <linux/bpf.h>
#define section(secname) __attribute__((section(secname), used))
char __license[] section("license") = "Apache-2.0";
// You probably shouldn't change the section or function name. Each is used by
// BPF tooling, and so changes can cause runtime failures.
section("xdp") int xdp_prog(struct xdp_md *ctx) { return XDP_DROP; }
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <linux/bpf.h>
#define section(secname) __attribute__((section(secname), used))
char __license[] section("license") = "Apache-2.0";
// You probably shouldn't change the section or function name. Each is used by
// BPF tooling, and so changes can cause runtime failures.
section("xdp") int xdp_prog(struct xdp_md *ctx) { return XDP_PASS; }
+131
View File
@@ -0,0 +1,131 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The xdp_loader tool is used to load compiled XDP object files into the XDP
// hook of a net device. It is intended primarily for testing.
package main
import (
"bytes"
_ "embed"
"flag"
"log"
"net"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
"golang.org/x/sys/unix"
)
var (
device = flag.String("device", "", "which device to attach to")
program = flag.String("program", "", "which program to install: one of [pass, drop]")
)
// Builtin programs selectable by users.
var (
//go:embed bpf/pass_ebpf.o
pass []byte
//go:embed bpf/drop_ebpf.o
drop []byte
)
var programs = map[string][]byte{
"pass": pass,
"drop": drop,
}
func main() {
// Sanity check.
if len(pass) == 0 {
panic("the pass program failed to embed")
}
if len(drop) == 0 {
panic("the drop program failed to embed")
}
flag.Parse()
// Get a net device.
if *device == "" {
log.Fatalf("must specify -device")
}
iface, err := net.InterfaceByName(*device)
if err != nil {
log.Fatalf("unknown device %q: %v", *device, err)
}
// Choose a program.
if *program == "" {
log.Fatalf("must specify -program")
}
progData, ok := programs[*program]
if !ok {
log.Fatalf("unknown program %q", *program)
}
// Load into the kernel. Note that this is usually done using bpf2go,
// but since we haven't set up that tool we do everything manually.
spec, err := ebpf.LoadCollectionSpecFromReader(bytes.NewReader(progData))
if err != nil {
log.Fatalf("failed to load spec: %v", err)
}
// We need to pass a struct with a field of a specific type and tag.
var objects struct {
Program *ebpf.Program `ebpf:"xdp_prog"`
}
if err := spec.LoadAndAssign(&objects, nil); err != nil {
log.Fatalf("failed to load program: %v", err)
}
defer func() {
if err := objects.Program.Close(); err != nil {
log.Printf("failed to close program: %v", err)
}
}()
// Attach the program to the XDP hook on the device. Fallback from best
// to worst mode.
modes := []struct {
name string
flag link.XDPAttachFlags
}{
{name: "offload", flag: link.XDPOffloadMode},
{name: "driver", flag: link.XDPDriverMode},
{name: "generic", flag: link.XDPGenericMode},
}
var attached link.Link
for _, mode := range modes {
attached, err = link.AttachXDP(link.XDPOptions{
Program: objects.Program,
Interface: iface.Index,
Flags: mode.flag,
})
if err == nil {
log.Printf("attached with mode %q", mode.name)
break
}
log.Printf("failed to attach with mode %q: %v", mode.name, err)
}
if attached == nil {
log.Fatalf("failed to attach program")
}
defer attached.Close()
log.Printf("Successfully attached! Press CTRL-C to quit and remove the program from the device.")
for {
unix.Pause()
}
}