mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
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:
committed by
gVisor bot
parent
1d3b90268d
commit
03b6826243
@@ -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(
|
||||
|
||||
@@ -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
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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"],
|
||||
)
|
||||
@@ -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; }
|
||||
@@ -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; }
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user