mirror of
https://github.com/aljazceru/kata-containers.git
synced 2026-01-24 16:54:26 +01:00
Merge pull request #4486 from openanolis/runtime-rs-merge-main
runtime-rs: runtime-rs merge main
This commit is contained in:
2
.github/workflows/snap-release.yaml
vendored
2
.github/workflows/snap-release.yaml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
# Check semantic versioning format (x.y.z) and if the current tag is the latest tag
|
||||
if echo "${current_version}" | grep -q "^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+$" && echo -e "$latest_version\n$current_version" | sort -C -V; then
|
||||
# Current version is the latest version, build it
|
||||
snapcraft -d snap --destructive-mode
|
||||
snapcraft snap --debug --destructive-mode
|
||||
fi
|
||||
|
||||
- name: Upload snap
|
||||
|
||||
2
.github/workflows/snap.yaml
vendored
2
.github/workflows/snap.yaml
vendored
@@ -24,4 +24,4 @@ jobs:
|
||||
- name: Build snap
|
||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'force-skip-ci') }}
|
||||
run: |
|
||||
snapcraft -d snap --destructive-mode
|
||||
snapcraft snap --debug --destructive-mode
|
||||
|
||||
@@ -116,7 +116,7 @@ detailed below.
|
||||
The Kata logs appear in the `containerd` log files, along with logs from `containerd` itself.
|
||||
|
||||
For more information about `containerd` debug, please see the
|
||||
[`containerd` documentation](https://github.com/containerd/containerd/blob/master/docs/getting-started.md).
|
||||
[`containerd` documentation](https://github.com/containerd/containerd/blob/main/docs/getting-started.md).
|
||||
|
||||
#### Enabling full `containerd` debug
|
||||
|
||||
|
||||
@@ -320,7 +320,7 @@ mod tests {
|
||||
|
||||
## Test user
|
||||
|
||||
[Unit tests are run *twice*](https://github.com/kata-containers/tests/blob/main/.ci/go-test.sh):
|
||||
[Unit tests are run *twice*](../src/runtime/go-test.sh):
|
||||
|
||||
- as the current user
|
||||
- as the `root` user (if different to the current user)
|
||||
|
||||
@@ -79,7 +79,7 @@ a "`BUG: feature X not implemented see {bug-url}`" type error.
|
||||
- Don't use multiple log calls when a single log call could be used.
|
||||
|
||||
- Use structured logging where possible to allow
|
||||
[standard tooling](https://github.com/kata-containers/tests/tree/main/cmd/log-parser)
|
||||
[standard tooling](../src/tools/log-parser)
|
||||
be able to extract the log fields.
|
||||
|
||||
### Names
|
||||
|
||||
@@ -17,7 +17,7 @@ Kubelet instance is responsible for managing the lifecycle of pods
|
||||
within the nodes and eventually relies on a container runtime to
|
||||
handle execution. The Kubelet architecture decouples lifecycle
|
||||
management from container execution through a dedicated gRPC based
|
||||
[Container Runtime Interface (CRI)](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/container-runtime-interface-v1.md).
|
||||
[Container Runtime Interface (CRI)](https://github.com/kubernetes/design-proposals-archive/blob/main/node/container-runtime-interface-v1.md).
|
||||
|
||||
In other words, a Kubelet is a CRI client and expects a CRI
|
||||
implementation to handle the server side of the interface.
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# Storage
|
||||
|
||||
## Limits
|
||||
|
||||
Kata Containers is [compatible](README.md#compatibility) with existing
|
||||
standards and runtime. From the perspective of storage, this means no
|
||||
limits are placed on the amount of storage a container
|
||||
[workload](README.md#workload) may use.
|
||||
|
||||
Since cgroups are not able to set limits on storage allocation, if you
|
||||
wish to constrain the amount of storage a container uses, consider
|
||||
using an existing facility such as `quota(1)` limits or
|
||||
[device mapper](#devicemapper) limits.
|
||||
|
||||
## virtio SCSI
|
||||
|
||||
If a block-based graph driver is [configured](README.md#configuration),
|
||||
|
||||
@@ -68,7 +68,7 @@ the Kata logs import to the EFK stack.
|
||||
> stack they are able to utilise in order to modify and test as necessary.
|
||||
|
||||
Minikube by default
|
||||
[configures](https://github.com/kubernetes/minikube/blob/master/deploy/iso/minikube-iso/board/coreos/minikube/rootfs-overlay/etc/systemd/journald.conf)
|
||||
[configures](https://github.com/kubernetes/minikube/blob/master/deploy/iso/minikube-iso/board/minikube/x86_64/rootfs-overlay/etc/systemd/journald.conf)
|
||||
the `systemd-journald` with the
|
||||
[`Storage=volatile`](https://www.freedesktop.org/software/systemd/man/journald.conf.html) option,
|
||||
which results in the journal being stored in `/run/log/journal`. Unfortunately, the Minikube EFK
|
||||
@@ -163,7 +163,7 @@ sub-filter on, for instance, the `SYSLOG_IDENTIFIER` to differentiate the Kata c
|
||||
on the `PRIORITY` to filter out critical issues etc.
|
||||
|
||||
Kata generates a significant amount of Kata specific information, which can be seen as
|
||||
[`logfmt`](https://github.com/kata-containers/tests/tree/main/cmd/log-parser#logfile-requirements).
|
||||
[`logfmt`](../../src/tools/log-parser/README.md#logfile-requirements).
|
||||
data contained in the `MESSAGE` field. Imported as-is, there is no easy way to filter on that data
|
||||
in Kibana:
|
||||
|
||||
|
||||
@@ -52,6 +52,36 @@ parts:
|
||||
curl -LO https://golang.org/dl/${tarfile}
|
||||
tar -xf ${tarfile} --strip-components=1
|
||||
|
||||
rustdeps:
|
||||
after: [metadata]
|
||||
plugin: nil
|
||||
prime:
|
||||
- -*
|
||||
build-packages:
|
||||
- curl
|
||||
override-build: |
|
||||
source "${SNAPCRAFT_PROJECT_DIR}/snap/local/snap-common.sh"
|
||||
|
||||
# put everything in stage
|
||||
cd "${SNAPCRAFT_STAGE}"
|
||||
|
||||
version="$(${yq} r ${kata_dir}/versions.yaml languages.rust.meta.newest-version)"
|
||||
if ! command -v rustup > /dev/null; then
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain ${version}
|
||||
fi
|
||||
|
||||
export PATH=${PATH}:${HOME}/.cargo/bin
|
||||
rustup toolchain install ${version}
|
||||
rustup default ${version}
|
||||
if [ "${arch}" == "ppc64le" ] || [ "${arch}" == "s390x" ] ; then
|
||||
[ ${arch} == "ppc64le"] && arch="powerpc64le"
|
||||
rustup target add ${arch}-unknown-linux-gnu
|
||||
else
|
||||
rustup target add ${arch}-unknown-linux-musl
|
||||
$([ "$(whoami)" != "root" ] && echo sudo) ln -sf /usr/bin/g++ /bin/musl-g++
|
||||
fi
|
||||
rustup component add rustfmt
|
||||
|
||||
image:
|
||||
after: [godeps, qemu, kernel]
|
||||
plugin: nil
|
||||
@@ -271,25 +301,26 @@ parts:
|
||||
|
||||
virtiofsd:
|
||||
plugin: nil
|
||||
after: [godeps]
|
||||
after: [godeps, rustdeps]
|
||||
override-build: |
|
||||
source "${SNAPCRAFT_PROJECT_DIR}/snap/local/snap-common.sh"
|
||||
|
||||
# Currently, only one platform uses the new rust virtiofsd. The
|
||||
# others make use of QEMU's C implementation.
|
||||
# Currently, powerpc makes use of the QEMU's C implementation.
|
||||
# The other platforms make use of the new rust virtiofsd.
|
||||
#
|
||||
# See "tools/packaging/scripts/configure-hypervisor.sh".
|
||||
if [ "${arch}" = 'x86_64' ]
|
||||
if [ "${arch}" == "ppc64le" ]
|
||||
then
|
||||
echo "INFO: Building rust version of virtiofsd"
|
||||
else
|
||||
echo "INFO: Building QEMU's C version of virtiofsd"
|
||||
# Handled by the 'qemu' part, so nothing more to do here.
|
||||
exit 0
|
||||
else
|
||||
echo "INFO: Building rust version of virtiofsd"
|
||||
fi
|
||||
|
||||
cd "${kata_dir}"
|
||||
|
||||
export PATH=${PATH}:${HOME}/.cargo/bin
|
||||
# Download the rust implementation of virtiofsd
|
||||
tools/packaging/static-build/virtiofsd/build-static-virtiofsd.sh
|
||||
sudo install \
|
||||
|
||||
8
src/agent/Cargo.lock
generated
8
src/agent/Cargo.lock
generated
@@ -271,9 +271,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.5"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
||||
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
@@ -1409,9 +1409,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
version = "1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
||||
@@ -18,7 +18,7 @@ serde_json = "1.0.39"
|
||||
scan_fmt = "0.2.3"
|
||||
scopeguard = "1.0.0"
|
||||
thiserror = "1.0.26"
|
||||
regex = "1.5.4"
|
||||
regex = "1.5.5"
|
||||
serial_test = "0.5.1"
|
||||
kata-sys-util = { path = "../libs/kata-sys-util" }
|
||||
sysinfo = "0.23.0"
|
||||
|
||||
@@ -20,7 +20,7 @@ protobuf = "2.27.0"
|
||||
slog = "2.5.2"
|
||||
slog-scope = "4.1.2"
|
||||
scan_fmt = "0.2.6"
|
||||
regex = "1.5.4"
|
||||
regex = "1.5.5"
|
||||
path-absolutize = "1.2.0"
|
||||
anyhow = "1.0.32"
|
||||
cgroups = { package = "cgroups-rs", version = "0.2.8" }
|
||||
|
||||
@@ -840,15 +840,13 @@ pub fn get_mount_fs_type_from_file(mount_file: &str, mount_point: &str) -> Resul
|
||||
return Err(anyhow!("Invalid mount point {}", mount_point));
|
||||
}
|
||||
|
||||
let file = File::open(mount_file)?;
|
||||
let reader = BufReader::new(file);
|
||||
let content = fs::read_to_string(mount_file)?;
|
||||
|
||||
let re = Regex::new(format!("device .+ mounted on {} with fstype (.+)", mount_point).as_str())?;
|
||||
|
||||
// Read the file line by line using the lines() iterator from std::io::BufRead.
|
||||
for (_index, line) in reader.lines().enumerate() {
|
||||
let line = line?;
|
||||
let capes = match re.captures(line.as_str()) {
|
||||
for (_index, line) in content.lines().enumerate() {
|
||||
let capes = match re.captures(line) {
|
||||
Some(c) => c,
|
||||
None => continue,
|
||||
};
|
||||
@@ -861,7 +859,7 @@ pub fn get_mount_fs_type_from_file(mount_file: &str, mount_point: &str) -> Resul
|
||||
Err(anyhow!(
|
||||
"failed to find FS type for mount point {}, mount file content: {:?}",
|
||||
mount_point,
|
||||
fs::read_to_string(mount_file)
|
||||
content
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
4
src/libs/Cargo.lock
generated
4
src/libs/Cargo.lock
generated
@@ -123,9 +123,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.6"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120"
|
||||
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
|
||||
@@ -160,7 +160,7 @@ DEFMEMSZ := 2048
|
||||
DEFMEMSLOTS := 10
|
||||
#Default number of bridges
|
||||
DEFBRIDGES := 1
|
||||
DEFENABLEANNOTATIONS := []
|
||||
DEFENABLEANNOTATIONS := [\"enable_iommu\"]
|
||||
DEFDISABLEGUESTSECCOMP := true
|
||||
DEFDISABLEGUESTEMPTYDIR := false
|
||||
#Default experimental features enabled
|
||||
@@ -175,9 +175,9 @@ DEFVALIDENTROPYSOURCES := [\"/dev/urandom\",\"/dev/random\",\"\"]
|
||||
DEFDISABLEBLOCK := false
|
||||
DEFSHAREDFS_CLH_VIRTIOFS := virtio-fs
|
||||
DEFSHAREDFS_QEMU_VIRTIOFS := virtio-fs
|
||||
DEFVIRTIOFSDAEMON := $(LIBEXECDIR)/kata-qemu/virtiofsd
|
||||
ifeq ($(ARCH),amd64)
|
||||
DEFVIRTIOFSDAEMON := $(LIBEXECDIR)/virtiofsd
|
||||
ifeq ($(ARCH),ppc64le)
|
||||
DEFVIRTIOFSDAEMON := $(LIBEXECDIR)/kata-qemu/virtiofsd
|
||||
endif
|
||||
DEFVALIDVIRTIOFSDAEMONPATHS := [\"$(DEFVIRTIOFSDAEMON)\"]
|
||||
# Default DAX mapping cache size in MiB
|
||||
|
||||
@@ -125,7 +125,7 @@ $ kata-runtime env
|
||||
|
||||
For detailed information and analysis on obtaining logs for other system
|
||||
components, see the documentation for the
|
||||
[`kata-log-parser`](https://github.com/kata-containers/tests/tree/main/cmd/log-parser)
|
||||
[`kata-log-parser`](../tools/log-parser)
|
||||
tool.
|
||||
|
||||
### Kata containerd shimv2
|
||||
|
||||
@@ -15,6 +15,14 @@ Available metrics include:
|
||||
All the provided metrics are in Prometheus format. While `kata-monitor` can be used as a standalone daemon on any host running Kata Containers workloads and can be used for retrieving profiling data from the running Kata runtimes, its main expected usage is to be deployed as a DaemonSet on a Kubernetes cluster: there Prometheus should scrape the metrics from the kata-monitor endpoints.
|
||||
For more information on the Kata Containers metrics architecture and a detailed list of the available metrics provided by Kata monitor check the [Kata 2.0 Metrics Design](../../../../docs/design/kata-2-0-metrics.md) document.
|
||||
|
||||
## Local network considerations
|
||||
|
||||
The `kata-monitor` daemon is not run unless explicitly
|
||||
[started](#kata-monitor-arguments). However, when it is running it
|
||||
will accept connections on the `localhost` network interface (by
|
||||
default) and provide metrics to any client process that connects to
|
||||
it, whether they are privileged or not.
|
||||
|
||||
## Usage
|
||||
Each `kata-monitor` instance detects and monitors the Kata Container workloads running on the same node.
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@ require (
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/containerd/cgroups v1.0.3
|
||||
github.com/containerd/console v1.0.3
|
||||
github.com/containerd/containerd v1.6.1
|
||||
github.com/containerd/containerd v1.6.6
|
||||
github.com/containerd/cri-containerd v1.11.1-0.20190125013620-4dd6735020f5
|
||||
github.com/containerd/fifo v1.0.0
|
||||
github.com/containerd/ttrpc v1.1.0
|
||||
github.com/containerd/typeurl v1.0.2
|
||||
github.com/containernetworking/plugins v1.0.1
|
||||
github.com/containernetworking/plugins v1.1.1
|
||||
github.com/coreos/go-systemd/v22 v22.3.2
|
||||
github.com/cri-o/cri-o v1.0.0-rc2.0.20170928185954-3394b3b2d6af
|
||||
github.com/docker/go-units v0.4.0
|
||||
@@ -25,17 +25,16 @@ require (
|
||||
github.com/go-openapi/strfmt v0.18.0
|
||||
github.com/go-openapi/swag v0.19.14
|
||||
github.com/go-openapi/validate v0.18.0
|
||||
github.com/godbus/dbus/v5 v5.0.4
|
||||
github.com/godbus/dbus/v5 v5.0.6
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/intel-go/cpuid v0.0.0-20210602155658-5747e5cec0d9
|
||||
github.com/mdlayher/vsock v1.1.0
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/opencontainers/runc v1.1.0
|
||||
github.com/opencontainers/runc v1.1.2
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
|
||||
github.com/opencontainers/selinux v1.10.0
|
||||
github.com/opencontainers/selinux v1.10.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/prometheus/client_golang v1.11.1
|
||||
github.com/prometheus/client_model v0.2.0
|
||||
github.com/prometheus/common v0.30.0
|
||||
github.com/prometheus/procfs v0.7.3
|
||||
@@ -51,7 +50,7 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.3.0
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
|
||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
|
||||
google.golang.org/grpc v1.43.0
|
||||
k8s.io/apimachinery v0.22.5
|
||||
k8s.io/cri-api v0.23.1
|
||||
|
||||
@@ -82,8 +82,9 @@ github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+V
|
||||
github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
|
||||
github.com/Microsoft/hcsshim v0.9.2 h1:wB06W5aYFfUB3IvootYAY2WnOmIdgPGfqSI6tufQNnY=
|
||||
github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
||||
github.com/Microsoft/hcsshim v0.9.3 h1:k371PzBuRrz2b+ebGuI2nVgVhgsVX60jMfSw80NECxo=
|
||||
github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
|
||||
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
@@ -154,8 +155,9 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE
|
||||
github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.6.2 h1:iHsfF/t4aW4heW2YKfeHrVPGdtYTL4C4KocpM8KTSnI=
|
||||
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.7.0 h1:1k/q3ATgxSXRdrmPfH8d7YK0GfqVsEKZAX9dQZvs56k=
|
||||
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -208,8 +210,9 @@ github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoT
|
||||
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
|
||||
github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
|
||||
github.com/containerd/containerd v1.6.1 h1:oa2uY0/0G+JX4X7hpGCYvkp9FjUancz56kSNnb1sG3o=
|
||||
github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE=
|
||||
github.com/containerd/containerd v1.6.6 h1:xJNPhbrmz8xAMDNoVjHy9YHtWwEQNS+CDkcIRh7t8Y0=
|
||||
github.com/containerd/containerd v1.6.6/go.mod h1:ZoP1geJldzCVY3Tonoz7b1IXk8rIX0Nltt5QE4OMNk0=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
@@ -232,6 +235,7 @@ github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZH
|
||||
github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk=
|
||||
github.com/containerd/go-cni v1.1.0/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA=
|
||||
github.com/containerd/go-cni v1.1.3/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA=
|
||||
github.com/containerd/go-cni v1.1.6/go.mod h1:BWtoWl5ghVymxu6MBjg79W9NZrCRyHIdUtk4cauMe34=
|
||||
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
|
||||
github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
|
||||
github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
|
||||
@@ -243,6 +247,7 @@ github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6T
|
||||
github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow=
|
||||
github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms=
|
||||
github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4=
|
||||
github.com/containerd/imgcrypt v1.1.4/go.mod h1:LorQnPtzL/T0IyCeftcsMEO7AqxUDbdO8j/tSUpgxvo=
|
||||
github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
|
||||
github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
|
||||
github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
|
||||
@@ -267,16 +272,19 @@ github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNR
|
||||
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
|
||||
github.com/containernetworking/cni v1.0.1 h1:9OIL/sZmMYDBe+G8svzILAlulUpaDTUjeAbtH/JNLBo=
|
||||
github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
|
||||
github.com/containernetworking/cni v1.1.1 h1:ky20T7c0MvKvbMOwS/FrlbNwjEoqJEUUYfsL4b0mc4k=
|
||||
github.com/containernetworking/cni v1.1.1/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
|
||||
github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
|
||||
github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
|
||||
github.com/containernetworking/plugins v1.0.1 h1:wwCfYbTCj5FC0EJgyzyjTXmqysOiJE9r712Z+2KVZAk=
|
||||
github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE=
|
||||
github.com/containernetworking/plugins v1.1.1 h1:+AGfFigZ5TiQH00vhR8qPeSatj53eNGz0C1d3wVYlHE=
|
||||
github.com/containernetworking/plugins v1.1.1/go.mod h1:Sr5TH/eBsGLXK/h71HeLfX19sZPp3ry5uHSkI4LPxV8=
|
||||
github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
|
||||
github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
|
||||
github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
|
||||
github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
|
||||
github.com/containers/ocicrypt v1.1.3/go.mod h1:xpdkbVAuaH3WzbEabUd5yDsl9SwJA5pABH85425Es2g=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
@@ -445,8 +453,9 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8=
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
|
||||
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@@ -527,6 +536,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -661,6 +671,7 @@ github.com/mdlayher/vsock v1.1.0 h1:2k9udP/hUkLUOboGxXMHOk4f0GWWZwS3IuE3Ee/YYfk=
|
||||
github.com/mdlayher/vsock v1.1.0/go.mod h1:nsVhPsVuBBwAKh6i6PzdNoke6/TNYTjkxoRKAp/+pXs=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
@@ -696,6 +707,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||
github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
@@ -715,6 +727,8 @@ github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1ls
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
@@ -724,8 +738,9 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
|
||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
@@ -747,8 +762,9 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo
|
||||
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
|
||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU=
|
||||
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opencontainers/selinux v1.10.1 h1:09LIPVRP3uuZGQvgR+SgMSNBd1Eb3vlRbGqQpoHsF8w=
|
||||
github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
|
||||
@@ -772,8 +788,9 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
|
||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
@@ -1192,11 +1209,13 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE=
|
||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1281,6 +1300,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -158,10 +158,10 @@ func watchOOMEvents(ctx context.Context, s *service) {
|
||||
containerID, err := s.sandbox.GetOOMEvent(ctx)
|
||||
if err != nil {
|
||||
if err.Error() == "ttrpc: closed" || err.Error() == "Dead agent" {
|
||||
shimLog.WithError(err).Warn("agent has shutdown, return from watching of OOM events")
|
||||
shimLog.WithError(err).Info("agent has shutdown, return from watching of OOM events")
|
||||
return
|
||||
}
|
||||
shimLog.WithError(err).Warn("failed to get OOM event from sandbox")
|
||||
shimLog.WithError(err).Info("failed to get OOM event from sandbox")
|
||||
time.Sleep(defaultCheckInterval)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1114,7 +1114,7 @@ func CalculateSandboxSizing(spec *specs.Spec) (numCPU, memSizeMB uint32) {
|
||||
// ... to result in VM resources of 1 (MB) for memory, and 3 for CPU (2200 mCPU rounded up to 3).
|
||||
annotation, ok := spec.Annotations[ctrAnnotations.SandboxCPUPeriod]
|
||||
if ok {
|
||||
period, err = strconv.ParseUint(annotation, 10, 32)
|
||||
period, err = strconv.ParseUint(annotation, 10, 64)
|
||||
if err != nil {
|
||||
ociLog.Warningf("sandbox-sizing: failure to parse SandboxCPUPeriod: %s", annotation)
|
||||
period = 0
|
||||
@@ -1123,7 +1123,7 @@ func CalculateSandboxSizing(spec *specs.Spec) (numCPU, memSizeMB uint32) {
|
||||
|
||||
annotation, ok = spec.Annotations[ctrAnnotations.SandboxCPUQuota]
|
||||
if ok {
|
||||
quota, err = strconv.ParseInt(annotation, 10, 32)
|
||||
quota, err = strconv.ParseInt(annotation, 10, 64)
|
||||
if err != nil {
|
||||
ociLog.Warningf("sandbox-sizing: failure to parse SandboxCPUQuota: %s", annotation)
|
||||
quota = 0
|
||||
@@ -1132,7 +1132,7 @@ func CalculateSandboxSizing(spec *specs.Spec) (numCPU, memSizeMB uint32) {
|
||||
|
||||
annotation, ok = spec.Annotations[ctrAnnotations.SandboxMem]
|
||||
if ok {
|
||||
memory, err = strconv.ParseInt(annotation, 10, 32)
|
||||
memory, err = strconv.ParseInt(annotation, 10, 64)
|
||||
if err != nil {
|
||||
ociLog.Warningf("sandbox-sizing: failure to parse SandboxMem: %s", annotation)
|
||||
memory = 0
|
||||
|
||||
@@ -1196,6 +1196,11 @@ func TestCalculateSandboxSizing(t *testing.T) {
|
||||
expectedCPU: 100,
|
||||
expectedMem: 0,
|
||||
},
|
||||
{
|
||||
spec: makeSizingAnnotations("4294967296", "400", "100"),
|
||||
expectedCPU: 4,
|
||||
expectedMem: 4096,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
|
||||
188
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
generated
vendored
188
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/hcs/system.go
generated
vendored
@@ -4,17 +4,22 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/cow"
|
||||
"github.com/Microsoft/hcsshim/internal/hcs/schema1"
|
||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
|
||||
"github.com/Microsoft/hcsshim/internal/jobobject"
|
||||
"github.com/Microsoft/hcsshim/internal/log"
|
||||
"github.com/Microsoft/hcsshim/internal/logfields"
|
||||
"github.com/Microsoft/hcsshim/internal/oc"
|
||||
"github.com/Microsoft/hcsshim/internal/timeout"
|
||||
"github.com/Microsoft/hcsshim/internal/vmcompute"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@@ -28,7 +33,8 @@ type System struct {
|
||||
waitBlock chan struct{}
|
||||
waitError error
|
||||
exitError error
|
||||
os, typ string
|
||||
os, typ, owner string
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
func newSystem(id string) *System {
|
||||
@@ -38,6 +44,11 @@ func newSystem(id string) *System {
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation detail for silo naming, this should NOT be relied upon very heavily.
|
||||
func siloNameFmt(containerID string) string {
|
||||
return fmt.Sprintf(`\Container_%s`, containerID)
|
||||
}
|
||||
|
||||
// CreateComputeSystem creates a new compute system with the given configuration but does not start it.
|
||||
func CreateComputeSystem(ctx context.Context, id string, hcsDocumentInterface interface{}) (_ *System, err error) {
|
||||
operation := "hcs::CreateComputeSystem"
|
||||
@@ -127,6 +138,7 @@ func (computeSystem *System) getCachedProperties(ctx context.Context) error {
|
||||
}
|
||||
computeSystem.typ = strings.ToLower(props.SystemType)
|
||||
computeSystem.os = strings.ToLower(props.RuntimeOSType)
|
||||
computeSystem.owner = strings.ToLower(props.Owner)
|
||||
if computeSystem.os == "" && computeSystem.typ == "container" {
|
||||
// Pre-RS5 HCS did not return the OS, but it only supported containers
|
||||
// that ran Windows.
|
||||
@@ -195,7 +207,7 @@ func (computeSystem *System) Start(ctx context.Context) (err error) {
|
||||
if err != nil {
|
||||
return makeSystemError(computeSystem, operation, err, events)
|
||||
}
|
||||
|
||||
computeSystem.startTime = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -324,11 +336,115 @@ func (computeSystem *System) Properties(ctx context.Context, types ...schema1.Pr
|
||||
return properties, nil
|
||||
}
|
||||
|
||||
// PropertiesV2 returns the requested container properties targeting a V2 schema container.
|
||||
func (computeSystem *System) PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (*hcsschema.Properties, error) {
|
||||
computeSystem.handleLock.RLock()
|
||||
defer computeSystem.handleLock.RUnlock()
|
||||
// queryInProc handles querying for container properties without reaching out to HCS. `props`
|
||||
// will be updated to contain any data returned from the queries present in `types`. If any properties
|
||||
// failed to be queried they will be tallied up and returned in as the first return value. Failures on
|
||||
// query are NOT considered errors; the only failure case for this method is if the containers job object
|
||||
// cannot be opened.
|
||||
func (computeSystem *System) queryInProc(ctx context.Context, props *hcsschema.Properties, types []hcsschema.PropertyType) ([]hcsschema.PropertyType, error) {
|
||||
// In the future we can make use of some new functionality in the HCS that allows you
|
||||
// to pass a job object for HCS to use for the container. Currently, the only way we'll
|
||||
// be able to open the job/silo is if we're running as SYSTEM.
|
||||
jobOptions := &jobobject.Options{
|
||||
UseNTVariant: true,
|
||||
Name: siloNameFmt(computeSystem.id),
|
||||
}
|
||||
job, err := jobobject.Open(ctx, jobOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer job.Close()
|
||||
|
||||
var fallbackQueryTypes []hcsschema.PropertyType
|
||||
for _, propType := range types {
|
||||
switch propType {
|
||||
case hcsschema.PTStatistics:
|
||||
// Handle a bad caller asking for the same type twice. No use in re-querying if this is
|
||||
// filled in already.
|
||||
if props.Statistics == nil {
|
||||
props.Statistics, err = computeSystem.statisticsInProc(job)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Warn("failed to get statistics in-proc")
|
||||
|
||||
fallbackQueryTypes = append(fallbackQueryTypes, propType)
|
||||
}
|
||||
}
|
||||
default:
|
||||
fallbackQueryTypes = append(fallbackQueryTypes, propType)
|
||||
}
|
||||
}
|
||||
|
||||
return fallbackQueryTypes, nil
|
||||
}
|
||||
|
||||
// statisticsInProc emulates what HCS does to grab statistics for a given container with a small
|
||||
// change to make grabbing the private working set total much more efficient.
|
||||
func (computeSystem *System) statisticsInProc(job *jobobject.JobObject) (*hcsschema.Statistics, error) {
|
||||
// Start timestamp for these stats before we grab them to match HCS
|
||||
timestamp := time.Now()
|
||||
|
||||
memInfo, err := job.QueryMemoryStats()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
processorInfo, err := job.QueryProcessorStats()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
storageInfo, err := job.QueryStorageStats()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This calculates the private working set more efficiently than HCS does. HCS calls NtQuerySystemInformation
|
||||
// with the class SystemProcessInformation which returns an array containing system information for *every*
|
||||
// process running on the machine. They then grab the pids that are running in the container and filter down
|
||||
// the entries in the array to only what's running in that silo and start tallying up the total. This doesn't
|
||||
// work well as performance should get worse if more processess are running on the machine in general and not
|
||||
// just in the container. All of the additional information besides the WorkingSetPrivateSize field is ignored
|
||||
// as well which isn't great and is wasted work to fetch.
|
||||
//
|
||||
// HCS only let's you grab statistics in an all or nothing fashion, so we can't just grab the private
|
||||
// working set ourselves and ask for everything else seperately. The optimization we can make here is
|
||||
// to open the silo ourselves and do the same queries for the rest of the info, as well as calculating
|
||||
// the private working set in a more efficient manner by:
|
||||
//
|
||||
// 1. Find the pids running in the silo
|
||||
// 2. Get a process handle for every process (only need PROCESS_QUERY_LIMITED_INFORMATION access)
|
||||
// 3. Call NtQueryInformationProcess on each process with the class ProcessVmCounters
|
||||
// 4. Tally up the total using the field PrivateWorkingSetSize in VM_COUNTERS_EX2.
|
||||
privateWorkingSet, err := job.QueryPrivateWorkingSet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &hcsschema.Statistics{
|
||||
Timestamp: timestamp,
|
||||
ContainerStartTime: computeSystem.startTime,
|
||||
Uptime100ns: uint64(time.Since(computeSystem.startTime).Nanoseconds()) / 100,
|
||||
Memory: &hcsschema.MemoryStats{
|
||||
MemoryUsageCommitBytes: memInfo.JobMemory,
|
||||
MemoryUsageCommitPeakBytes: memInfo.PeakJobMemoryUsed,
|
||||
MemoryUsagePrivateWorkingSetBytes: privateWorkingSet,
|
||||
},
|
||||
Processor: &hcsschema.ProcessorStats{
|
||||
RuntimeKernel100ns: uint64(processorInfo.TotalKernelTime),
|
||||
RuntimeUser100ns: uint64(processorInfo.TotalUserTime),
|
||||
TotalRuntime100ns: uint64(processorInfo.TotalKernelTime + processorInfo.TotalUserTime),
|
||||
},
|
||||
Storage: &hcsschema.StorageStats{
|
||||
ReadCountNormalized: uint64(storageInfo.ReadStats.IoCount),
|
||||
ReadSizeBytes: storageInfo.ReadStats.TotalSize,
|
||||
WriteCountNormalized: uint64(storageInfo.WriteStats.IoCount),
|
||||
WriteSizeBytes: storageInfo.WriteStats.TotalSize,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// hcsPropertiesV2Query is a helper to make a HcsGetComputeSystemProperties call using the V2 schema property types.
|
||||
func (computeSystem *System) hcsPropertiesV2Query(ctx context.Context, types []hcsschema.PropertyType) (*hcsschema.Properties, error) {
|
||||
operation := "hcs::System::PropertiesV2"
|
||||
|
||||
queryBytes, err := json.Marshal(hcsschema.PropertyQuery{PropertyTypes: types})
|
||||
@@ -345,12 +461,66 @@ func (computeSystem *System) PropertiesV2(ctx context.Context, types ...hcsschem
|
||||
if propertiesJSON == "" {
|
||||
return nil, ErrUnexpectedValue
|
||||
}
|
||||
properties := &hcsschema.Properties{}
|
||||
if err := json.Unmarshal([]byte(propertiesJSON), properties); err != nil {
|
||||
props := &hcsschema.Properties{}
|
||||
if err := json.Unmarshal([]byte(propertiesJSON), props); err != nil {
|
||||
return nil, makeSystemError(computeSystem, operation, err, nil)
|
||||
}
|
||||
|
||||
return properties, nil
|
||||
return props, nil
|
||||
}
|
||||
|
||||
// PropertiesV2 returns the requested compute systems properties targeting a V2 schema compute system.
|
||||
func (computeSystem *System) PropertiesV2(ctx context.Context, types ...hcsschema.PropertyType) (_ *hcsschema.Properties, err error) {
|
||||
computeSystem.handleLock.RLock()
|
||||
defer computeSystem.handleLock.RUnlock()
|
||||
|
||||
// Let HCS tally up the total for VM based queries instead of querying ourselves.
|
||||
if computeSystem.typ != "container" {
|
||||
return computeSystem.hcsPropertiesV2Query(ctx, types)
|
||||
}
|
||||
|
||||
// Define a starter Properties struct with the default fields returned from every
|
||||
// query. Owner is only returned from Statistics but it's harmless to include.
|
||||
properties := &hcsschema.Properties{
|
||||
Id: computeSystem.id,
|
||||
SystemType: computeSystem.typ,
|
||||
RuntimeOsType: computeSystem.os,
|
||||
Owner: computeSystem.owner,
|
||||
}
|
||||
|
||||
logEntry := log.G(ctx)
|
||||
// First lets try and query ourselves without reaching to HCS. If any of the queries fail
|
||||
// we'll take note and fallback to querying HCS for any of the failed types.
|
||||
fallbackTypes, err := computeSystem.queryInProc(ctx, properties, types)
|
||||
if err == nil && len(fallbackTypes) == 0 {
|
||||
return properties, nil
|
||||
} else if err != nil {
|
||||
logEntry.WithError(fmt.Errorf("failed to query compute system properties in-proc: %w", err))
|
||||
fallbackTypes = types
|
||||
}
|
||||
|
||||
logEntry.WithFields(logrus.Fields{
|
||||
logfields.ContainerID: computeSystem.id,
|
||||
"propertyTypes": fallbackTypes,
|
||||
}).Info("falling back to HCS for property type queries")
|
||||
|
||||
hcsProperties, err := computeSystem.hcsPropertiesV2Query(ctx, fallbackTypes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Now add in anything that we might have successfully queried in process.
|
||||
if properties.Statistics != nil {
|
||||
hcsProperties.Statistics = properties.Statistics
|
||||
hcsProperties.Owner = properties.Owner
|
||||
}
|
||||
|
||||
// For future support for querying processlist in-proc as well.
|
||||
if properties.ProcessList != nil {
|
||||
hcsProperties.ProcessList = properties.ProcessList
|
||||
}
|
||||
|
||||
return hcsProperties, nil
|
||||
}
|
||||
|
||||
// Pause pauses the execution of the computeSystem. This feature is not enabled in TP5.
|
||||
|
||||
9
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicy.go
generated
vendored
9
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/hns/hnspolicy.go
generated
vendored
@@ -21,10 +21,11 @@ const (
|
||||
)
|
||||
|
||||
type NatPolicy struct {
|
||||
Type PolicyType `json:"Type"`
|
||||
Protocol string `json:",omitempty"`
|
||||
InternalPort uint16 `json:",omitempty"`
|
||||
ExternalPort uint16 `json:",omitempty"`
|
||||
Type PolicyType `json:"Type"`
|
||||
Protocol string `json:",omitempty"`
|
||||
InternalPort uint16 `json:",omitempty"`
|
||||
ExternalPort uint16 `json:",omitempty"`
|
||||
ExternalPortReserved bool `json:",omitempty"`
|
||||
}
|
||||
|
||||
type QosPolicy struct {
|
||||
|
||||
111
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/jobobject/iocp.go
generated
vendored
Normal file
111
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/jobobject/iocp.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
package jobobject
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/log"
|
||||
"github.com/Microsoft/hcsshim/internal/queue"
|
||||
"github.com/Microsoft/hcsshim/internal/winapi"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
ioInitOnce sync.Once
|
||||
initIOErr error
|
||||
// Global iocp handle that will be re-used for every job object
|
||||
ioCompletionPort windows.Handle
|
||||
// Mapping of job handle to queue to place notifications in.
|
||||
jobMap sync.Map
|
||||
)
|
||||
|
||||
// MsgAllProcessesExited is a type representing a message that every process in a job has exited.
|
||||
type MsgAllProcessesExited struct{}
|
||||
|
||||
// MsgUnimplemented represents a message that we are aware of, but that isn't implemented currently.
|
||||
// This should not be treated as an error.
|
||||
type MsgUnimplemented struct{}
|
||||
|
||||
// pollIOCP polls the io completion port forever.
|
||||
func pollIOCP(ctx context.Context, iocpHandle windows.Handle) {
|
||||
var (
|
||||
overlapped uintptr
|
||||
code uint32
|
||||
key uintptr
|
||||
)
|
||||
|
||||
for {
|
||||
err := windows.GetQueuedCompletionStatus(iocpHandle, &code, &key, (**windows.Overlapped)(unsafe.Pointer(&overlapped)), windows.INFINITE)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("failed to poll for job object message")
|
||||
continue
|
||||
}
|
||||
if val, ok := jobMap.Load(key); ok {
|
||||
msq, ok := val.(*queue.MessageQueue)
|
||||
if !ok {
|
||||
log.G(ctx).WithField("value", msq).Warn("encountered non queue type in job map")
|
||||
continue
|
||||
}
|
||||
notification, err := parseMessage(code, overlapped)
|
||||
if err != nil {
|
||||
log.G(ctx).WithFields(logrus.Fields{
|
||||
"code": code,
|
||||
"overlapped": overlapped,
|
||||
}).Warn("failed to parse job object message")
|
||||
continue
|
||||
}
|
||||
if err := msq.Write(notification); err == queue.ErrQueueClosed {
|
||||
// Write will only return an error when the queue is closed.
|
||||
// The only time a queue would ever be closed is when we call `Close` on
|
||||
// the job it belongs to which also removes it from the jobMap, so something
|
||||
// went wrong here. We can't return as this is reading messages for all jobs
|
||||
// so just log it and move on.
|
||||
log.G(ctx).WithFields(logrus.Fields{
|
||||
"code": code,
|
||||
"overlapped": overlapped,
|
||||
}).Warn("tried to write to a closed queue")
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
log.G(ctx).Warn("received a message for a job not present in the mapping")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseMessage(code uint32, overlapped uintptr) (interface{}, error) {
|
||||
// Check code and parse out relevant information related to that notification
|
||||
// that we care about. For now all we handle is the message that all processes
|
||||
// in the job have exited.
|
||||
switch code {
|
||||
case winapi.JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
|
||||
return MsgAllProcessesExited{}, nil
|
||||
// Other messages for completeness and a check to make sure that if we fall
|
||||
// into the default case that this is a code we don't know how to handle.
|
||||
case winapi.JOB_OBJECT_MSG_END_OF_JOB_TIME:
|
||||
case winapi.JOB_OBJECT_MSG_END_OF_PROCESS_TIME:
|
||||
case winapi.JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT:
|
||||
case winapi.JOB_OBJECT_MSG_NEW_PROCESS:
|
||||
case winapi.JOB_OBJECT_MSG_EXIT_PROCESS:
|
||||
case winapi.JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
|
||||
case winapi.JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT:
|
||||
case winapi.JOB_OBJECT_MSG_JOB_MEMORY_LIMIT:
|
||||
case winapi.JOB_OBJECT_MSG_NOTIFICATION_LIMIT:
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown job notification type: %d", code)
|
||||
}
|
||||
return MsgUnimplemented{}, nil
|
||||
}
|
||||
|
||||
// Assigns an IO completion port to get notified of events for the registered job
|
||||
// object.
|
||||
func attachIOCP(job windows.Handle, iocp windows.Handle) error {
|
||||
info := winapi.JOBOBJECT_ASSOCIATE_COMPLETION_PORT{
|
||||
CompletionKey: job,
|
||||
CompletionPort: iocp,
|
||||
}
|
||||
_, err := windows.SetInformationJobObject(job, windows.JobObjectAssociateCompletionPortInformation, uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
|
||||
return err
|
||||
}
|
||||
499
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/jobobject/jobobject.go
generated
vendored
Normal file
499
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/jobobject/jobobject.go
generated
vendored
Normal file
@@ -0,0 +1,499 @@
|
||||
package jobobject
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/queue"
|
||||
"github.com/Microsoft/hcsshim/internal/winapi"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// This file provides higher level constructs for the win32 job object API.
|
||||
// Most of the core creation and management functions are already present in "golang.org/x/sys/windows"
|
||||
// (CreateJobObject, AssignProcessToJobObject, etc.) as well as most of the limit information
|
||||
// structs and associated limit flags. Whatever is not present from the job object API
|
||||
// in golang.org/x/sys/windows is located in /internal/winapi.
|
||||
//
|
||||
// https://docs.microsoft.com/en-us/windows/win32/procthread/job-objects
|
||||
|
||||
// JobObject is a high level wrapper around a Windows job object. Holds a handle to
|
||||
// the job, a queue to receive iocp notifications about the lifecycle
|
||||
// of the job and a mutex for synchronized handle access.
|
||||
type JobObject struct {
|
||||
handle windows.Handle
|
||||
mq *queue.MessageQueue
|
||||
handleLock sync.RWMutex
|
||||
}
|
||||
|
||||
// JobLimits represents the resource constraints that can be applied to a job object.
|
||||
type JobLimits struct {
|
||||
CPULimit uint32
|
||||
CPUWeight uint32
|
||||
MemoryLimitInBytes uint64
|
||||
MaxIOPS int64
|
||||
MaxBandwidth int64
|
||||
}
|
||||
|
||||
type CPURateControlType uint32
|
||||
|
||||
const (
|
||||
WeightBased CPURateControlType = iota
|
||||
RateBased
|
||||
)
|
||||
|
||||
// Processor resource controls
|
||||
const (
|
||||
cpuLimitMin = 1
|
||||
cpuLimitMax = 10000
|
||||
cpuWeightMin = 1
|
||||
cpuWeightMax = 9
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAlreadyClosed = errors.New("the handle has already been closed")
|
||||
ErrNotRegistered = errors.New("job is not registered to receive notifications")
|
||||
)
|
||||
|
||||
// Options represents the set of configurable options when making or opening a job object.
|
||||
type Options struct {
|
||||
// `Name` specifies the name of the job object if a named job object is desired.
|
||||
Name string
|
||||
// `Notifications` specifies if the job will be registered to receive notifications.
|
||||
// Defaults to false.
|
||||
Notifications bool
|
||||
// `UseNTVariant` specifies if we should use the `Nt` variant of Open/CreateJobObject.
|
||||
// Defaults to false.
|
||||
UseNTVariant bool
|
||||
}
|
||||
|
||||
// Create creates a job object.
|
||||
//
|
||||
// If options.Name is an empty string, the job will not be assigned a name.
|
||||
//
|
||||
// If options.Notifications are not enabled `PollNotifications` will return immediately with error `errNotRegistered`.
|
||||
//
|
||||
// If `options` is nil, use default option values.
|
||||
//
|
||||
// Returns a JobObject structure and an error if there is one.
|
||||
func Create(ctx context.Context, options *Options) (_ *JobObject, err error) {
|
||||
if options == nil {
|
||||
options = &Options{}
|
||||
}
|
||||
|
||||
var jobName *winapi.UnicodeString
|
||||
if options.Name != "" {
|
||||
jobName, err = winapi.NewUnicodeString(options.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var jobHandle windows.Handle
|
||||
if options.UseNTVariant {
|
||||
oa := winapi.ObjectAttributes{
|
||||
Length: unsafe.Sizeof(winapi.ObjectAttributes{}),
|
||||
ObjectName: jobName,
|
||||
Attributes: 0,
|
||||
}
|
||||
status := winapi.NtCreateJobObject(&jobHandle, winapi.JOB_OBJECT_ALL_ACCESS, &oa)
|
||||
if status != 0 {
|
||||
return nil, winapi.RtlNtStatusToDosError(status)
|
||||
}
|
||||
} else {
|
||||
var jobNameBuf *uint16
|
||||
if jobName != nil && jobName.Buffer != nil {
|
||||
jobNameBuf = jobName.Buffer
|
||||
}
|
||||
jobHandle, err = windows.CreateJobObject(nil, jobNameBuf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
windows.Close(jobHandle)
|
||||
}
|
||||
}()
|
||||
|
||||
job := &JobObject{
|
||||
handle: jobHandle,
|
||||
}
|
||||
|
||||
// If the IOCP we'll be using to receive messages for all jobs hasn't been
|
||||
// created, create it and start polling.
|
||||
if options.Notifications {
|
||||
mq, err := setupNotifications(ctx, job)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
job.mq = mq
|
||||
}
|
||||
|
||||
return job, nil
|
||||
}
|
||||
|
||||
// Open opens an existing job object with name provided in `options`. If no name is provided
|
||||
// return an error since we need to know what job object to open.
|
||||
//
|
||||
// If options.Notifications is false `PollNotifications` will return immediately with error `errNotRegistered`.
|
||||
//
|
||||
// Returns a JobObject structure and an error if there is one.
|
||||
func Open(ctx context.Context, options *Options) (_ *JobObject, err error) {
|
||||
if options == nil || (options != nil && options.Name == "") {
|
||||
return nil, errors.New("no job object name specified to open")
|
||||
}
|
||||
|
||||
unicodeJobName, err := winapi.NewUnicodeString(options.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var jobHandle windows.Handle
|
||||
if options != nil && options.UseNTVariant {
|
||||
oa := winapi.ObjectAttributes{
|
||||
Length: unsafe.Sizeof(winapi.ObjectAttributes{}),
|
||||
ObjectName: unicodeJobName,
|
||||
Attributes: 0,
|
||||
}
|
||||
status := winapi.NtOpenJobObject(&jobHandle, winapi.JOB_OBJECT_ALL_ACCESS, &oa)
|
||||
if status != 0 {
|
||||
return nil, winapi.RtlNtStatusToDosError(status)
|
||||
}
|
||||
} else {
|
||||
jobHandle, err = winapi.OpenJobObject(winapi.JOB_OBJECT_ALL_ACCESS, false, unicodeJobName.Buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
windows.Close(jobHandle)
|
||||
}
|
||||
}()
|
||||
|
||||
job := &JobObject{
|
||||
handle: jobHandle,
|
||||
}
|
||||
|
||||
// If the IOCP we'll be using to receive messages for all jobs hasn't been
|
||||
// created, create it and start polling.
|
||||
if options != nil && options.Notifications {
|
||||
mq, err := setupNotifications(ctx, job)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
job.mq = mq
|
||||
}
|
||||
|
||||
return job, nil
|
||||
}
|
||||
|
||||
// helper function to setup notifications for creating/opening a job object
|
||||
func setupNotifications(ctx context.Context, job *JobObject) (*queue.MessageQueue, error) {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return nil, ErrAlreadyClosed
|
||||
}
|
||||
|
||||
ioInitOnce.Do(func() {
|
||||
h, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0xffffffff)
|
||||
if err != nil {
|
||||
initIOErr = err
|
||||
return
|
||||
}
|
||||
ioCompletionPort = h
|
||||
go pollIOCP(ctx, h)
|
||||
})
|
||||
|
||||
if initIOErr != nil {
|
||||
return nil, initIOErr
|
||||
}
|
||||
|
||||
mq := queue.NewMessageQueue()
|
||||
jobMap.Store(uintptr(job.handle), mq)
|
||||
if err := attachIOCP(job.handle, ioCompletionPort); err != nil {
|
||||
jobMap.Delete(uintptr(job.handle))
|
||||
return nil, fmt.Errorf("failed to attach job to IO completion port: %w", err)
|
||||
}
|
||||
return mq, nil
|
||||
}
|
||||
|
||||
// PollNotification will poll for a job object notification. This call should only be called once
|
||||
// per job (ideally in a goroutine loop) and will block if there is not a notification ready.
|
||||
// This call will return immediately with error `ErrNotRegistered` if the job was not registered
|
||||
// to receive notifications during `Create`. Internally, messages will be queued and there
|
||||
// is no worry of messages being dropped.
|
||||
func (job *JobObject) PollNotification() (interface{}, error) {
|
||||
if job.mq == nil {
|
||||
return nil, ErrNotRegistered
|
||||
}
|
||||
return job.mq.ReadOrWait()
|
||||
}
|
||||
|
||||
// UpdateProcThreadAttribute updates the passed in ProcThreadAttributeList to contain what is necessary to
|
||||
// launch a process in a job at creation time. This can be used to avoid having to call Assign() after a process
|
||||
// has already started running.
|
||||
func (job *JobObject) UpdateProcThreadAttribute(attrList *windows.ProcThreadAttributeListContainer) error {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return ErrAlreadyClosed
|
||||
}
|
||||
|
||||
if err := attrList.Update(
|
||||
winapi.PROC_THREAD_ATTRIBUTE_JOB_LIST,
|
||||
unsafe.Pointer(&job.handle),
|
||||
unsafe.Sizeof(job.handle),
|
||||
); err != nil {
|
||||
return fmt.Errorf("failed to update proc thread attributes for job object: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the job object handle.
|
||||
func (job *JobObject) Close() error {
|
||||
job.handleLock.Lock()
|
||||
defer job.handleLock.Unlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return ErrAlreadyClosed
|
||||
}
|
||||
|
||||
if err := windows.Close(job.handle); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if job.mq != nil {
|
||||
job.mq.Close()
|
||||
}
|
||||
// Handles now invalid so if the map entry to receive notifications for this job still
|
||||
// exists remove it so we can stop receiving notifications.
|
||||
if _, ok := jobMap.Load(uintptr(job.handle)); ok {
|
||||
jobMap.Delete(uintptr(job.handle))
|
||||
}
|
||||
|
||||
job.handle = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assign assigns a process to the job object.
|
||||
func (job *JobObject) Assign(pid uint32) error {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return ErrAlreadyClosed
|
||||
}
|
||||
|
||||
if pid == 0 {
|
||||
return errors.New("invalid pid: 0")
|
||||
}
|
||||
hProc, err := windows.OpenProcess(winapi.PROCESS_ALL_ACCESS, true, pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer windows.Close(hProc)
|
||||
return windows.AssignProcessToJobObject(job.handle, hProc)
|
||||
}
|
||||
|
||||
// Terminate terminates the job, essentially calls TerminateProcess on every process in the
|
||||
// job.
|
||||
func (job *JobObject) Terminate(exitCode uint32) error {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
if job.handle == 0 {
|
||||
return ErrAlreadyClosed
|
||||
}
|
||||
return windows.TerminateJobObject(job.handle, exitCode)
|
||||
}
|
||||
|
||||
// Pids returns all of the process IDs in the job object.
|
||||
func (job *JobObject) Pids() ([]uint32, error) {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return nil, ErrAlreadyClosed
|
||||
}
|
||||
|
||||
info := winapi.JOBOBJECT_BASIC_PROCESS_ID_LIST{}
|
||||
err := winapi.QueryInformationJobObject(
|
||||
job.handle,
|
||||
winapi.JobObjectBasicProcessIdList,
|
||||
uintptr(unsafe.Pointer(&info)),
|
||||
uint32(unsafe.Sizeof(info)),
|
||||
nil,
|
||||
)
|
||||
|
||||
// This is either the case where there is only one process or no processes in
|
||||
// the job. Any other case will result in ERROR_MORE_DATA. Check if info.NumberOfProcessIdsInList
|
||||
// is 1 and just return this, otherwise return an empty slice.
|
||||
if err == nil {
|
||||
if info.NumberOfProcessIdsInList == 1 {
|
||||
return []uint32{uint32(info.ProcessIdList[0])}, nil
|
||||
}
|
||||
// Return empty slice instead of nil to play well with the caller of this.
|
||||
// Do not return an error if no processes are running inside the job
|
||||
return []uint32{}, nil
|
||||
}
|
||||
|
||||
if err != winapi.ERROR_MORE_DATA {
|
||||
return nil, fmt.Errorf("failed initial query for PIDs in job object: %w", err)
|
||||
}
|
||||
|
||||
jobBasicProcessIDListSize := unsafe.Sizeof(info) + (unsafe.Sizeof(info.ProcessIdList[0]) * uintptr(info.NumberOfAssignedProcesses-1))
|
||||
buf := make([]byte, jobBasicProcessIDListSize)
|
||||
if err = winapi.QueryInformationJobObject(
|
||||
job.handle,
|
||||
winapi.JobObjectBasicProcessIdList,
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uint32(len(buf)),
|
||||
nil,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to query for PIDs in job object: %w", err)
|
||||
}
|
||||
|
||||
bufInfo := (*winapi.JOBOBJECT_BASIC_PROCESS_ID_LIST)(unsafe.Pointer(&buf[0]))
|
||||
pids := make([]uint32, bufInfo.NumberOfProcessIdsInList)
|
||||
for i, bufPid := range bufInfo.AllPids() {
|
||||
pids[i] = uint32(bufPid)
|
||||
}
|
||||
return pids, nil
|
||||
}
|
||||
|
||||
// QueryMemoryStats gets the memory stats for the job object.
|
||||
func (job *JobObject) QueryMemoryStats() (*winapi.JOBOBJECT_MEMORY_USAGE_INFORMATION, error) {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return nil, ErrAlreadyClosed
|
||||
}
|
||||
|
||||
info := winapi.JOBOBJECT_MEMORY_USAGE_INFORMATION{}
|
||||
if err := winapi.QueryInformationJobObject(
|
||||
job.handle,
|
||||
winapi.JobObjectMemoryUsageInformation,
|
||||
uintptr(unsafe.Pointer(&info)),
|
||||
uint32(unsafe.Sizeof(info)),
|
||||
nil,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to query for job object memory stats: %w", err)
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// QueryProcessorStats gets the processor stats for the job object.
|
||||
func (job *JobObject) QueryProcessorStats() (*winapi.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION, error) {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return nil, ErrAlreadyClosed
|
||||
}
|
||||
|
||||
info := winapi.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION{}
|
||||
if err := winapi.QueryInformationJobObject(
|
||||
job.handle,
|
||||
winapi.JobObjectBasicAccountingInformation,
|
||||
uintptr(unsafe.Pointer(&info)),
|
||||
uint32(unsafe.Sizeof(info)),
|
||||
nil,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to query for job object process stats: %w", err)
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// QueryStorageStats gets the storage (I/O) stats for the job object.
|
||||
func (job *JobObject) QueryStorageStats() (*winapi.JOBOBJECT_IO_ATTRIBUTION_INFORMATION, error) {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return nil, ErrAlreadyClosed
|
||||
}
|
||||
|
||||
info := winapi.JOBOBJECT_IO_ATTRIBUTION_INFORMATION{
|
||||
ControlFlags: winapi.JOBOBJECT_IO_ATTRIBUTION_CONTROL_ENABLE,
|
||||
}
|
||||
if err := winapi.QueryInformationJobObject(
|
||||
job.handle,
|
||||
winapi.JobObjectIoAttribution,
|
||||
uintptr(unsafe.Pointer(&info)),
|
||||
uint32(unsafe.Sizeof(info)),
|
||||
nil,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("failed to query for job object storage stats: %w", err)
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// QueryPrivateWorkingSet returns the private working set size for the job. This is calculated by adding up the
|
||||
// private working set for every process running in the job.
|
||||
func (job *JobObject) QueryPrivateWorkingSet() (uint64, error) {
|
||||
pids, err := job.Pids()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
openAndQueryWorkingSet := func(pid uint32) (uint64, error) {
|
||||
h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
|
||||
if err != nil {
|
||||
// Continue to the next if OpenProcess doesn't return a valid handle (fails). Handles a
|
||||
// case where one of the pids in the job exited before we open.
|
||||
return 0, nil
|
||||
}
|
||||
defer func() {
|
||||
_ = windows.Close(h)
|
||||
}()
|
||||
// Check if the process is actually running in the job still. There's a small chance
|
||||
// that the process could have exited and had its pid re-used between grabbing the pids
|
||||
// in the job and opening the handle to it above.
|
||||
var inJob int32
|
||||
if err := winapi.IsProcessInJob(h, job.handle, &inJob); err != nil {
|
||||
// This shouldn't fail unless we have incorrect access rights which we control
|
||||
// here so probably best to error out if this failed.
|
||||
return 0, err
|
||||
}
|
||||
// Don't report stats for this process as it's not running in the job. This shouldn't be
|
||||
// an error condition though.
|
||||
if inJob == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var vmCounters winapi.VM_COUNTERS_EX2
|
||||
status := winapi.NtQueryInformationProcess(
|
||||
h,
|
||||
winapi.ProcessVmCounters,
|
||||
uintptr(unsafe.Pointer(&vmCounters)),
|
||||
uint32(unsafe.Sizeof(vmCounters)),
|
||||
nil,
|
||||
)
|
||||
if !winapi.NTSuccess(status) {
|
||||
return 0, fmt.Errorf("failed to query information for process: %w", winapi.RtlNtStatusToDosError(status))
|
||||
}
|
||||
return uint64(vmCounters.PrivateWorkingSetSize), nil
|
||||
}
|
||||
|
||||
var jobWorkingSetSize uint64
|
||||
for _, pid := range pids {
|
||||
workingSet, err := openAndQueryWorkingSet(pid)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
jobWorkingSetSize += workingSet
|
||||
}
|
||||
|
||||
return jobWorkingSetSize, nil
|
||||
}
|
||||
315
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/jobobject/limits.go
generated
vendored
Normal file
315
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/jobobject/limits.go
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
package jobobject
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/winapi"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
memoryLimitMax uint64 = 0xffffffffffffffff
|
||||
)
|
||||
|
||||
func isFlagSet(flag, controlFlags uint32) bool {
|
||||
return (flag & controlFlags) == flag
|
||||
}
|
||||
|
||||
// SetResourceLimits sets resource limits on the job object (cpu, memory, storage).
|
||||
func (job *JobObject) SetResourceLimits(limits *JobLimits) error {
|
||||
// Go through and check what limits were specified and apply them to the job.
|
||||
if limits.MemoryLimitInBytes != 0 {
|
||||
if err := job.SetMemoryLimit(limits.MemoryLimitInBytes); err != nil {
|
||||
return fmt.Errorf("failed to set job object memory limit: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if limits.CPULimit != 0 {
|
||||
if err := job.SetCPULimit(RateBased, limits.CPULimit); err != nil {
|
||||
return fmt.Errorf("failed to set job object cpu limit: %w", err)
|
||||
}
|
||||
} else if limits.CPUWeight != 0 {
|
||||
if err := job.SetCPULimit(WeightBased, limits.CPUWeight); err != nil {
|
||||
return fmt.Errorf("failed to set job object cpu limit: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if limits.MaxBandwidth != 0 || limits.MaxIOPS != 0 {
|
||||
if err := job.SetIOLimit(limits.MaxBandwidth, limits.MaxIOPS); err != nil {
|
||||
return fmt.Errorf("failed to set io limit on job object: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetTerminateOnLastHandleClose sets the job object flag that specifies that the job should terminate
|
||||
// all processes in the job on the last open handle being closed.
|
||||
func (job *JobObject) SetTerminateOnLastHandleClose() error {
|
||||
info, err := job.getExtendedInformation()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
||||
return job.setExtendedInformation(info)
|
||||
}
|
||||
|
||||
// SetMemoryLimit sets the memory limit of the job object based on the given `memoryLimitInBytes`.
|
||||
func (job *JobObject) SetMemoryLimit(memoryLimitInBytes uint64) error {
|
||||
if memoryLimitInBytes >= memoryLimitMax {
|
||||
return errors.New("memory limit specified exceeds the max size")
|
||||
}
|
||||
|
||||
info, err := job.getExtendedInformation()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info.JobMemoryLimit = uintptr(memoryLimitInBytes)
|
||||
info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_JOB_MEMORY
|
||||
return job.setExtendedInformation(info)
|
||||
}
|
||||
|
||||
// GetMemoryLimit gets the memory limit in bytes of the job object.
|
||||
func (job *JobObject) GetMemoryLimit() (uint64, error) {
|
||||
info, err := job.getExtendedInformation()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(info.JobMemoryLimit), nil
|
||||
}
|
||||
|
||||
// SetCPULimit sets the CPU limit depending on the specified `CPURateControlType` to
|
||||
// `rateControlValue` for the job object.
|
||||
func (job *JobObject) SetCPULimit(rateControlType CPURateControlType, rateControlValue uint32) error {
|
||||
cpuInfo, err := job.getCPURateControlInformation()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch rateControlType {
|
||||
case WeightBased:
|
||||
if rateControlValue < cpuWeightMin || rateControlValue > cpuWeightMax {
|
||||
return fmt.Errorf("processor weight value of `%d` is invalid", rateControlValue)
|
||||
}
|
||||
cpuInfo.ControlFlags |= winapi.JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | winapi.JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED
|
||||
cpuInfo.Value = rateControlValue
|
||||
case RateBased:
|
||||
if rateControlValue < cpuLimitMin || rateControlValue > cpuLimitMax {
|
||||
return fmt.Errorf("processor rate of `%d` is invalid", rateControlValue)
|
||||
}
|
||||
cpuInfo.ControlFlags |= winapi.JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | winapi.JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP
|
||||
cpuInfo.Value = rateControlValue
|
||||
default:
|
||||
return errors.New("invalid job object cpu rate control type")
|
||||
}
|
||||
return job.setCPURateControlInfo(cpuInfo)
|
||||
}
|
||||
|
||||
// GetCPULimit gets the cpu limits for the job object.
|
||||
// `rateControlType` is used to indicate what type of cpu limit to query for.
|
||||
func (job *JobObject) GetCPULimit(rateControlType CPURateControlType) (uint32, error) {
|
||||
info, err := job.getCPURateControlInformation()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !isFlagSet(winapi.JOB_OBJECT_CPU_RATE_CONTROL_ENABLE, info.ControlFlags) {
|
||||
return 0, errors.New("the job does not have cpu rate control enabled")
|
||||
}
|
||||
|
||||
switch rateControlType {
|
||||
case WeightBased:
|
||||
if !isFlagSet(winapi.JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED, info.ControlFlags) {
|
||||
return 0, errors.New("cannot get cpu weight for job object without cpu weight option set")
|
||||
}
|
||||
case RateBased:
|
||||
if !isFlagSet(winapi.JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP, info.ControlFlags) {
|
||||
return 0, errors.New("cannot get cpu rate hard cap for job object without cpu rate hard cap option set")
|
||||
}
|
||||
default:
|
||||
return 0, errors.New("invalid job object cpu rate control type")
|
||||
}
|
||||
return info.Value, nil
|
||||
}
|
||||
|
||||
// SetCPUAffinity sets the processor affinity for the job object.
|
||||
// The affinity is passed in as a bitmask.
|
||||
func (job *JobObject) SetCPUAffinity(affinityBitMask uint64) error {
|
||||
info, err := job.getExtendedInformation()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info.BasicLimitInformation.LimitFlags |= uint32(windows.JOB_OBJECT_LIMIT_AFFINITY)
|
||||
info.BasicLimitInformation.Affinity = uintptr(affinityBitMask)
|
||||
return job.setExtendedInformation(info)
|
||||
}
|
||||
|
||||
// GetCPUAffinity gets the processor affinity for the job object.
|
||||
// The returned affinity is a bitmask.
|
||||
func (job *JobObject) GetCPUAffinity() (uint64, error) {
|
||||
info, err := job.getExtendedInformation()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(info.BasicLimitInformation.Affinity), nil
|
||||
}
|
||||
|
||||
// SetIOLimit sets the IO limits specified on the job object.
|
||||
func (job *JobObject) SetIOLimit(maxBandwidth, maxIOPS int64) error {
|
||||
ioInfo, err := job.getIOLimit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ioInfo.ControlFlags |= winapi.JOB_OBJECT_IO_RATE_CONTROL_ENABLE
|
||||
if maxBandwidth != 0 {
|
||||
ioInfo.MaxBandwidth = maxBandwidth
|
||||
}
|
||||
if maxIOPS != 0 {
|
||||
ioInfo.MaxIops = maxIOPS
|
||||
}
|
||||
return job.setIORateControlInfo(ioInfo)
|
||||
}
|
||||
|
||||
// GetIOMaxBandwidthLimit gets the max bandwidth for the job object.
|
||||
func (job *JobObject) GetIOMaxBandwidthLimit() (int64, error) {
|
||||
info, err := job.getIOLimit()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return info.MaxBandwidth, nil
|
||||
}
|
||||
|
||||
// GetIOMaxIopsLimit gets the max iops for the job object.
|
||||
func (job *JobObject) GetIOMaxIopsLimit() (int64, error) {
|
||||
info, err := job.getIOLimit()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return info.MaxIops, nil
|
||||
}
|
||||
|
||||
// Helper function for getting a job object's extended information.
|
||||
func (job *JobObject) getExtendedInformation() (*windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION, error) {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return nil, ErrAlreadyClosed
|
||||
}
|
||||
|
||||
info := windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION{}
|
||||
if err := winapi.QueryInformationJobObject(
|
||||
job.handle,
|
||||
windows.JobObjectExtendedLimitInformation,
|
||||
uintptr(unsafe.Pointer(&info)),
|
||||
uint32(unsafe.Sizeof(info)),
|
||||
nil,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("query %v returned error: %w", info, err)
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// Helper function for getting a job object's CPU rate control information.
|
||||
func (job *JobObject) getCPURateControlInformation() (*winapi.JOBOBJECT_CPU_RATE_CONTROL_INFORMATION, error) {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return nil, ErrAlreadyClosed
|
||||
}
|
||||
|
||||
info := winapi.JOBOBJECT_CPU_RATE_CONTROL_INFORMATION{}
|
||||
if err := winapi.QueryInformationJobObject(
|
||||
job.handle,
|
||||
windows.JobObjectCpuRateControlInformation,
|
||||
uintptr(unsafe.Pointer(&info)),
|
||||
uint32(unsafe.Sizeof(info)),
|
||||
nil,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("query %v returned error: %w", info, err)
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// Helper function for setting a job object's extended information.
|
||||
func (job *JobObject) setExtendedInformation(info *windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION) error {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return ErrAlreadyClosed
|
||||
}
|
||||
|
||||
if _, err := windows.SetInformationJobObject(
|
||||
job.handle,
|
||||
windows.JobObjectExtendedLimitInformation,
|
||||
uintptr(unsafe.Pointer(info)),
|
||||
uint32(unsafe.Sizeof(*info)),
|
||||
); err != nil {
|
||||
return fmt.Errorf("failed to set Extended info %v on job object: %w", info, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper function for querying job handle for IO limit information.
|
||||
func (job *JobObject) getIOLimit() (*winapi.JOBOBJECT_IO_RATE_CONTROL_INFORMATION, error) {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return nil, ErrAlreadyClosed
|
||||
}
|
||||
|
||||
ioInfo := &winapi.JOBOBJECT_IO_RATE_CONTROL_INFORMATION{}
|
||||
var blockCount uint32 = 1
|
||||
|
||||
if _, err := winapi.QueryIoRateControlInformationJobObject(
|
||||
job.handle,
|
||||
nil,
|
||||
&ioInfo,
|
||||
&blockCount,
|
||||
); err != nil {
|
||||
return nil, fmt.Errorf("query %v returned error: %w", ioInfo, err)
|
||||
}
|
||||
|
||||
if !isFlagSet(winapi.JOB_OBJECT_IO_RATE_CONTROL_ENABLE, ioInfo.ControlFlags) {
|
||||
return nil, fmt.Errorf("query %v cannot get IO limits for job object without IO rate control option set", ioInfo)
|
||||
}
|
||||
return ioInfo, nil
|
||||
}
|
||||
|
||||
// Helper function for setting a job object's IO rate control information.
|
||||
func (job *JobObject) setIORateControlInfo(ioInfo *winapi.JOBOBJECT_IO_RATE_CONTROL_INFORMATION) error {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return ErrAlreadyClosed
|
||||
}
|
||||
|
||||
if _, err := winapi.SetIoRateControlInformationJobObject(job.handle, ioInfo); err != nil {
|
||||
return fmt.Errorf("failed to set IO limit info %v on job object: %w", ioInfo, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper function for setting a job object's CPU rate control information.
|
||||
func (job *JobObject) setCPURateControlInfo(cpuInfo *winapi.JOBOBJECT_CPU_RATE_CONTROL_INFORMATION) error {
|
||||
job.handleLock.RLock()
|
||||
defer job.handleLock.RUnlock()
|
||||
|
||||
if job.handle == 0 {
|
||||
return ErrAlreadyClosed
|
||||
}
|
||||
if _, err := windows.SetInformationJobObject(
|
||||
job.handle,
|
||||
windows.JobObjectCpuRateControlInformation,
|
||||
uintptr(unsafe.Pointer(cpuInfo)),
|
||||
uint32(unsafe.Sizeof(cpuInfo)),
|
||||
); err != nil {
|
||||
return fmt.Errorf("failed to set cpu limit info %v on job object: %w", cpuInfo, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
111
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/queue/mq.go
generated
vendored
Normal file
111
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/queue/mq.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrQueueClosed = errors.New("the queue is closed for reading and writing")
|
||||
ErrQueueEmpty = errors.New("the queue is empty")
|
||||
)
|
||||
|
||||
// MessageQueue represents a threadsafe message queue to be used to retrieve or
|
||||
// write messages to.
|
||||
type MessageQueue struct {
|
||||
m *sync.RWMutex
|
||||
c *sync.Cond
|
||||
messages []interface{}
|
||||
closed bool
|
||||
}
|
||||
|
||||
// NewMessageQueue returns a new MessageQueue.
|
||||
func NewMessageQueue() *MessageQueue {
|
||||
m := &sync.RWMutex{}
|
||||
return &MessageQueue{
|
||||
m: m,
|
||||
c: sync.NewCond(m),
|
||||
messages: []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes `msg` to the queue.
|
||||
func (mq *MessageQueue) Write(msg interface{}) error {
|
||||
mq.m.Lock()
|
||||
defer mq.m.Unlock()
|
||||
|
||||
if mq.closed {
|
||||
return ErrQueueClosed
|
||||
}
|
||||
mq.messages = append(mq.messages, msg)
|
||||
// Signal a waiter that there is now a value available in the queue.
|
||||
mq.c.Signal()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read will read a value from the queue if available, otherwise return an error.
|
||||
func (mq *MessageQueue) Read() (interface{}, error) {
|
||||
mq.m.Lock()
|
||||
defer mq.m.Unlock()
|
||||
if mq.closed {
|
||||
return nil, ErrQueueClosed
|
||||
}
|
||||
if mq.isEmpty() {
|
||||
return nil, ErrQueueEmpty
|
||||
}
|
||||
val := mq.messages[0]
|
||||
mq.messages[0] = nil
|
||||
mq.messages = mq.messages[1:]
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// ReadOrWait will read a value from the queue if available, else it will wait for a
|
||||
// value to become available. This will block forever if nothing gets written or until
|
||||
// the queue gets closed.
|
||||
func (mq *MessageQueue) ReadOrWait() (interface{}, error) {
|
||||
mq.m.Lock()
|
||||
if mq.closed {
|
||||
mq.m.Unlock()
|
||||
return nil, ErrQueueClosed
|
||||
}
|
||||
if mq.isEmpty() {
|
||||
for !mq.closed && mq.isEmpty() {
|
||||
mq.c.Wait()
|
||||
}
|
||||
mq.m.Unlock()
|
||||
return mq.Read()
|
||||
}
|
||||
val := mq.messages[0]
|
||||
mq.messages[0] = nil
|
||||
mq.messages = mq.messages[1:]
|
||||
mq.m.Unlock()
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// IsEmpty returns if the queue is empty
|
||||
func (mq *MessageQueue) IsEmpty() bool {
|
||||
mq.m.RLock()
|
||||
defer mq.m.RUnlock()
|
||||
return len(mq.messages) == 0
|
||||
}
|
||||
|
||||
// Nonexported empty check that doesn't lock so we can call this in Read and Write.
|
||||
func (mq *MessageQueue) isEmpty() bool {
|
||||
return len(mq.messages) == 0
|
||||
}
|
||||
|
||||
// Close closes the queue for future writes or reads. Any attempts to read or write from the
|
||||
// queue after close will return ErrQueueClosed. This is safe to call multiple times.
|
||||
func (mq *MessageQueue) Close() {
|
||||
mq.m.Lock()
|
||||
defer mq.m.Unlock()
|
||||
// Already closed
|
||||
if mq.closed {
|
||||
return
|
||||
}
|
||||
mq.messages = nil
|
||||
mq.closed = true
|
||||
// If there's anybody currently waiting on a value from ReadOrWait, we need to
|
||||
// broadcast so the read(s) can return ErrQueueClosed.
|
||||
mq.c.Broadcast()
|
||||
}
|
||||
3
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/iocp.go
generated
vendored
3
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/iocp.go
generated
vendored
@@ -1,3 +0,0 @@
|
||||
package winapi
|
||||
|
||||
//sys GetQueuedCompletionStatus(cphandle windows.Handle, qty *uint32, key *uintptr, overlapped **windows.Overlapped, timeout uint32) (err error)
|
||||
9
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go
generated
vendored
9
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/jobobject.go
generated
vendored
@@ -24,7 +24,10 @@ const (
|
||||
// Access rights for creating or opening job objects.
|
||||
//
|
||||
// https://docs.microsoft.com/en-us/windows/win32/procthread/job-object-security-and-access-rights
|
||||
const JOB_OBJECT_ALL_ACCESS = 0x1F001F
|
||||
const (
|
||||
JOB_OBJECT_QUERY = 0x0004
|
||||
JOB_OBJECT_ALL_ACCESS = 0x1F001F
|
||||
)
|
||||
|
||||
// IO limit flags
|
||||
//
|
||||
@@ -93,7 +96,7 @@ type JOBOBJECT_BASIC_PROCESS_ID_LIST struct {
|
||||
|
||||
// AllPids returns all the process Ids in the job object.
|
||||
func (p *JOBOBJECT_BASIC_PROCESS_ID_LIST) AllPids() []uintptr {
|
||||
return (*[(1 << 27) - 1]uintptr)(unsafe.Pointer(&p.ProcessIdList[0]))[:p.NumberOfProcessIdsInList]
|
||||
return (*[(1 << 27) - 1]uintptr)(unsafe.Pointer(&p.ProcessIdList[0]))[:p.NumberOfProcessIdsInList:p.NumberOfProcessIdsInList]
|
||||
}
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-jobobject_basic_accounting_information
|
||||
@@ -162,7 +165,7 @@ type JOBOBJECT_ASSOCIATE_COMPLETION_PORT struct {
|
||||
// PBOOL Result
|
||||
// );
|
||||
//
|
||||
//sys IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *bool) (err error) = kernel32.IsProcessInJob
|
||||
//sys IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *int32) (err error) = kernel32.IsProcessInJob
|
||||
|
||||
// BOOL QueryInformationJobObject(
|
||||
// HANDLE hJob,
|
||||
|
||||
57
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go
generated
vendored
57
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/process.go
generated
vendored
@@ -6,3 +6,60 @@ const (
|
||||
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x20016
|
||||
PROC_THREAD_ATTRIBUTE_JOB_LIST = 0x2000D
|
||||
)
|
||||
|
||||
// ProcessVmCounters corresponds to the _VM_COUNTERS_EX and _VM_COUNTERS_EX2 structures.
|
||||
const ProcessVmCounters = 3
|
||||
|
||||
// __kernel_entry NTSTATUS NtQueryInformationProcess(
|
||||
// [in] HANDLE ProcessHandle,
|
||||
// [in] PROCESSINFOCLASS ProcessInformationClass,
|
||||
// [out] PVOID ProcessInformation,
|
||||
// [in] ULONG ProcessInformationLength,
|
||||
// [out, optional] PULONG ReturnLength
|
||||
// );
|
||||
//
|
||||
//sys NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo uintptr, processInfoLength uint32, returnLength *uint32) (status uint32) = ntdll.NtQueryInformationProcess
|
||||
|
||||
// typedef struct _VM_COUNTERS_EX
|
||||
// {
|
||||
// SIZE_T PeakVirtualSize;
|
||||
// SIZE_T VirtualSize;
|
||||
// ULONG PageFaultCount;
|
||||
// SIZE_T PeakWorkingSetSize;
|
||||
// SIZE_T WorkingSetSize;
|
||||
// SIZE_T QuotaPeakPagedPoolUsage;
|
||||
// SIZE_T QuotaPagedPoolUsage;
|
||||
// SIZE_T QuotaPeakNonPagedPoolUsage;
|
||||
// SIZE_T QuotaNonPagedPoolUsage;
|
||||
// SIZE_T PagefileUsage;
|
||||
// SIZE_T PeakPagefileUsage;
|
||||
// SIZE_T PrivateUsage;
|
||||
// } VM_COUNTERS_EX, *PVM_COUNTERS_EX;
|
||||
//
|
||||
type VM_COUNTERS_EX struct {
|
||||
PeakVirtualSize uintptr
|
||||
VirtualSize uintptr
|
||||
PageFaultCount uint32
|
||||
PeakWorkingSetSize uintptr
|
||||
WorkingSetSize uintptr
|
||||
QuotaPeakPagedPoolUsage uintptr
|
||||
QuotaPagedPoolUsage uintptr
|
||||
QuotaPeakNonPagedPoolUsage uintptr
|
||||
QuotaNonPagedPoolUsage uintptr
|
||||
PagefileUsage uintptr
|
||||
PeakPagefileUsage uintptr
|
||||
PrivateUsage uintptr
|
||||
}
|
||||
|
||||
// typedef struct _VM_COUNTERS_EX2
|
||||
// {
|
||||
// VM_COUNTERS_EX CountersEx;
|
||||
// SIZE_T PrivateWorkingSetSize;
|
||||
// SIZE_T SharedCommitUsage;
|
||||
// } VM_COUNTERS_EX2, *PVM_COUNTERS_EX2;
|
||||
//
|
||||
type VM_COUNTERS_EX2 struct {
|
||||
CountersEx VM_COUNTERS_EX
|
||||
PrivateWorkingSetSize uintptr
|
||||
SharedCommitUsage uintptr
|
||||
}
|
||||
|
||||
2
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go
generated
vendored
2
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/winapi.go
generated
vendored
@@ -2,4 +2,4 @@
|
||||
// be thought of as an extension to golang.org/x/sys/windows.
|
||||
package winapi
|
||||
|
||||
//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go console.go system.go net.go path.go thread.go iocp.go jobobject.go logon.go memory.go process.go processor.go devices.go filesystem.go errors.go
|
||||
//go:generate go run ..\..\mksyscall_windows.go -output zsyscall_windows.go user.go console.go system.go net.go path.go thread.go jobobject.go logon.go memory.go process.go processor.go devices.go filesystem.go errors.go
|
||||
|
||||
22
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go
generated
vendored
22
src/runtime/vendor/github.com/Microsoft/hcsshim/internal/winapi/zsyscall_windows.go
generated
vendored
@@ -50,7 +50,6 @@ var (
|
||||
procSetJobCompartmentId = modiphlpapi.NewProc("SetJobCompartmentId")
|
||||
procSearchPathW = modkernel32.NewProc("SearchPathW")
|
||||
procCreateRemoteThread = modkernel32.NewProc("CreateRemoteThread")
|
||||
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
|
||||
procIsProcessInJob = modkernel32.NewProc("IsProcessInJob")
|
||||
procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject")
|
||||
procOpenJobObjectW = modkernel32.NewProc("OpenJobObjectW")
|
||||
@@ -61,6 +60,7 @@ var (
|
||||
procLogonUserW = modadvapi32.NewProc("LogonUserW")
|
||||
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
|
||||
procLocalFree = modkernel32.NewProc("LocalFree")
|
||||
procNtQueryInformationProcess = modntdll.NewProc("NtQueryInformationProcess")
|
||||
procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount")
|
||||
procCM_Get_Device_ID_List_SizeA = modcfgmgr32.NewProc("CM_Get_Device_ID_List_SizeA")
|
||||
procCM_Get_Device_ID_ListA = modcfgmgr32.NewProc("CM_Get_Device_ID_ListA")
|
||||
@@ -140,19 +140,7 @@ func CreateRemoteThread(process windows.Handle, sa *windows.SecurityAttributes,
|
||||
return
|
||||
}
|
||||
|
||||
func GetQueuedCompletionStatus(cphandle windows.Handle, qty *uint32, key *uintptr, overlapped **windows.Overlapped, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *bool) (err error) {
|
||||
func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result *int32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procIsProcessInJob.Addr(), 3, uintptr(procHandle), uintptr(jobHandle), uintptr(unsafe.Pointer(result)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
@@ -256,6 +244,12 @@ func LocalFree(ptr uintptr) {
|
||||
return
|
||||
}
|
||||
|
||||
func NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo uintptr, processInfoLength uint32, returnLength *uint32) (status uint32) {
|
||||
r0, _, _ := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(processHandle), uintptr(processInfoClass), uintptr(processInfo), uintptr(processInfoLength), uintptr(unsafe.Pointer(returnLength)), 0)
|
||||
status = uint32(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func GetActiveProcessorCount(groupNumber uint16) (amount uint32) {
|
||||
r0, _, _ := syscall.Syscall(procGetActiveProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0)
|
||||
amount = uint32(r0)
|
||||
|
||||
1
src/runtime/vendor/github.com/cilium/ebpf/.gitignore
generated
vendored
1
src/runtime/vendor/github.com/cilium/ebpf/.gitignore
generated
vendored
@@ -5,6 +5,7 @@
|
||||
*.so
|
||||
*.dylib
|
||||
*.o
|
||||
!*_bpf*.o
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
1
src/runtime/vendor/github.com/cilium/ebpf/.golangci.yaml
generated
vendored
1
src/runtime/vendor/github.com/cilium/ebpf/.golangci.yaml
generated
vendored
@@ -24,6 +24,5 @@ linters:
|
||||
|
||||
# Could be enabled later:
|
||||
# - gocyclo
|
||||
# - prealloc
|
||||
# - maligned
|
||||
# - gosec
|
||||
|
||||
4
src/runtime/vendor/github.com/cilium/ebpf/ARCHITECTURE.md
generated
vendored
4
src/runtime/vendor/github.com/cilium/ebpf/ARCHITECTURE.md
generated
vendored
@@ -57,7 +57,7 @@ Objects
|
||||
loading a spec will fail because the kernel is too old, or a feature is not
|
||||
enabled. There are multiple ways the library deals with that:
|
||||
|
||||
* Fallback: older kernels don't allowing naming programs and maps. The library
|
||||
* Fallback: older kernels don't allow naming programs and maps. The library
|
||||
automatically detects support for names, and omits them during load if
|
||||
necessary. This works since name is primarily a debug aid.
|
||||
|
||||
@@ -68,7 +68,7 @@ enabled. There are multiple ways the library deals with that:
|
||||
Once program and map objects are loaded they expose the kernel's low-level API,
|
||||
e.g. `NextKey`. Often this API is awkward to use in Go, so there are safer
|
||||
wrappers on top of the low-level API, like `MapIterator`. The low-level API is
|
||||
useful as an out when our higher-level API doesn't support a particular use case.
|
||||
useful when our higher-level API doesn't support a particular use case.
|
||||
|
||||
Links
|
||||
---
|
||||
|
||||
4
src/runtime/vendor/github.com/cilium/ebpf/CONTRIBUTING.md
generated
vendored
4
src/runtime/vendor/github.com/cilium/ebpf/CONTRIBUTING.md
generated
vendored
@@ -6,8 +6,8 @@ are welcome. Please take a look at [the architecture](ARCHITECTURE.md) to get
|
||||
a better understanding for the high-level goals.
|
||||
|
||||
New features must be accompanied by tests. Before starting work on any large
|
||||
feature, please [join](https://cilium.herokuapp.com/) the
|
||||
[#libbpf-go](https://cilium.slack.com/messages/libbpf-go) channel on Slack to
|
||||
feature, please [join](https://ebpf.io/slack) the
|
||||
[#ebpf-go](https://cilium.slack.com/messages/ebpf-go) channel on Slack to
|
||||
discuss the design first.
|
||||
|
||||
When submitting pull requests, consider writing details about what problem you
|
||||
|
||||
5
src/runtime/vendor/github.com/cilium/ebpf/Makefile
generated
vendored
5
src/runtime/vendor/github.com/cilium/ebpf/Makefile
generated
vendored
@@ -18,11 +18,14 @@ TARGETS := \
|
||||
testdata/loader-clang-7 \
|
||||
testdata/loader-clang-9 \
|
||||
testdata/loader-$(CLANG) \
|
||||
testdata/btf_map_init \
|
||||
testdata/invalid_map \
|
||||
testdata/raw_tracepoint \
|
||||
testdata/invalid_map_static \
|
||||
testdata/initialized_btf_map \
|
||||
testdata/invalid_btf_map_init \
|
||||
testdata/strings \
|
||||
testdata/freplace \
|
||||
testdata/iproute2_map_compat \
|
||||
internal/btf/testdata/relocs
|
||||
|
||||
.PHONY: all clean docker-all docker-shell
|
||||
|
||||
62
src/runtime/vendor/github.com/cilium/ebpf/README.md
generated
vendored
62
src/runtime/vendor/github.com/cilium/ebpf/README.md
generated
vendored
@@ -2,28 +2,16 @@
|
||||
|
||||
[](https://pkg.go.dev/github.com/cilium/ebpf)
|
||||
|
||||

|
||||
|
||||
eBPF is a pure Go library that provides utilities for loading, compiling, and
|
||||
debugging eBPF programs. It has minimal external dependencies and is intended to
|
||||
be used in long running processes.
|
||||
|
||||
* [asm](https://pkg.go.dev/github.com/cilium/ebpf/asm) contains a basic
|
||||
assembler
|
||||
* [link](https://pkg.go.dev/github.com/cilium/ebpf/link) allows attaching eBPF
|
||||
to various hooks
|
||||
* [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a
|
||||
`PERF_EVENT_ARRAY`
|
||||
* [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows
|
||||
compiling and embedding eBPF programs in Go code
|
||||
|
||||
The library is maintained by [Cloudflare](https://www.cloudflare.com) and
|
||||
[Cilium](https://www.cilium.io). Feel free to
|
||||
[join](https://cilium.herokuapp.com/) the
|
||||
[#libbpf-go](https://cilium.slack.com/messages/libbpf-go) channel on Slack.
|
||||
[Cilium](https://www.cilium.io).
|
||||
|
||||
## Current status
|
||||
|
||||
The package is production ready, but **the API is explicitly unstable right
|
||||
now**. Expect to update your code if you want to follow along.
|
||||
See [ebpf.io](https://ebpf.io) for other projects from the eBPF ecosystem.
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -33,21 +21,37 @@ your own tools can be found under [examples/](examples/).
|
||||
Contributions are highly encouraged, as they highlight certain use cases of
|
||||
eBPF and the library, and help shape the future of the project.
|
||||
|
||||
## Getting Help
|
||||
|
||||
Please
|
||||
[join](https://ebpf.io/slack) the
|
||||
[#ebpf-go](https://cilium.slack.com/messages/ebpf-go) channel on Slack if you
|
||||
have questions regarding the library.
|
||||
|
||||
## Packages
|
||||
|
||||
This library includes the following packages:
|
||||
|
||||
* [asm](https://pkg.go.dev/github.com/cilium/ebpf/asm) contains a basic
|
||||
assembler, allowing you to write eBPF assembly instructions directly
|
||||
within your Go code. (You don't need to use this if you prefer to write your eBPF program in C.)
|
||||
* [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows
|
||||
compiling and embedding eBPF programs written in C within Go code. As well as
|
||||
compiling the C code, it auto-generates Go code for loading and manipulating
|
||||
the eBPF program and map objects.
|
||||
* [link](https://pkg.go.dev/github.com/cilium/ebpf/link) allows attaching eBPF
|
||||
to various hooks
|
||||
* [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a
|
||||
`PERF_EVENT_ARRAY`
|
||||
* [ringbuf](https://pkg.go.dev/github.com/cilium/ebpf/ringbuf) allows reading from a
|
||||
`BPF_MAP_TYPE_RINGBUF` map
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
* A version of Go that is [supported by
|
||||
upstream](https://golang.org/doc/devel/release.html#policy)
|
||||
* Linux 4.9, 4.19 or 5.4 (versions in-between should work, but are not tested)
|
||||
|
||||
## Useful resources
|
||||
|
||||
* [eBPF.io](https://ebpf.io) (recommended)
|
||||
* [Cilium eBPF documentation](https://docs.cilium.io/en/latest/bpf/#bpf-guide)
|
||||
(recommended)
|
||||
* [Linux documentation on
|
||||
BPF](https://www.kernel.org/doc/html/latest/networking/filter.html)
|
||||
* [eBPF features by Linux
|
||||
version](https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md)
|
||||
* Linux >= 4.9. CI is run against LTS releases.
|
||||
|
||||
## Regenerating Testdata
|
||||
|
||||
@@ -60,3 +64,7 @@ The toolchain image build files are kept in [testdata/docker/](testdata/docker/)
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
### eBPF Gopher
|
||||
|
||||
The eBPF honeygopher is based on the Go gopher designed by Renee French.
|
||||
|
||||
6
src/runtime/vendor/github.com/cilium/ebpf/asm/func.go
generated
vendored
6
src/runtime/vendor/github.com/cilium/ebpf/asm/func.go
generated
vendored
@@ -184,6 +184,12 @@ const (
|
||||
FnKtimeGetCoarseNs
|
||||
FnImaInodeHash
|
||||
FnSockFromFile
|
||||
FnCheckMtu
|
||||
FnForEachMapElem
|
||||
FnSnprintf
|
||||
FnSysBpf
|
||||
FnBtfFindByNameKind
|
||||
FnSysClose
|
||||
)
|
||||
|
||||
// Call emits a function call.
|
||||
|
||||
10
src/runtime/vendor/github.com/cilium/ebpf/asm/func_string.go
generated
vendored
10
src/runtime/vendor/github.com/cilium/ebpf/asm/func_string.go
generated
vendored
@@ -171,11 +171,17 @@ func _() {
|
||||
_ = x[FnKtimeGetCoarseNs-160]
|
||||
_ = x[FnImaInodeHash-161]
|
||||
_ = x[FnSockFromFile-162]
|
||||
_ = x[FnCheckMtu-163]
|
||||
_ = x[FnForEachMapElem-164]
|
||||
_ = x[FnSnprintf-165]
|
||||
_ = x[FnSysBpf-166]
|
||||
_ = x[FnBtfFindByNameKind-167]
|
||||
_ = x[FnSysClose-168]
|
||||
}
|
||||
|
||||
const _BuiltinFunc_name = "FnUnspecFnMapLookupElemFnMapUpdateElemFnMapDeleteElemFnProbeReadFnKtimeGetNsFnTracePrintkFnGetPrandomU32FnGetSmpProcessorIdFnSkbStoreBytesFnL3CsumReplaceFnL4CsumReplaceFnTailCallFnCloneRedirectFnGetCurrentPidTgidFnGetCurrentUidGidFnGetCurrentCommFnGetCgroupClassidFnSkbVlanPushFnSkbVlanPopFnSkbGetTunnelKeyFnSkbSetTunnelKeyFnPerfEventReadFnRedirectFnGetRouteRealmFnPerfEventOutputFnSkbLoadBytesFnGetStackidFnCsumDiffFnSkbGetTunnelOptFnSkbSetTunnelOptFnSkbChangeProtoFnSkbChangeTypeFnSkbUnderCgroupFnGetHashRecalcFnGetCurrentTaskFnProbeWriteUserFnCurrentTaskUnderCgroupFnSkbChangeTailFnSkbPullDataFnCsumUpdateFnSetHashInvalidFnGetNumaNodeIdFnSkbChangeHeadFnXdpAdjustHeadFnProbeReadStrFnGetSocketCookieFnGetSocketUidFnSetHashFnSetsockoptFnSkbAdjustRoomFnRedirectMapFnSkRedirectMapFnSockMapUpdateFnXdpAdjustMetaFnPerfEventReadValueFnPerfProgReadValueFnGetsockoptFnOverrideReturnFnSockOpsCbFlagsSetFnMsgRedirectMapFnMsgApplyBytesFnMsgCorkBytesFnMsgPullDataFnBindFnXdpAdjustTailFnSkbGetXfrmStateFnGetStackFnSkbLoadBytesRelativeFnFibLookupFnSockHashUpdateFnMsgRedirectHashFnSkRedirectHashFnLwtPushEncapFnLwtSeg6StoreBytesFnLwtSeg6AdjustSrhFnLwtSeg6ActionFnRcRepeatFnRcKeydownFnSkbCgroupIdFnGetCurrentCgroupIdFnGetLocalStorageFnSkSelectReuseportFnSkbAncestorCgroupIdFnSkLookupTcpFnSkLookupUdpFnSkReleaseFnMapPushElemFnMapPopElemFnMapPeekElemFnMsgPushDataFnMsgPopDataFnRcPointerRelFnSpinLockFnSpinUnlockFnSkFullsockFnTcpSockFnSkbEcnSetCeFnGetListenerSockFnSkcLookupTcpFnTcpCheckSyncookieFnSysctlGetNameFnSysctlGetCurrentValueFnSysctlGetNewValueFnSysctlSetNewValueFnStrtolFnStrtoulFnSkStorageGetFnSkStorageDeleteFnSendSignalFnTcpGenSyncookieFnSkbOutputFnProbeReadUserFnProbeReadKernelFnProbeReadUserStrFnProbeReadKernelStrFnTcpSendAckFnSendSignalThreadFnJiffies64FnReadBranchRecordsFnGetNsCurrentPidTgidFnXdpOutputFnGetNetnsCookieFnGetCurrentAncestorCgroupIdFnSkAssignFnKtimeGetBootNsFnSeqPrintfFnSeqWriteFnSkCgroupIdFnSkAncestorCgroupIdFnRingbufOutputFnRingbufReserveFnRingbufSubmitFnRingbufDiscardFnRingbufQueryFnCsumLevelFnSkcToTcp6SockFnSkcToTcpSockFnSkcToTcpTimewaitSockFnSkcToTcpRequestSockFnSkcToUdp6SockFnGetTaskStackFnLoadHdrOptFnStoreHdrOptFnReserveHdrOptFnInodeStorageGetFnInodeStorageDeleteFnDPathFnCopyFromUserFnSnprintfBtfFnSeqPrintfBtfFnSkbCgroupClassidFnRedirectNeighFnPerCpuPtrFnThisCpuPtrFnRedirectPeerFnTaskStorageGetFnTaskStorageDeleteFnGetCurrentTaskBtfFnBprmOptsSetFnKtimeGetCoarseNsFnImaInodeHashFnSockFromFile"
|
||||
const _BuiltinFunc_name = "FnUnspecFnMapLookupElemFnMapUpdateElemFnMapDeleteElemFnProbeReadFnKtimeGetNsFnTracePrintkFnGetPrandomU32FnGetSmpProcessorIdFnSkbStoreBytesFnL3CsumReplaceFnL4CsumReplaceFnTailCallFnCloneRedirectFnGetCurrentPidTgidFnGetCurrentUidGidFnGetCurrentCommFnGetCgroupClassidFnSkbVlanPushFnSkbVlanPopFnSkbGetTunnelKeyFnSkbSetTunnelKeyFnPerfEventReadFnRedirectFnGetRouteRealmFnPerfEventOutputFnSkbLoadBytesFnGetStackidFnCsumDiffFnSkbGetTunnelOptFnSkbSetTunnelOptFnSkbChangeProtoFnSkbChangeTypeFnSkbUnderCgroupFnGetHashRecalcFnGetCurrentTaskFnProbeWriteUserFnCurrentTaskUnderCgroupFnSkbChangeTailFnSkbPullDataFnCsumUpdateFnSetHashInvalidFnGetNumaNodeIdFnSkbChangeHeadFnXdpAdjustHeadFnProbeReadStrFnGetSocketCookieFnGetSocketUidFnSetHashFnSetsockoptFnSkbAdjustRoomFnRedirectMapFnSkRedirectMapFnSockMapUpdateFnXdpAdjustMetaFnPerfEventReadValueFnPerfProgReadValueFnGetsockoptFnOverrideReturnFnSockOpsCbFlagsSetFnMsgRedirectMapFnMsgApplyBytesFnMsgCorkBytesFnMsgPullDataFnBindFnXdpAdjustTailFnSkbGetXfrmStateFnGetStackFnSkbLoadBytesRelativeFnFibLookupFnSockHashUpdateFnMsgRedirectHashFnSkRedirectHashFnLwtPushEncapFnLwtSeg6StoreBytesFnLwtSeg6AdjustSrhFnLwtSeg6ActionFnRcRepeatFnRcKeydownFnSkbCgroupIdFnGetCurrentCgroupIdFnGetLocalStorageFnSkSelectReuseportFnSkbAncestorCgroupIdFnSkLookupTcpFnSkLookupUdpFnSkReleaseFnMapPushElemFnMapPopElemFnMapPeekElemFnMsgPushDataFnMsgPopDataFnRcPointerRelFnSpinLockFnSpinUnlockFnSkFullsockFnTcpSockFnSkbEcnSetCeFnGetListenerSockFnSkcLookupTcpFnTcpCheckSyncookieFnSysctlGetNameFnSysctlGetCurrentValueFnSysctlGetNewValueFnSysctlSetNewValueFnStrtolFnStrtoulFnSkStorageGetFnSkStorageDeleteFnSendSignalFnTcpGenSyncookieFnSkbOutputFnProbeReadUserFnProbeReadKernelFnProbeReadUserStrFnProbeReadKernelStrFnTcpSendAckFnSendSignalThreadFnJiffies64FnReadBranchRecordsFnGetNsCurrentPidTgidFnXdpOutputFnGetNetnsCookieFnGetCurrentAncestorCgroupIdFnSkAssignFnKtimeGetBootNsFnSeqPrintfFnSeqWriteFnSkCgroupIdFnSkAncestorCgroupIdFnRingbufOutputFnRingbufReserveFnRingbufSubmitFnRingbufDiscardFnRingbufQueryFnCsumLevelFnSkcToTcp6SockFnSkcToTcpSockFnSkcToTcpTimewaitSockFnSkcToTcpRequestSockFnSkcToUdp6SockFnGetTaskStackFnLoadHdrOptFnStoreHdrOptFnReserveHdrOptFnInodeStorageGetFnInodeStorageDeleteFnDPathFnCopyFromUserFnSnprintfBtfFnSeqPrintfBtfFnSkbCgroupClassidFnRedirectNeighFnPerCpuPtrFnThisCpuPtrFnRedirectPeerFnTaskStorageGetFnTaskStorageDeleteFnGetCurrentTaskBtfFnBprmOptsSetFnKtimeGetCoarseNsFnImaInodeHashFnSockFromFileFnCheckMtuFnForEachMapElemFnSnprintfFnSysBpfFnBtfFindByNameKindFnSysClose"
|
||||
|
||||
var _BuiltinFunc_index = [...]uint16{0, 8, 23, 38, 53, 64, 76, 89, 104, 123, 138, 153, 168, 178, 193, 212, 230, 246, 264, 277, 289, 306, 323, 338, 348, 363, 380, 394, 406, 416, 433, 450, 466, 481, 497, 512, 528, 544, 568, 583, 596, 608, 624, 639, 654, 669, 683, 700, 714, 723, 735, 750, 763, 778, 793, 808, 828, 847, 859, 875, 894, 910, 925, 939, 952, 958, 973, 990, 1000, 1022, 1033, 1049, 1066, 1082, 1096, 1115, 1133, 1148, 1158, 1169, 1182, 1202, 1219, 1238, 1259, 1272, 1285, 1296, 1309, 1321, 1334, 1347, 1359, 1373, 1383, 1395, 1407, 1416, 1429, 1446, 1460, 1479, 1494, 1517, 1536, 1555, 1563, 1572, 1586, 1603, 1615, 1632, 1643, 1658, 1675, 1693, 1713, 1725, 1743, 1754, 1773, 1794, 1805, 1821, 1849, 1859, 1875, 1886, 1896, 1908, 1928, 1943, 1959, 1974, 1990, 2004, 2015, 2030, 2044, 2066, 2087, 2102, 2116, 2128, 2141, 2156, 2173, 2193, 2200, 2214, 2227, 2241, 2259, 2274, 2285, 2297, 2311, 2327, 2346, 2365, 2378, 2396, 2410, 2424}
|
||||
var _BuiltinFunc_index = [...]uint16{0, 8, 23, 38, 53, 64, 76, 89, 104, 123, 138, 153, 168, 178, 193, 212, 230, 246, 264, 277, 289, 306, 323, 338, 348, 363, 380, 394, 406, 416, 433, 450, 466, 481, 497, 512, 528, 544, 568, 583, 596, 608, 624, 639, 654, 669, 683, 700, 714, 723, 735, 750, 763, 778, 793, 808, 828, 847, 859, 875, 894, 910, 925, 939, 952, 958, 973, 990, 1000, 1022, 1033, 1049, 1066, 1082, 1096, 1115, 1133, 1148, 1158, 1169, 1182, 1202, 1219, 1238, 1259, 1272, 1285, 1296, 1309, 1321, 1334, 1347, 1359, 1373, 1383, 1395, 1407, 1416, 1429, 1446, 1460, 1479, 1494, 1517, 1536, 1555, 1563, 1572, 1586, 1603, 1615, 1632, 1643, 1658, 1675, 1693, 1713, 1725, 1743, 1754, 1773, 1794, 1805, 1821, 1849, 1859, 1875, 1886, 1896, 1908, 1928, 1943, 1959, 1974, 1990, 2004, 2015, 2030, 2044, 2066, 2087, 2102, 2116, 2128, 2141, 2156, 2173, 2193, 2200, 2214, 2227, 2241, 2259, 2274, 2285, 2297, 2311, 2327, 2346, 2365, 2378, 2396, 2410, 2424, 2434, 2450, 2460, 2468, 2487, 2497}
|
||||
|
||||
func (i BuiltinFunc) String() string {
|
||||
if i < 0 || i >= BuiltinFunc(len(_BuiltinFunc_index)-1) {
|
||||
|
||||
5
src/runtime/vendor/github.com/cilium/ebpf/asm/instruction.go
generated
vendored
5
src/runtime/vendor/github.com/cilium/ebpf/asm/instruction.go
generated
vendored
@@ -181,6 +181,11 @@ func (ins *Instruction) IsFunctionCall() bool {
|
||||
return ins.OpCode.JumpOp() == Call && ins.Src == PseudoCall
|
||||
}
|
||||
|
||||
// IsBuiltinCall returns true if the instruction is a built-in call, i.e. BPF helper call.
|
||||
func (ins *Instruction) IsBuiltinCall() bool {
|
||||
return ins.OpCode.JumpOp() == Call && ins.Src == R0 && ins.Dst == R0
|
||||
}
|
||||
|
||||
// IsConstantLoad returns true if the instruction loads a constant of the
|
||||
// given size.
|
||||
func (ins *Instruction) IsConstantLoad(size Size) bool {
|
||||
|
||||
65
src/runtime/vendor/github.com/cilium/ebpf/attachtype_string.go
generated
vendored
Normal file
65
src/runtime/vendor/github.com/cilium/ebpf/attachtype_string.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Code generated by "stringer -type AttachType -trimprefix Attach"; DO NOT EDIT.
|
||||
|
||||
package ebpf
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[AttachNone-0]
|
||||
_ = x[AttachCGroupInetIngress-0]
|
||||
_ = x[AttachCGroupInetEgress-1]
|
||||
_ = x[AttachCGroupInetSockCreate-2]
|
||||
_ = x[AttachCGroupSockOps-3]
|
||||
_ = x[AttachSkSKBStreamParser-4]
|
||||
_ = x[AttachSkSKBStreamVerdict-5]
|
||||
_ = x[AttachCGroupDevice-6]
|
||||
_ = x[AttachSkMsgVerdict-7]
|
||||
_ = x[AttachCGroupInet4Bind-8]
|
||||
_ = x[AttachCGroupInet6Bind-9]
|
||||
_ = x[AttachCGroupInet4Connect-10]
|
||||
_ = x[AttachCGroupInet6Connect-11]
|
||||
_ = x[AttachCGroupInet4PostBind-12]
|
||||
_ = x[AttachCGroupInet6PostBind-13]
|
||||
_ = x[AttachCGroupUDP4Sendmsg-14]
|
||||
_ = x[AttachCGroupUDP6Sendmsg-15]
|
||||
_ = x[AttachLircMode2-16]
|
||||
_ = x[AttachFlowDissector-17]
|
||||
_ = x[AttachCGroupSysctl-18]
|
||||
_ = x[AttachCGroupUDP4Recvmsg-19]
|
||||
_ = x[AttachCGroupUDP6Recvmsg-20]
|
||||
_ = x[AttachCGroupGetsockopt-21]
|
||||
_ = x[AttachCGroupSetsockopt-22]
|
||||
_ = x[AttachTraceRawTp-23]
|
||||
_ = x[AttachTraceFEntry-24]
|
||||
_ = x[AttachTraceFExit-25]
|
||||
_ = x[AttachModifyReturn-26]
|
||||
_ = x[AttachLSMMac-27]
|
||||
_ = x[AttachTraceIter-28]
|
||||
_ = x[AttachCgroupInet4GetPeername-29]
|
||||
_ = x[AttachCgroupInet6GetPeername-30]
|
||||
_ = x[AttachCgroupInet4GetSockname-31]
|
||||
_ = x[AttachCgroupInet6GetSockname-32]
|
||||
_ = x[AttachXDPDevMap-33]
|
||||
_ = x[AttachCgroupInetSockRelease-34]
|
||||
_ = x[AttachXDPCPUMap-35]
|
||||
_ = x[AttachSkLookup-36]
|
||||
_ = x[AttachXDP-37]
|
||||
_ = x[AttachSkSKBVerdict-38]
|
||||
_ = x[AttachSkReuseportSelect-39]
|
||||
_ = x[AttachSkReuseportSelectOrMigrate-40]
|
||||
_ = x[AttachPerfEvent-41]
|
||||
}
|
||||
|
||||
const _AttachType_name = "NoneCGroupInetEgressCGroupInetSockCreateCGroupSockOpsSkSKBStreamParserSkSKBStreamVerdictCGroupDeviceSkMsgVerdictCGroupInet4BindCGroupInet6BindCGroupInet4ConnectCGroupInet6ConnectCGroupInet4PostBindCGroupInet6PostBindCGroupUDP4SendmsgCGroupUDP6SendmsgLircMode2FlowDissectorCGroupSysctlCGroupUDP4RecvmsgCGroupUDP6RecvmsgCGroupGetsockoptCGroupSetsockoptTraceRawTpTraceFEntryTraceFExitModifyReturnLSMMacTraceIterCgroupInet4GetPeernameCgroupInet6GetPeernameCgroupInet4GetSocknameCgroupInet6GetSocknameXDPDevMapCgroupInetSockReleaseXDPCPUMapSkLookupXDPSkSKBVerdictSkReuseportSelectSkReuseportSelectOrMigratePerfEvent"
|
||||
|
||||
var _AttachType_index = [...]uint16{0, 4, 20, 40, 53, 70, 88, 100, 112, 127, 142, 160, 178, 197, 216, 233, 250, 259, 272, 284, 301, 318, 334, 350, 360, 371, 381, 393, 399, 408, 430, 452, 474, 496, 505, 526, 535, 543, 546, 558, 575, 601, 610}
|
||||
|
||||
func (i AttachType) String() string {
|
||||
if i >= AttachType(len(_AttachType_index)-1) {
|
||||
return "AttachType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _AttachType_name[_AttachType_index[i]:_AttachType_index[i+1]]
|
||||
}
|
||||
532
src/runtime/vendor/github.com/cilium/ebpf/collection.go
generated
vendored
532
src/runtime/vendor/github.com/cilium/ebpf/collection.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package ebpf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -25,6 +26,10 @@ type CollectionOptions struct {
|
||||
type CollectionSpec struct {
|
||||
Maps map[string]*MapSpec
|
||||
Programs map[string]*ProgramSpec
|
||||
|
||||
// ByteOrder specifies whether the ELF was compiled for
|
||||
// big-endian or little-endian architectures.
|
||||
ByteOrder binary.ByteOrder
|
||||
}
|
||||
|
||||
// Copy returns a recursive copy of the spec.
|
||||
@@ -34,8 +39,9 @@ func (cs *CollectionSpec) Copy() *CollectionSpec {
|
||||
}
|
||||
|
||||
cpy := CollectionSpec{
|
||||
Maps: make(map[string]*MapSpec, len(cs.Maps)),
|
||||
Programs: make(map[string]*ProgramSpec, len(cs.Programs)),
|
||||
Maps: make(map[string]*MapSpec, len(cs.Maps)),
|
||||
Programs: make(map[string]*ProgramSpec, len(cs.Programs)),
|
||||
ByteOrder: cs.ByteOrder,
|
||||
}
|
||||
|
||||
for name, spec := range cs.Maps {
|
||||
@@ -123,7 +129,7 @@ func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error
|
||||
buf := make([]byte, len(value))
|
||||
copy(buf, value)
|
||||
|
||||
err := patchValue(buf, btf.MapValue(rodata.BTF), consts)
|
||||
err := patchValue(buf, rodata.BTF.Value, consts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -134,15 +140,15 @@ func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error
|
||||
|
||||
// Assign the contents of a CollectionSpec to a struct.
|
||||
//
|
||||
// This function is a short-cut to manually checking the presence
|
||||
// of maps and programs in a collection spec. Consider using bpf2go if this
|
||||
// sounds useful.
|
||||
// This function is a shortcut to manually checking the presence
|
||||
// of maps and programs in a CollectionSpec. Consider using bpf2go
|
||||
// if this sounds useful.
|
||||
//
|
||||
// The argument to must be a pointer to a struct. A field of the
|
||||
// 'to' must be a pointer to a struct. A field of the
|
||||
// struct is updated with values from Programs or Maps if it
|
||||
// has an `ebpf` tag and its type is *ProgramSpec or *MapSpec.
|
||||
// The tag gives the name of the program or map as found in
|
||||
// the CollectionSpec.
|
||||
// The tag's value specifies the name of the program or map as
|
||||
// found in the CollectionSpec.
|
||||
//
|
||||
// struct {
|
||||
// Foo *ebpf.ProgramSpec `ebpf:"xdp_foo"`
|
||||
@@ -150,42 +156,47 @@ func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error
|
||||
// Ignored int
|
||||
// }
|
||||
//
|
||||
// Returns an error if any of the fields can't be found, or
|
||||
// if the same map or program is assigned multiple times.
|
||||
// Returns an error if any of the eBPF objects can't be found, or
|
||||
// if the same MapSpec or ProgramSpec is assigned multiple times.
|
||||
func (cs *CollectionSpec) Assign(to interface{}) error {
|
||||
valueOf := func(typ reflect.Type, name string) (reflect.Value, error) {
|
||||
// Assign() only supports assigning ProgramSpecs and MapSpecs,
|
||||
// so doesn't load any resources into the kernel.
|
||||
getValue := func(typ reflect.Type, name string) (interface{}, error) {
|
||||
switch typ {
|
||||
|
||||
case reflect.TypeOf((*ProgramSpec)(nil)):
|
||||
p := cs.Programs[name]
|
||||
if p == nil {
|
||||
return reflect.Value{}, fmt.Errorf("missing program %q", name)
|
||||
if p := cs.Programs[name]; p != nil {
|
||||
return p, nil
|
||||
}
|
||||
return reflect.ValueOf(p), nil
|
||||
return nil, fmt.Errorf("missing program %q", name)
|
||||
|
||||
case reflect.TypeOf((*MapSpec)(nil)):
|
||||
m := cs.Maps[name]
|
||||
if m == nil {
|
||||
return reflect.Value{}, fmt.Errorf("missing map %q", name)
|
||||
if m := cs.Maps[name]; m != nil {
|
||||
return m, nil
|
||||
}
|
||||
return reflect.ValueOf(m), nil
|
||||
return nil, fmt.Errorf("missing map %q", name)
|
||||
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("unsupported type %s", typ)
|
||||
return nil, fmt.Errorf("unsupported type %s", typ)
|
||||
}
|
||||
}
|
||||
|
||||
return assignValues(to, valueOf)
|
||||
return assignValues(to, getValue)
|
||||
}
|
||||
|
||||
// LoadAndAssign maps and programs into the kernel and assign them to a struct.
|
||||
// LoadAndAssign loads Maps and Programs into the kernel and assigns them
|
||||
// to a struct.
|
||||
//
|
||||
// This function is a short-cut to manually checking the presence
|
||||
// of maps and programs in a collection spec. Consider using bpf2go if this
|
||||
// sounds useful.
|
||||
// This function is a shortcut to manually checking the presence
|
||||
// of maps and programs in a CollectionSpec. Consider using bpf2go
|
||||
// if this sounds useful.
|
||||
//
|
||||
// The argument to must be a pointer to a struct. A field of the
|
||||
// struct is updated with values from Programs or Maps if it
|
||||
// has an `ebpf` tag and its type is *Program or *Map.
|
||||
// The tag gives the name of the program or map as found in
|
||||
// the CollectionSpec.
|
||||
// 'to' must be a pointer to a struct. A field of the struct is updated with
|
||||
// a Program or Map if it has an `ebpf` tag and its type is *Program or *Map.
|
||||
// The tag's value specifies the name of the program or map as found in the
|
||||
// CollectionSpec. Before updating the struct, the requested objects and their
|
||||
// dependent resources are loaded into the kernel and populated with values if
|
||||
// specified.
|
||||
//
|
||||
// struct {
|
||||
// Foo *ebpf.Program `ebpf:"xdp_foo"`
|
||||
@@ -196,39 +207,53 @@ func (cs *CollectionSpec) Assign(to interface{}) error {
|
||||
// opts may be nil.
|
||||
//
|
||||
// Returns an error if any of the fields can't be found, or
|
||||
// if the same map or program is assigned multiple times.
|
||||
// if the same Map or Program is assigned multiple times.
|
||||
func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions) error {
|
||||
if opts == nil {
|
||||
opts = &CollectionOptions{}
|
||||
}
|
||||
loader := newCollectionLoader(cs, opts)
|
||||
defer loader.cleanup()
|
||||
|
||||
loadMap, loadProgram, done, cleanup := lazyLoadCollection(cs, opts)
|
||||
defer cleanup()
|
||||
|
||||
valueOf := func(typ reflect.Type, name string) (reflect.Value, error) {
|
||||
// Support assigning Programs and Maps, lazy-loading the required objects.
|
||||
assignedMaps := make(map[string]bool)
|
||||
getValue := func(typ reflect.Type, name string) (interface{}, error) {
|
||||
switch typ {
|
||||
|
||||
case reflect.TypeOf((*Program)(nil)):
|
||||
p, err := loadProgram(name)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
return reflect.ValueOf(p), nil
|
||||
return loader.loadProgram(name)
|
||||
|
||||
case reflect.TypeOf((*Map)(nil)):
|
||||
m, err := loadMap(name)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
return reflect.ValueOf(m), nil
|
||||
assignedMaps[name] = true
|
||||
return loader.loadMap(name)
|
||||
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("unsupported type %s", typ)
|
||||
return nil, fmt.Errorf("unsupported type %s", typ)
|
||||
}
|
||||
}
|
||||
|
||||
if err := assignValues(to, valueOf); err != nil {
|
||||
// Load the Maps and Programs requested by the annotated struct.
|
||||
if err := assignValues(to, getValue); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
done()
|
||||
// Populate the requested maps. Has a chance of lazy-loading other dependent maps.
|
||||
if err := loader.populateMaps(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Evaluate the loader's objects after all (lazy)loading has taken place.
|
||||
for n, m := range loader.maps {
|
||||
switch m.typ {
|
||||
case ProgramArray:
|
||||
// Require all lazy-loaded ProgramArrays to be assigned to the given object.
|
||||
// Without any references, they will be closed on the first GC and all tail
|
||||
// calls into them will miss.
|
||||
if !assignedMaps[n] {
|
||||
return fmt.Errorf("ProgramArray %s must be assigned to prevent missed tail calls", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loader.finalize()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -246,24 +271,32 @@ func NewCollection(spec *CollectionSpec) (*Collection, error) {
|
||||
|
||||
// NewCollectionWithOptions creates a Collection from a specification.
|
||||
func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Collection, error) {
|
||||
loadMap, loadProgram, done, cleanup := lazyLoadCollection(spec, &opts)
|
||||
defer cleanup()
|
||||
loader := newCollectionLoader(spec, &opts)
|
||||
defer loader.cleanup()
|
||||
|
||||
// Create maps first, as their fds need to be linked into programs.
|
||||
for mapName := range spec.Maps {
|
||||
_, err := loadMap(mapName)
|
||||
if err != nil {
|
||||
if _, err := loader.loadMap(mapName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for progName := range spec.Programs {
|
||||
_, err := loadProgram(progName)
|
||||
if err != nil {
|
||||
if _, err := loader.loadProgram(progName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
maps, progs := done()
|
||||
// Maps can contain Program and Map stubs, so populate them after
|
||||
// all Maps and Programs have been successfully loaded.
|
||||
if err := loader.populateMaps(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maps, progs := loader.maps, loader.programs
|
||||
|
||||
loader.finalize()
|
||||
|
||||
return &Collection{
|
||||
progs,
|
||||
maps,
|
||||
@@ -314,113 +347,154 @@ func (hc handleCache) close() {
|
||||
for _, handle := range hc.btfHandles {
|
||||
handle.Close()
|
||||
}
|
||||
hc.btfHandles = nil
|
||||
hc.btfSpecs = nil
|
||||
}
|
||||
|
||||
func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) (
|
||||
loadMap func(string) (*Map, error),
|
||||
loadProgram func(string) (*Program, error),
|
||||
done func() (map[string]*Map, map[string]*Program),
|
||||
cleanup func(),
|
||||
) {
|
||||
var (
|
||||
maps = make(map[string]*Map)
|
||||
progs = make(map[string]*Program)
|
||||
handles = newHandleCache()
|
||||
skipMapsAndProgs = false
|
||||
)
|
||||
type collectionLoader struct {
|
||||
coll *CollectionSpec
|
||||
opts *CollectionOptions
|
||||
maps map[string]*Map
|
||||
programs map[string]*Program
|
||||
handles *handleCache
|
||||
}
|
||||
|
||||
cleanup = func() {
|
||||
handles.close()
|
||||
|
||||
if skipMapsAndProgs {
|
||||
return
|
||||
}
|
||||
|
||||
for _, m := range maps {
|
||||
m.Close()
|
||||
}
|
||||
|
||||
for _, p := range progs {
|
||||
p.Close()
|
||||
}
|
||||
func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) *collectionLoader {
|
||||
if opts == nil {
|
||||
opts = &CollectionOptions{}
|
||||
}
|
||||
|
||||
done = func() (map[string]*Map, map[string]*Program) {
|
||||
skipMapsAndProgs = true
|
||||
return maps, progs
|
||||
return &collectionLoader{
|
||||
coll,
|
||||
opts,
|
||||
make(map[string]*Map),
|
||||
make(map[string]*Program),
|
||||
newHandleCache(),
|
||||
}
|
||||
}
|
||||
|
||||
loadMap = func(mapName string) (*Map, error) {
|
||||
if m := maps[mapName]; m != nil {
|
||||
return m, nil
|
||||
}
|
||||
// finalize should be called when all the collectionLoader's resources
|
||||
// have been successfully loaded into the kernel and populated with values.
|
||||
func (cl *collectionLoader) finalize() {
|
||||
cl.maps, cl.programs = nil, nil
|
||||
}
|
||||
|
||||
mapSpec := coll.Maps[mapName]
|
||||
if mapSpec == nil {
|
||||
return nil, fmt.Errorf("missing map %s", mapName)
|
||||
}
|
||||
// cleanup cleans up all resources left over in the collectionLoader.
|
||||
// Call finalize() when Map and Program creation/population is successful
|
||||
// to prevent them from getting closed.
|
||||
func (cl *collectionLoader) cleanup() {
|
||||
cl.handles.close()
|
||||
for _, m := range cl.maps {
|
||||
m.Close()
|
||||
}
|
||||
for _, p := range cl.programs {
|
||||
p.Close()
|
||||
}
|
||||
}
|
||||
|
||||
m, err := newMapWithOptions(mapSpec, opts.Maps, handles)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("map %s: %w", mapName, err)
|
||||
}
|
||||
|
||||
maps[mapName] = m
|
||||
func (cl *collectionLoader) loadMap(mapName string) (*Map, error) {
|
||||
if m := cl.maps[mapName]; m != nil {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
loadProgram = func(progName string) (*Program, error) {
|
||||
if prog := progs[progName]; prog != nil {
|
||||
return prog, nil
|
||||
mapSpec := cl.coll.Maps[mapName]
|
||||
if mapSpec == nil {
|
||||
return nil, fmt.Errorf("missing map %s", mapName)
|
||||
}
|
||||
|
||||
m, err := newMapWithOptions(mapSpec, cl.opts.Maps, cl.handles)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("map %s: %w", mapName, err)
|
||||
}
|
||||
|
||||
cl.maps[mapName] = m
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (cl *collectionLoader) loadProgram(progName string) (*Program, error) {
|
||||
if prog := cl.programs[progName]; prog != nil {
|
||||
return prog, nil
|
||||
}
|
||||
|
||||
progSpec := cl.coll.Programs[progName]
|
||||
if progSpec == nil {
|
||||
return nil, fmt.Errorf("unknown program %s", progName)
|
||||
}
|
||||
|
||||
progSpec = progSpec.Copy()
|
||||
|
||||
// Rewrite any reference to a valid map.
|
||||
for i := range progSpec.Instructions {
|
||||
ins := &progSpec.Instructions[i]
|
||||
|
||||
if !ins.IsLoadFromMap() || ins.Reference == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
progSpec := coll.Programs[progName]
|
||||
if progSpec == nil {
|
||||
return nil, fmt.Errorf("unknown program %s", progName)
|
||||
if uint32(ins.Constant) != math.MaxUint32 {
|
||||
// Don't overwrite maps already rewritten, users can
|
||||
// rewrite programs in the spec themselves
|
||||
continue
|
||||
}
|
||||
|
||||
progSpec = progSpec.Copy()
|
||||
|
||||
// Rewrite any reference to a valid map.
|
||||
for i := range progSpec.Instructions {
|
||||
ins := &progSpec.Instructions[i]
|
||||
|
||||
if !ins.IsLoadFromMap() || ins.Reference == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if uint32(ins.Constant) != math.MaxUint32 {
|
||||
// Don't overwrite maps already rewritten, users can
|
||||
// rewrite programs in the spec themselves
|
||||
continue
|
||||
}
|
||||
|
||||
m, err := loadMap(ins.Reference)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("program %s: %w", progName, err)
|
||||
}
|
||||
|
||||
fd := m.FD()
|
||||
if fd < 0 {
|
||||
return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
|
||||
}
|
||||
if err := ins.RewriteMapPtr(m.FD()); err != nil {
|
||||
return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err)
|
||||
}
|
||||
}
|
||||
|
||||
prog, err := newProgramWithOptions(progSpec, opts.Programs, handles)
|
||||
m, err := cl.loadMap(ins.Reference)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("program %s: %w", progName, err)
|
||||
}
|
||||
|
||||
progs[progName] = prog
|
||||
return prog, nil
|
||||
fd := m.FD()
|
||||
if fd < 0 {
|
||||
return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
|
||||
}
|
||||
if err := ins.RewriteMapPtr(m.FD()); err != nil {
|
||||
return nil, fmt.Errorf("program %s: map %s: %w", progName, ins.Reference, err)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
prog, err := newProgramWithOptions(progSpec, cl.opts.Programs, cl.handles)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("program %s: %w", progName, err)
|
||||
}
|
||||
|
||||
cl.programs[progName] = prog
|
||||
return prog, nil
|
||||
}
|
||||
|
||||
func (cl *collectionLoader) populateMaps() error {
|
||||
for mapName, m := range cl.maps {
|
||||
mapSpec, ok := cl.coll.Maps[mapName]
|
||||
if !ok {
|
||||
return fmt.Errorf("missing map spec %s", mapName)
|
||||
}
|
||||
|
||||
mapSpec = mapSpec.Copy()
|
||||
|
||||
// Replace any object stubs with loaded objects.
|
||||
for i, kv := range mapSpec.Contents {
|
||||
switch v := kv.Value.(type) {
|
||||
case programStub:
|
||||
// loadProgram is idempotent and could return an existing Program.
|
||||
prog, err := cl.loadProgram(string(v))
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading program %s, for map %s: %w", v, mapName, err)
|
||||
}
|
||||
mapSpec.Contents[i] = MapKV{kv.Key, prog}
|
||||
|
||||
case mapStub:
|
||||
// loadMap is idempotent and could return an existing Map.
|
||||
innerMap, err := cl.loadMap(string(v))
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading inner map %s, for map %s: %w", v, mapName, err)
|
||||
}
|
||||
mapSpec.Contents[i] = MapKV{kv.Key, innerMap}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate and freeze the map if specified.
|
||||
if err := m.finalize(mapSpec); err != nil {
|
||||
return fmt.Errorf("populating map %s: %w", mapName, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadCollection parses an object file and converts it to a collection.
|
||||
@@ -466,108 +540,81 @@ func (coll *Collection) DetachProgram(name string) *Program {
|
||||
return p
|
||||
}
|
||||
|
||||
// Assign the contents of a collection to a struct.
|
||||
//
|
||||
// Deprecated: use CollectionSpec.Assign instead. It provides the same
|
||||
// functionality but creates only the maps and programs requested.
|
||||
func (coll *Collection) Assign(to interface{}) error {
|
||||
assignedMaps := make(map[string]struct{})
|
||||
assignedPrograms := make(map[string]struct{})
|
||||
valueOf := func(typ reflect.Type, name string) (reflect.Value, error) {
|
||||
switch typ {
|
||||
case reflect.TypeOf((*Program)(nil)):
|
||||
p := coll.Programs[name]
|
||||
if p == nil {
|
||||
return reflect.Value{}, fmt.Errorf("missing program %q", name)
|
||||
}
|
||||
assignedPrograms[name] = struct{}{}
|
||||
return reflect.ValueOf(p), nil
|
||||
case reflect.TypeOf((*Map)(nil)):
|
||||
m := coll.Maps[name]
|
||||
if m == nil {
|
||||
return reflect.Value{}, fmt.Errorf("missing map %q", name)
|
||||
}
|
||||
assignedMaps[name] = struct{}{}
|
||||
return reflect.ValueOf(m), nil
|
||||
default:
|
||||
return reflect.Value{}, fmt.Errorf("unsupported type %s", typ)
|
||||
}
|
||||
}
|
||||
|
||||
if err := assignValues(to, valueOf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for name := range assignedPrograms {
|
||||
coll.DetachProgram(name)
|
||||
}
|
||||
|
||||
for name := range assignedMaps {
|
||||
coll.DetachMap(name)
|
||||
}
|
||||
|
||||
return nil
|
||||
// structField represents a struct field containing the ebpf struct tag.
|
||||
type structField struct {
|
||||
reflect.StructField
|
||||
value reflect.Value
|
||||
}
|
||||
|
||||
func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Value, error)) error {
|
||||
type structField struct {
|
||||
reflect.StructField
|
||||
value reflect.Value
|
||||
// ebpfFields extracts field names tagged with 'ebpf' from a struct type.
|
||||
// Keep track of visited types to avoid infinite recursion.
|
||||
func ebpfFields(structVal reflect.Value, visited map[reflect.Type]bool) ([]structField, error) {
|
||||
if visited == nil {
|
||||
visited = make(map[reflect.Type]bool)
|
||||
}
|
||||
|
||||
var (
|
||||
fields []structField
|
||||
visitedTypes = make(map[reflect.Type]bool)
|
||||
flattenStruct func(reflect.Value) error
|
||||
)
|
||||
structType := structVal.Type()
|
||||
if structType.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("%s is not a struct", structType)
|
||||
}
|
||||
|
||||
flattenStruct = func(structVal reflect.Value) error {
|
||||
structType := structVal.Type()
|
||||
if structType.Kind() != reflect.Struct {
|
||||
return fmt.Errorf("%s is not a struct", structType)
|
||||
if visited[structType] {
|
||||
return nil, fmt.Errorf("recursion on type %s", structType)
|
||||
}
|
||||
|
||||
fields := make([]structField, 0, structType.NumField())
|
||||
for i := 0; i < structType.NumField(); i++ {
|
||||
field := structField{structType.Field(i), structVal.Field(i)}
|
||||
|
||||
// If the field is tagged, gather it and move on.
|
||||
name := field.Tag.Get("ebpf")
|
||||
if name != "" {
|
||||
fields = append(fields, field)
|
||||
continue
|
||||
}
|
||||
|
||||
if visitedTypes[structType] {
|
||||
return fmt.Errorf("recursion on type %s", structType)
|
||||
}
|
||||
|
||||
for i := 0; i < structType.NumField(); i++ {
|
||||
field := structField{structType.Field(i), structVal.Field(i)}
|
||||
|
||||
name := field.Tag.Get("ebpf")
|
||||
if name != "" {
|
||||
fields = append(fields, field)
|
||||
// If the field does not have an ebpf tag, but is a struct or a pointer
|
||||
// to a struct, attempt to gather its fields as well.
|
||||
var v reflect.Value
|
||||
switch field.Type.Kind() {
|
||||
case reflect.Ptr:
|
||||
if field.Type.Elem().Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
|
||||
var err error
|
||||
switch field.Type.Kind() {
|
||||
case reflect.Ptr:
|
||||
if field.Type.Elem().Kind() != reflect.Struct {
|
||||
continue
|
||||
}
|
||||
|
||||
if field.value.IsNil() {
|
||||
return fmt.Errorf("nil pointer to %s", structType)
|
||||
}
|
||||
|
||||
err = flattenStruct(field.value.Elem())
|
||||
|
||||
case reflect.Struct:
|
||||
err = flattenStruct(field.value)
|
||||
|
||||
default:
|
||||
continue
|
||||
if field.value.IsNil() {
|
||||
return nil, fmt.Errorf("nil pointer to %s", structType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("field %s: %w", field.Name, err)
|
||||
}
|
||||
// Obtain the destination type of the pointer.
|
||||
v = field.value.Elem()
|
||||
|
||||
case reflect.Struct:
|
||||
// Reference the value's type directly.
|
||||
v = field.value
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
return nil
|
||||
inner, err := ebpfFields(v, visited)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("field %s: %w", field.Name, err)
|
||||
}
|
||||
|
||||
fields = append(fields, inner...)
|
||||
}
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
// assignValues attempts to populate all fields of 'to' tagged with 'ebpf'.
|
||||
//
|
||||
// getValue is called for every tagged field of 'to' and must return the value
|
||||
// to be assigned to the field with the given typ and name.
|
||||
func assignValues(to interface{},
|
||||
getValue func(typ reflect.Type, name string) (interface{}, error)) error {
|
||||
|
||||
toValue := reflect.ValueOf(to)
|
||||
if toValue.Type().Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("%T is not a pointer to struct", to)
|
||||
@@ -577,7 +624,8 @@ func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Va
|
||||
return fmt.Errorf("nil pointer to %T", to)
|
||||
}
|
||||
|
||||
if err := flattenStruct(toValue.Elem()); err != nil {
|
||||
fields, err := ebpfFields(toValue.Elem(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -587,19 +635,23 @@ func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Va
|
||||
name string
|
||||
}
|
||||
|
||||
assignedTo := make(map[elem]string)
|
||||
assigned := make(map[elem]string)
|
||||
for _, field := range fields {
|
||||
name := field.Tag.Get("ebpf")
|
||||
if strings.Contains(name, ",") {
|
||||
// Get string value the field is tagged with.
|
||||
tag := field.Tag.Get("ebpf")
|
||||
if strings.Contains(tag, ",") {
|
||||
return fmt.Errorf("field %s: ebpf tag contains a comma", field.Name)
|
||||
}
|
||||
|
||||
e := elem{field.Type, name}
|
||||
if assignedField := assignedTo[e]; assignedField != "" {
|
||||
return fmt.Errorf("field %s: %q was already assigned to %s", field.Name, name, assignedField)
|
||||
// Check if the eBPF object with the requested
|
||||
// type and tag was already assigned elsewhere.
|
||||
e := elem{field.Type, tag}
|
||||
if af := assigned[e]; af != "" {
|
||||
return fmt.Errorf("field %s: object %q was already assigned to %s", field.Name, tag, af)
|
||||
}
|
||||
|
||||
value, err := valueOf(field.Type, name)
|
||||
// Get the eBPF object referred to by the tag.
|
||||
value, err := getValue(field.Type, tag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("field %s: %w", field.Name, err)
|
||||
}
|
||||
@@ -607,9 +659,9 @@ func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Va
|
||||
if !field.value.CanSet() {
|
||||
return fmt.Errorf("field %s: can't set value", field.Name)
|
||||
}
|
||||
field.value.Set(reflect.ValueOf(value))
|
||||
|
||||
field.value.Set(value)
|
||||
assignedTo[e] = field.Name
|
||||
assigned[e] = field.Name
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
180
src/runtime/vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
180
src/runtime/vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
// elfCode is a convenience to reduce the amount of arguments that have to
|
||||
// be passed around explicitly. You should treat it's contents as immutable.
|
||||
// be passed around explicitly. You should treat its contents as immutable.
|
||||
type elfCode struct {
|
||||
*internal.SafeELFFile
|
||||
sections map[elf.SectionIndex]*elfSection
|
||||
@@ -188,7 +188,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
||||
return nil, fmt.Errorf("load programs: %w", err)
|
||||
}
|
||||
|
||||
return &CollectionSpec{maps, progs}, nil
|
||||
return &CollectionSpec{maps, progs, ec.ByteOrder}, nil
|
||||
}
|
||||
|
||||
func loadLicense(sec *elf.Section) (string, error) {
|
||||
@@ -520,8 +520,12 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error {
|
||||
return fmt.Errorf("map %s: missing flags", mapName)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil {
|
||||
return fmt.Errorf("map %s: unknown and non-zero fields in definition", mapName)
|
||||
extra, err := io.ReadAll(lr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("map %s: reading map tail: %w", mapName, err)
|
||||
}
|
||||
if len(extra) > 0 {
|
||||
spec.Extra = *bytes.NewReader(extra)
|
||||
}
|
||||
|
||||
if err := spec.clampPerfEventArraySize(); err != nil {
|
||||
@@ -535,6 +539,9 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadBTFMaps iterates over all ELF sections marked as BTF map sections
|
||||
// (like .maps) and parses them into MapSpecs. Dump the .maps section and
|
||||
// any relocations with `readelf -x .maps -r <elf_file>`.
|
||||
func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
|
||||
for _, sec := range ec.sections {
|
||||
if sec.kind != btfMapSection {
|
||||
@@ -545,33 +552,46 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
|
||||
return fmt.Errorf("missing BTF")
|
||||
}
|
||||
|
||||
_, err := io.Copy(internal.DiscardZeroes{}, bufio.NewReader(sec.Open()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("section %v: initializing BTF map definitions: %w", sec.Name, internal.ErrNotSupported)
|
||||
}
|
||||
|
||||
var ds btf.Datasec
|
||||
// Each section must appear as a DataSec in the ELF's BTF blob.
|
||||
var ds *btf.Datasec
|
||||
if err := ec.btf.FindType(sec.Name, &ds); err != nil {
|
||||
return fmt.Errorf("cannot find section '%s' in BTF: %w", sec.Name, err)
|
||||
}
|
||||
|
||||
// Open a Reader to the ELF's raw section bytes so we can assert that all
|
||||
// of them are zero on a per-map (per-Var) basis. For now, the section's
|
||||
// sole purpose is to receive relocations, so all must be zero.
|
||||
rs := sec.Open()
|
||||
|
||||
for _, vs := range ds.Vars {
|
||||
// BPF maps are declared as and assigned to global variables,
|
||||
// so iterate over each Var in the DataSec and validate their types.
|
||||
v, ok := vs.Type.(*btf.Var)
|
||||
if !ok {
|
||||
return fmt.Errorf("section %v: unexpected type %s", sec.Name, vs.Type)
|
||||
}
|
||||
name := string(v.Name)
|
||||
|
||||
// The BTF metadata for each Var contains the full length of the map
|
||||
// declaration, so read the corresponding amount of bytes from the ELF.
|
||||
// This way, we can pinpoint which map declaration contains unexpected
|
||||
// (and therefore unsupported) data.
|
||||
_, err := io.Copy(internal.DiscardZeroes{}, io.LimitReader(rs, int64(vs.Size)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("section %v: map %s: initializing BTF map definitions: %w", sec.Name, name, internal.ErrNotSupported)
|
||||
}
|
||||
|
||||
if maps[name] != nil {
|
||||
return fmt.Errorf("section %v: map %s already exists", sec.Name, name)
|
||||
}
|
||||
|
||||
// Each Var representing a BTF map definition contains a Struct.
|
||||
mapStruct, ok := v.Type.(*btf.Struct)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected struct, got %s", v.Type)
|
||||
}
|
||||
|
||||
mapSpec, err := mapSpecFromBTF(name, mapStruct, false, ec.btf)
|
||||
mapSpec, err := mapSpecFromBTF(sec, &vs, mapStruct, ec.btf, name, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("map %v: %w", name, err)
|
||||
}
|
||||
@@ -582,32 +602,52 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
|
||||
|
||||
maps[name] = mapSpec
|
||||
}
|
||||
|
||||
// Drain the ELF section reader to make sure all bytes are accounted for
|
||||
// with BTF metadata.
|
||||
i, err := io.Copy(io.Discard, rs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("section %v: unexpected error reading remainder of ELF section: %w", sec.Name, err)
|
||||
}
|
||||
if i > 0 {
|
||||
return fmt.Errorf("section %v: %d unexpected remaining bytes in ELF section, invalid BTF?", sec.Name, i)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// A programStub is a placeholder for a Program to be inserted at a certain map key.
|
||||
// It needs to be resolved into a Program later on in the loader process.
|
||||
type programStub string
|
||||
|
||||
// A mapStub is a placeholder for a Map to be inserted at a certain map key.
|
||||
// It needs to be resolved into a Map later on in the loader process.
|
||||
type mapStub string
|
||||
|
||||
// mapSpecFromBTF produces a MapSpec based on a btf.Struct def representing
|
||||
// a BTF map definition. The name and spec arguments will be copied to the
|
||||
// resulting MapSpec, and inner must be true on any resursive invocations.
|
||||
func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*MapSpec, error) {
|
||||
|
||||
func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *btf.Spec, name string, inner bool) (*MapSpec, error) {
|
||||
var (
|
||||
key, value btf.Type
|
||||
keySize, valueSize uint32
|
||||
mapType, flags, maxEntries uint32
|
||||
pinType PinType
|
||||
innerMapSpec *MapSpec
|
||||
err error
|
||||
key, value btf.Type
|
||||
keySize, valueSize uint32
|
||||
mapType MapType
|
||||
flags, maxEntries uint32
|
||||
pinType PinType
|
||||
innerMapSpec *MapSpec
|
||||
contents []MapKV
|
||||
err error
|
||||
)
|
||||
|
||||
for i, member := range def.Members {
|
||||
switch member.Name {
|
||||
case "type":
|
||||
mapType, err = uintFromBTF(member.Type)
|
||||
mt, err := uintFromBTF(member.Type)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get type: %w", err)
|
||||
}
|
||||
mapType = MapType(mt)
|
||||
|
||||
case "map_flags":
|
||||
flags, err = uintFromBTF(member.Type)
|
||||
@@ -717,7 +757,7 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*
|
||||
case *btf.Struct:
|
||||
// The values member pointing to an array of structs means we're expecting
|
||||
// a map-in-map declaration.
|
||||
if MapType(mapType) != ArrayOfMaps && MapType(mapType) != HashOfMaps {
|
||||
if mapType != ArrayOfMaps && mapType != HashOfMaps {
|
||||
return nil, errors.New("outer map needs to be an array or a hash of maps")
|
||||
}
|
||||
if inner {
|
||||
@@ -731,21 +771,38 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*
|
||||
// on kernels 5.2 and up)
|
||||
// Pass the BTF spec from the parent object, since both parent and
|
||||
// child must be created from the same BTF blob (on kernels that support BTF).
|
||||
innerMapSpec, err = mapSpecFromBTF(name+"_inner", t, true, spec)
|
||||
innerMapSpec, err = mapSpecFromBTF(es, vs, t, spec, name+"_inner", true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't parse BTF map definition of inner map: %w", err)
|
||||
}
|
||||
|
||||
case *btf.FuncProto:
|
||||
// The values member contains an array of function pointers, meaning an
|
||||
// autopopulated PROG_ARRAY.
|
||||
if mapType != ProgramArray {
|
||||
return nil, errors.New("map needs to be a program array")
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported value type %q in 'values' field", t)
|
||||
}
|
||||
|
||||
contents, err = resolveBTFValuesContents(es, vs, member)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolving values contents: %w", err)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name)
|
||||
}
|
||||
}
|
||||
|
||||
bm := btf.NewMap(spec, key, value)
|
||||
if key == nil {
|
||||
key = &btf.Void{}
|
||||
}
|
||||
if value == nil {
|
||||
value = &btf.Void{}
|
||||
}
|
||||
|
||||
return &MapSpec{
|
||||
Name: SanitizeName(name, -1),
|
||||
@@ -754,9 +811,10 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*
|
||||
ValueSize: valueSize,
|
||||
MaxEntries: maxEntries,
|
||||
Flags: flags,
|
||||
BTF: &bm,
|
||||
BTF: &btf.Map{Spec: spec, Key: key, Value: value},
|
||||
Pinning: pinType,
|
||||
InnerMap: innerMapSpec,
|
||||
Contents: contents,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -793,6 +851,64 @@ func resolveBTFArrayMacro(typ btf.Type) (btf.Type, error) {
|
||||
return ptr.Target, nil
|
||||
}
|
||||
|
||||
// resolveBTFValuesContents resolves relocations into ELF sections belonging
|
||||
// to btf.VarSecinfo's. This can be used on the 'values' member in BTF map
|
||||
// definitions to extract static declarations of map contents.
|
||||
func resolveBTFValuesContents(es *elfSection, vs *btf.VarSecinfo, member btf.Member) ([]MapKV, error) {
|
||||
// The elements of a .values pointer array are not encoded in BTF.
|
||||
// Instead, relocations are generated into each array index.
|
||||
// However, it's possible to leave certain array indices empty, so all
|
||||
// indices' offsets need to be checked for emitted relocations.
|
||||
|
||||
// The offset of the 'values' member within the _struct_ (in bits)
|
||||
// is the starting point of the array. Convert to bytes. Add VarSecinfo
|
||||
// offset to get the absolute position in the ELF blob.
|
||||
start := (member.OffsetBits / 8) + vs.Offset
|
||||
// 'values' is encoded in BTF as a zero (variable) length struct
|
||||
// member, and its contents run until the end of the VarSecinfo.
|
||||
// Add VarSecinfo offset to get the absolute position in the ELF blob.
|
||||
end := vs.Size + vs.Offset
|
||||
// The size of an address in this section. This determines the width of
|
||||
// an index in the array.
|
||||
align := uint32(es.SectionHeader.Addralign)
|
||||
|
||||
// Check if variable-length section is aligned.
|
||||
if (end-start)%align != 0 {
|
||||
return nil, errors.New("unaligned static values section")
|
||||
}
|
||||
elems := (end - start) / align
|
||||
|
||||
if elems == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
contents := make([]MapKV, 0, elems)
|
||||
|
||||
// k is the array index, off is its corresponding ELF section offset.
|
||||
for k, off := uint32(0), start; k < elems; k, off = k+1, off+align {
|
||||
r, ok := es.relocations[uint64(off)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// Relocation exists for the current offset in the ELF section.
|
||||
// Emit a value stub based on the type of relocation to be replaced by
|
||||
// a real fd later in the pipeline before populating the map.
|
||||
// Map keys are encoded in MapKV entries, so empty array indices are
|
||||
// skipped here.
|
||||
switch t := elf.ST_TYPE(r.Info); t {
|
||||
case elf.STT_FUNC:
|
||||
contents = append(contents, MapKV{uint32(k), programStub(r.Name)})
|
||||
case elf.STT_OBJECT:
|
||||
contents = append(contents, MapKV{uint32(k), mapStub(r.Name)})
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown relocation type %v", t)
|
||||
}
|
||||
}
|
||||
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
|
||||
for _, sec := range ec.sections {
|
||||
if sec.kind != dataSection {
|
||||
@@ -809,9 +925,9 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
|
||||
return errors.New("data sections require BTF, make sure all consts are marked as static")
|
||||
}
|
||||
|
||||
btfMap, err := ec.btf.Datasec(sec.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
var datasec *btf.Datasec
|
||||
if err := ec.btf.FindType(sec.Name, &datasec); err != nil {
|
||||
return fmt.Errorf("data section %s: can't get BTF: %w", sec.Name, err)
|
||||
}
|
||||
|
||||
data, err := sec.Data()
|
||||
@@ -830,7 +946,7 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
|
||||
ValueSize: uint32(len(data)),
|
||||
MaxEntries: 1,
|
||||
Contents: []MapKV{{uint32(0), data}},
|
||||
BTF: btfMap,
|
||||
BTF: &btf.Map{Spec: ec.btf, Key: &btf.Void{}, Value: datasec},
|
||||
}
|
||||
|
||||
switch sec.Name {
|
||||
@@ -855,6 +971,8 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
|
||||
}{
|
||||
// From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c
|
||||
"socket": {SocketFilter, AttachNone, 0},
|
||||
"sk_reuseport/migrate": {SkReuseport, AttachSkReuseportSelectOrMigrate, 0},
|
||||
"sk_reuseport": {SkReuseport, AttachSkReuseportSelect, 0},
|
||||
"seccomp": {SocketFilter, AttachNone, 0},
|
||||
"kprobe/": {Kprobe, AttachNone, 0},
|
||||
"uprobe/": {Kprobe, AttachNone, 0},
|
||||
@@ -884,6 +1002,7 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
|
||||
"fmod_ret.s/": {Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE},
|
||||
"fexit.s/": {Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE},
|
||||
"sk_lookup/": {SkLookup, AttachSkLookup, 0},
|
||||
"freplace/": {Extension, AttachNone, 0},
|
||||
"lsm/": {LSM, AttachLSMMac, 0},
|
||||
"lsm.s/": {LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
|
||||
|
||||
@@ -907,6 +1026,11 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
|
||||
"cgroup/setsockopt": {CGroupSockopt, AttachCGroupSetsockopt, 0},
|
||||
"classifier": {SchedCLS, AttachNone, 0},
|
||||
"action": {SchedACT, AttachNone, 0},
|
||||
|
||||
"cgroup/getsockname4": {CGroupSockAddr, AttachCgroupInet4GetSockname, 0},
|
||||
"cgroup/getsockname6": {CGroupSockAddr, AttachCgroupInet6GetSockname, 0},
|
||||
"cgroup/getpeername4": {CGroupSockAddr, AttachCgroupInet4GetPeername, 0},
|
||||
"cgroup/getpeername6": {CGroupSockAddr, AttachCgroupInet6GetPeername, 0},
|
||||
}
|
||||
|
||||
for prefix, t := range types {
|
||||
|
||||
1
src/runtime/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go
generated
vendored
1
src/runtime/vendor/github.com/cilium/ebpf/elf_reader_fuzz.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
// Use with https://github.com/dvyukov/go-fuzz
|
||||
|
||||
4
src/runtime/vendor/github.com/cilium/ebpf/go.mod
generated
vendored
4
src/runtime/vendor/github.com/cilium/ebpf/go.mod
generated
vendored
@@ -1,9 +1,9 @@
|
||||
module github.com/cilium/ebpf
|
||||
|
||||
go 1.15
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/frankban/quicktest v1.11.3
|
||||
github.com/google/go-cmp v0.5.4
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
|
||||
)
|
||||
|
||||
4
src/runtime/vendor/github.com/cilium/ebpf/go.sum
generated
vendored
4
src/runtime/vendor/github.com/cilium/ebpf/go.sum
generated
vendored
@@ -7,7 +7,7 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
36
src/runtime/vendor/github.com/cilium/ebpf/info.go
generated
vendored
36
src/runtime/vendor/github.com/cilium/ebpf/info.go
generated
vendored
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cilium/ebpf/internal"
|
||||
"github.com/cilium/ebpf/internal/btf"
|
||||
)
|
||||
|
||||
// MapInfo describes a map.
|
||||
@@ -87,12 +88,16 @@ type ProgramInfo struct {
|
||||
Tag string
|
||||
// Name as supplied by user space at load time.
|
||||
Name string
|
||||
// BTF for the program.
|
||||
btf btf.ID
|
||||
// IDS map ids related to program.
|
||||
ids []MapID
|
||||
|
||||
stats *programStats
|
||||
}
|
||||
|
||||
func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) {
|
||||
info, err := bpfGetProgInfoByFD(fd)
|
||||
info, err := bpfGetProgInfoByFD(fd, nil)
|
||||
if errors.Is(err, syscall.EINVAL) {
|
||||
return newProgramInfoFromProc(fd)
|
||||
}
|
||||
@@ -100,6 +105,15 @@ func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mapIDs []MapID
|
||||
if info.nr_map_ids > 0 {
|
||||
mapIDs = make([]MapID, info.nr_map_ids)
|
||||
info, err = bpfGetProgInfoByFD(fd, mapIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &ProgramInfo{
|
||||
Type: ProgramType(info.prog_type),
|
||||
id: ProgramID(info.id),
|
||||
@@ -107,6 +121,8 @@ func newProgramInfoFromFd(fd *internal.FD) (*ProgramInfo, error) {
|
||||
Tag: hex.EncodeToString(info.tag[:]),
|
||||
// name is available from 4.15.
|
||||
Name: internal.CString(info.name[:]),
|
||||
btf: btf.ID(info.btf_id),
|
||||
ids: mapIDs,
|
||||
stats: &programStats{
|
||||
runtime: time.Duration(info.run_time_ns),
|
||||
runCount: info.run_cnt,
|
||||
@@ -142,6 +158,17 @@ func (pi *ProgramInfo) ID() (ProgramID, bool) {
|
||||
return pi.id, pi.id > 0
|
||||
}
|
||||
|
||||
// BTFID returns the BTF ID associated with the program.
|
||||
//
|
||||
// Available from 5.0.
|
||||
//
|
||||
// The bool return value indicates whether this optional field is available and
|
||||
// populated. (The field may be available but not populated if the kernel
|
||||
// supports the field but the program was loaded without BTF information.)
|
||||
func (pi *ProgramInfo) BTFID() (btf.ID, bool) {
|
||||
return pi.btf, pi.btf > 0
|
||||
}
|
||||
|
||||
// RunCount returns the total number of times the program was called.
|
||||
//
|
||||
// Can return 0 if the collection of statistics is not enabled. See EnableStats().
|
||||
@@ -164,6 +191,13 @@ func (pi *ProgramInfo) Runtime() (time.Duration, bool) {
|
||||
return time.Duration(0), false
|
||||
}
|
||||
|
||||
// MapIDs returns the maps related to the program.
|
||||
//
|
||||
// The bool return value indicates whether this optional field is available.
|
||||
func (pi *ProgramInfo) MapIDs() ([]MapID, bool) {
|
||||
return pi.ids, pi.ids != nil
|
||||
}
|
||||
|
||||
func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error {
|
||||
raw, err := fd.Value()
|
||||
if err != nil {
|
||||
|
||||
6
src/runtime/vendor/github.com/cilium/ebpf/internal/align.go
generated
vendored
Normal file
6
src/runtime/vendor/github.com/cilium/ebpf/internal/align.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package internal
|
||||
|
||||
// Align returns 'n' updated to 'alignment' boundary.
|
||||
func Align(n, alignment int) int {
|
||||
return (int(n) + alignment - 1) / alignment * alignment
|
||||
}
|
||||
293
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
293
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
@@ -7,7 +7,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
@@ -27,12 +26,15 @@ var (
|
||||
ErrNoExtendedInfo = errors.New("no extended info")
|
||||
)
|
||||
|
||||
// ID represents the unique ID of a BTF object.
|
||||
type ID uint32
|
||||
|
||||
// Spec represents decoded BTF.
|
||||
type Spec struct {
|
||||
rawTypes []rawType
|
||||
strings stringTable
|
||||
types []Type
|
||||
namedTypes map[string][]namedType
|
||||
namedTypes map[string][]NamedType
|
||||
funcInfos map[string]extInfo
|
||||
lineInfos map[string]extInfo
|
||||
coreRelos map[string]coreRelos
|
||||
@@ -61,15 +63,6 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
btfSection, btfExtSection, sectionSizes, err := findBtfSections(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if btfSection == nil {
|
||||
return nil, fmt.Errorf("btf: %w", ErrNotFound)
|
||||
}
|
||||
|
||||
symbols, err := file.Symbols()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read symbols: %v", err)
|
||||
@@ -87,10 +80,6 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
}
|
||||
|
||||
secName := file.Sections[symbol.Section].Name
|
||||
if _, ok := sectionSizes[secName]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if symbol.Value > math.MaxUint32 {
|
||||
return nil, fmt.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name)
|
||||
}
|
||||
@@ -98,24 +87,10 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value)
|
||||
}
|
||||
|
||||
spec, err := loadNakedSpec(btfSection.Open(), file.ByteOrder, sectionSizes, variableOffsets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if btfExtSection == nil {
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
spec.funcInfos, spec.lineInfos, spec.coreRelos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read ext info: %w", err)
|
||||
}
|
||||
|
||||
return spec, nil
|
||||
return loadSpecFromELF(file, variableOffsets)
|
||||
}
|
||||
|
||||
func findBtfSections(file *internal.SafeELFFile) (*elf.Section, *elf.Section, map[string]uint32, error) {
|
||||
func loadSpecFromELF(file *internal.SafeELFFile, variableOffsets map[variable]uint32) (*Spec, error) {
|
||||
var (
|
||||
btfSection *elf.Section
|
||||
btfExtSection *elf.Section
|
||||
@@ -134,33 +109,45 @@ func findBtfSections(file *internal.SafeELFFile) (*elf.Section, *elf.Section, ma
|
||||
}
|
||||
|
||||
if sec.Size > math.MaxUint32 {
|
||||
return nil, nil, nil, fmt.Errorf("section %s exceeds maximum size", sec.Name)
|
||||
return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name)
|
||||
}
|
||||
|
||||
sectionSizes[sec.Name] = uint32(sec.Size)
|
||||
}
|
||||
}
|
||||
return btfSection, btfExtSection, sectionSizes, nil
|
||||
}
|
||||
|
||||
func loadSpecFromVmlinux(rd io.ReaderAt) (*Spec, error) {
|
||||
file, err := internal.NewSafeELFFile(rd)
|
||||
if btfSection == nil {
|
||||
return nil, fmt.Errorf("btf: %w", ErrNotFound)
|
||||
}
|
||||
|
||||
spec, err := loadRawSpec(btfSection.Open(), file.ByteOrder, sectionSizes, variableOffsets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
btfSection, _, _, err := findBtfSections(file)
|
||||
if btfExtSection == nil {
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
spec.funcInfos, spec.lineInfos, spec.coreRelos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(".BTF ELF section: %s", err)
|
||||
return nil, fmt.Errorf("can't read ext info: %w", err)
|
||||
}
|
||||
if btfSection == nil {
|
||||
return nil, fmt.Errorf("unable to find .BTF ELF section")
|
||||
}
|
||||
return loadNakedSpec(btfSection.Open(), file.ByteOrder, nil, nil)
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func loadNakedSpec(btf io.ReadSeeker, bo binary.ByteOrder, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) (*Spec, error) {
|
||||
// LoadRawSpec reads a blob of BTF data that isn't wrapped in an ELF file.
|
||||
//
|
||||
// Prefer using LoadSpecFromReader, since this function only supports a subset
|
||||
// of BTF.
|
||||
func LoadRawSpec(btf io.Reader, bo binary.ByteOrder) (*Spec, error) {
|
||||
// This will return an error if we encounter a Datasec, since we can't fix
|
||||
// it up.
|
||||
return loadRawSpec(btf, bo, nil, nil)
|
||||
}
|
||||
|
||||
func loadRawSpec(btf io.Reader, bo binary.ByteOrder, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) (*Spec, error) {
|
||||
rawTypes, rawStrings, err := parseBTF(btf, bo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -217,7 +204,7 @@ func loadKernelSpec() (*Spec, error) {
|
||||
if err == nil {
|
||||
defer fh.Close()
|
||||
|
||||
return loadNakedSpec(fh, internal.NativeEndian, nil, nil)
|
||||
return LoadRawSpec(fh, internal.NativeEndian)
|
||||
}
|
||||
|
||||
// use same list of locations as libbpf
|
||||
@@ -241,14 +228,20 @@ func loadKernelSpec() (*Spec, error) {
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
return loadSpecFromVmlinux(fh)
|
||||
file, err := internal.NewSafeELFFile(fh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return loadSpecFromELF(file, nil)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no BTF for kernel version %s: %w", release, internal.ErrNotSupported)
|
||||
}
|
||||
|
||||
func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) {
|
||||
rawBTF, err := ioutil.ReadAll(btf)
|
||||
func parseBTF(btf io.Reader, bo binary.ByteOrder) ([]rawType, stringTable, error) {
|
||||
rawBTF, err := io.ReadAll(btf)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("can't read BTF: %v", err)
|
||||
}
|
||||
@@ -357,6 +350,30 @@ func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[s
|
||||
return nil
|
||||
}
|
||||
|
||||
// Copy creates a copy of Spec.
|
||||
func (s *Spec) Copy() *Spec {
|
||||
types, _ := copyTypes(s.types, nil)
|
||||
namedTypes := make(map[string][]NamedType)
|
||||
for _, typ := range types {
|
||||
if named, ok := typ.(NamedType); ok {
|
||||
name := essentialName(named.TypeName())
|
||||
namedTypes[name] = append(namedTypes[name], named)
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Other parts of spec are not copied since they are immutable.
|
||||
return &Spec{
|
||||
s.rawTypes,
|
||||
s.strings,
|
||||
types,
|
||||
namedTypes,
|
||||
s.funcInfos,
|
||||
s.lineInfos,
|
||||
s.coreRelos,
|
||||
s.byteOrder,
|
||||
}
|
||||
}
|
||||
|
||||
type marshalOpts struct {
|
||||
ByteOrder binary.ByteOrder
|
||||
StripFuncLinkage bool
|
||||
@@ -447,36 +464,37 @@ func (s *Spec) Program(name string, length uint64) (*Program, error) {
|
||||
return &Program{s, length, funcInfos, lineInfos, relos}, nil
|
||||
}
|
||||
|
||||
// Datasec returns the BTF required to create maps which represent data sections.
|
||||
func (s *Spec) Datasec(name string) (*Map, error) {
|
||||
var datasec Datasec
|
||||
if err := s.FindType(name, &datasec); err != nil {
|
||||
return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err)
|
||||
}
|
||||
|
||||
m := NewMap(s, &Void{}, &datasec)
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// FindType searches for a type with a specific name.
|
||||
//
|
||||
// hint determines the type of the returned Type.
|
||||
// Called T a type that satisfies Type, typ must be a non-nil **T.
|
||||
// On success, the address of the found type will be copied in typ.
|
||||
//
|
||||
// Returns an error wrapping ErrNotFound if no matching
|
||||
// type exists in spec.
|
||||
func (s *Spec) FindType(name string, typ Type) error {
|
||||
var (
|
||||
wanted = reflect.TypeOf(typ)
|
||||
candidate Type
|
||||
)
|
||||
func (s *Spec) FindType(name string, typ interface{}) error {
|
||||
typValue := reflect.ValueOf(typ)
|
||||
if typValue.Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("%T is not a pointer", typ)
|
||||
}
|
||||
|
||||
typPtr := typValue.Elem()
|
||||
if !typPtr.CanSet() {
|
||||
return fmt.Errorf("%T cannot be set", typ)
|
||||
}
|
||||
|
||||
wanted := typPtr.Type()
|
||||
if !wanted.AssignableTo(reflect.TypeOf((*Type)(nil)).Elem()) {
|
||||
return fmt.Errorf("%T does not satisfy Type interface", typ)
|
||||
}
|
||||
|
||||
var candidate Type
|
||||
for _, typ := range s.namedTypes[essentialName(name)] {
|
||||
if reflect.TypeOf(typ) != wanted {
|
||||
continue
|
||||
}
|
||||
|
||||
// Match against the full name, not just the essential one.
|
||||
if typ.name() != name {
|
||||
if typ.TypeName() != name {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -491,15 +509,15 @@ func (s *Spec) FindType(name string, typ Type) error {
|
||||
return fmt.Errorf("type %s: %w", name, ErrNotFound)
|
||||
}
|
||||
|
||||
cpy, _ := copyType(candidate, nil)
|
||||
value := reflect.Indirect(reflect.ValueOf(cpy))
|
||||
reflect.Indirect(reflect.ValueOf(typ)).Set(value)
|
||||
typPtr.Set(reflect.ValueOf(candidate))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle is a reference to BTF loaded into the kernel.
|
||||
type Handle struct {
|
||||
fd *internal.FD
|
||||
spec *Spec
|
||||
fd *internal.FD
|
||||
}
|
||||
|
||||
// NewHandle loads BTF into the kernel.
|
||||
@@ -541,7 +559,32 @@ func NewHandle(spec *Spec) (*Handle, error) {
|
||||
return nil, internal.ErrorWithLog(err, logBuf, logErr)
|
||||
}
|
||||
|
||||
return &Handle{fd}, nil
|
||||
return &Handle{spec.Copy(), fd}, nil
|
||||
}
|
||||
|
||||
// NewHandleFromID returns the BTF handle for a given id.
|
||||
//
|
||||
// Returns ErrNotExist, if there is no BTF with the given id.
|
||||
//
|
||||
// Requires CAP_SYS_ADMIN.
|
||||
func NewHandleFromID(id ID) (*Handle, error) {
|
||||
fd, err := internal.BPFObjGetFDByID(internal.BPF_BTF_GET_FD_BY_ID, uint32(id))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get BTF by id: %w", err)
|
||||
}
|
||||
|
||||
info, err := newInfoFromFd(fd)
|
||||
if err != nil {
|
||||
_ = fd.Close()
|
||||
return nil, fmt.Errorf("get BTF spec for handle: %w", err)
|
||||
}
|
||||
|
||||
return &Handle{info.BTF, fd}, nil
|
||||
}
|
||||
|
||||
// Spec returns the Spec that defined the BTF loaded into the kernel.
|
||||
func (h *Handle) Spec() *Spec {
|
||||
return h.spec
|
||||
}
|
||||
|
||||
// Close destroys the handle.
|
||||
@@ -563,43 +606,8 @@ func (h *Handle) FD() int {
|
||||
|
||||
// Map is the BTF for a map.
|
||||
type Map struct {
|
||||
spec *Spec
|
||||
key, value Type
|
||||
}
|
||||
|
||||
// NewMap returns a new Map containing the given values.
|
||||
// The key and value arguments are initialized to Void if nil values are given.
|
||||
func NewMap(spec *Spec, key Type, value Type) Map {
|
||||
if key == nil {
|
||||
key = &Void{}
|
||||
}
|
||||
if value == nil {
|
||||
value = &Void{}
|
||||
}
|
||||
|
||||
return Map{
|
||||
spec: spec,
|
||||
key: key,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// MapSpec should be a method on Map, but is a free function
|
||||
// to hide it from users of the ebpf package.
|
||||
func MapSpec(m *Map) *Spec {
|
||||
return m.spec
|
||||
}
|
||||
|
||||
// MapKey should be a method on Map, but is a free function
|
||||
// to hide it from users of the ebpf package.
|
||||
func MapKey(m *Map) Type {
|
||||
return m.key
|
||||
}
|
||||
|
||||
// MapValue should be a method on Map, but is a free function
|
||||
// to hide it from users of the ebpf package.
|
||||
func MapValue(m *Map) Type {
|
||||
return m.value
|
||||
Spec *Spec
|
||||
Key, Value Type
|
||||
}
|
||||
|
||||
// Program is the BTF information for a stream of instructions.
|
||||
@@ -610,68 +618,59 @@ type Program struct {
|
||||
coreRelos coreRelos
|
||||
}
|
||||
|
||||
// ProgramSpec returns the Spec needed for loading function and line infos into the kernel.
|
||||
//
|
||||
// This is a free function instead of a method to hide it from users
|
||||
// of package ebpf.
|
||||
func ProgramSpec(s *Program) *Spec {
|
||||
return s.spec
|
||||
// Spec returns the BTF spec of this program.
|
||||
func (p *Program) Spec() *Spec {
|
||||
return p.spec
|
||||
}
|
||||
|
||||
// ProgramAppend the information from other to the Program.
|
||||
//
|
||||
// This is a free function instead of a method to hide it from users
|
||||
// of package ebpf.
|
||||
func ProgramAppend(s, other *Program) error {
|
||||
funcInfos, err := s.funcInfos.append(other.funcInfos, s.length)
|
||||
// Append the information from other to the Program.
|
||||
func (p *Program) Append(other *Program) error {
|
||||
if other.spec != p.spec {
|
||||
return fmt.Errorf("can't append program with different BTF specs")
|
||||
}
|
||||
|
||||
funcInfos, err := p.funcInfos.append(other.funcInfos, p.length)
|
||||
if err != nil {
|
||||
return fmt.Errorf("func infos: %w", err)
|
||||
}
|
||||
|
||||
lineInfos, err := s.lineInfos.append(other.lineInfos, s.length)
|
||||
lineInfos, err := p.lineInfos.append(other.lineInfos, p.length)
|
||||
if err != nil {
|
||||
return fmt.Errorf("line infos: %w", err)
|
||||
}
|
||||
|
||||
s.funcInfos = funcInfos
|
||||
s.lineInfos = lineInfos
|
||||
s.coreRelos = s.coreRelos.append(other.coreRelos, s.length)
|
||||
s.length += other.length
|
||||
p.funcInfos = funcInfos
|
||||
p.lineInfos = lineInfos
|
||||
p.coreRelos = p.coreRelos.append(other.coreRelos, p.length)
|
||||
p.length += other.length
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProgramFuncInfos returns the binary form of BTF function infos.
|
||||
//
|
||||
// This is a free function instead of a method to hide it from users
|
||||
// of package ebpf.
|
||||
func ProgramFuncInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
|
||||
bytes, err = s.funcInfos.MarshalBinary()
|
||||
// FuncInfos returns the binary form of BTF function infos.
|
||||
func (p *Program) FuncInfos() (recordSize uint32, bytes []byte, err error) {
|
||||
bytes, err = p.funcInfos.MarshalBinary()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, nil, fmt.Errorf("func infos: %w", err)
|
||||
}
|
||||
|
||||
return s.funcInfos.recordSize, bytes, nil
|
||||
return p.funcInfos.recordSize, bytes, nil
|
||||
}
|
||||
|
||||
// ProgramLineInfos returns the binary form of BTF line infos.
|
||||
//
|
||||
// This is a free function instead of a method to hide it from users
|
||||
// of package ebpf.
|
||||
func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
|
||||
bytes, err = s.lineInfos.MarshalBinary()
|
||||
// LineInfos returns the binary form of BTF line infos.
|
||||
func (p *Program) LineInfos() (recordSize uint32, bytes []byte, err error) {
|
||||
bytes, err = p.lineInfos.MarshalBinary()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return 0, nil, fmt.Errorf("line infos: %w", err)
|
||||
}
|
||||
|
||||
return s.lineInfos.recordSize, bytes, nil
|
||||
return p.lineInfos.recordSize, bytes, nil
|
||||
}
|
||||
|
||||
// ProgramFixups returns the changes required to adjust the program to the target.
|
||||
// Fixups returns the changes required to adjust the program to the target.
|
||||
//
|
||||
// This is a free function instead of a method to hide it from users
|
||||
// of package ebpf.
|
||||
func ProgramFixups(s *Program, target *Spec) (COREFixups, error) {
|
||||
if len(s.coreRelos) == 0 {
|
||||
// Passing a nil target will relocate against the running kernel.
|
||||
func (p *Program) Fixups(target *Spec) (COREFixups, error) {
|
||||
if len(p.coreRelos) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -683,7 +682,7 @@ func ProgramFixups(s *Program, target *Spec) (COREFixups, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return coreRelocate(s.spec, target, s.coreRelos)
|
||||
return coreRelocate(p.spec, target, p.coreRelos)
|
||||
}
|
||||
|
||||
type bpfLoadBTFAttr struct {
|
||||
|
||||
11
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
generated
vendored
11
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
generated
vendored
@@ -31,6 +31,8 @@ const (
|
||||
// Added ~5.1
|
||||
kindVar
|
||||
kindDatasec
|
||||
// Added ~5.13
|
||||
kindFloat
|
||||
)
|
||||
|
||||
// FuncLinkage describes BTF function linkage metadata.
|
||||
@@ -54,7 +56,7 @@ const (
|
||||
|
||||
const (
|
||||
btfTypeKindShift = 24
|
||||
btfTypeKindLen = 4
|
||||
btfTypeKindLen = 5
|
||||
btfTypeVlenShift = 0
|
||||
btfTypeVlenMask = 16
|
||||
btfTypeKindFlagShift = 31
|
||||
@@ -67,8 +69,8 @@ type btfType struct {
|
||||
/* "info" bits arrangement
|
||||
* bits 0-15: vlen (e.g. # of struct's members), linkage
|
||||
* bits 16-23: unused
|
||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||
* bits 28-30: unused
|
||||
* bits 24-28: kind (e.g. int, ptr, array...etc)
|
||||
* bits 29-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union and fwd
|
||||
*/
|
||||
@@ -117,6 +119,8 @@ func (k btfKind) String() string {
|
||||
return "Variable"
|
||||
case kindDatasec:
|
||||
return "Section"
|
||||
case kindFloat:
|
||||
return "Float"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown (%d)", k)
|
||||
}
|
||||
@@ -260,6 +264,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
|
||||
data = new(btfVariable)
|
||||
case kindDatasec:
|
||||
data = make([]btfVarSecinfo, header.Vlen())
|
||||
case kindFloat:
|
||||
default:
|
||||
return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind())
|
||||
}
|
||||
|
||||
33
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/core.go
generated
vendored
33
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/core.go
generated
vendored
@@ -234,13 +234,13 @@ func coreRelocate(local, target *Spec, relos coreRelos) (COREFixups, error) {
|
||||
}
|
||||
|
||||
localType := local.types[id]
|
||||
named, ok := localType.(namedType)
|
||||
if !ok || named.name() == "" {
|
||||
named, ok := localType.(NamedType)
|
||||
if !ok || named.TypeName() == "" {
|
||||
return nil, fmt.Errorf("relocate unnamed or anonymous type %s: %w", localType, ErrNotSupported)
|
||||
}
|
||||
|
||||
relos := relosByID[id]
|
||||
targets := target.namedTypes[named.essentialName()]
|
||||
targets := target.namedTypes[essentialName(named.TypeName())]
|
||||
fixups, err := coreCalculateFixups(localType, targets, relos)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("relocate %s: %w", localType, err)
|
||||
@@ -262,7 +262,7 @@ var errImpossibleRelocation = errors.New("impossible relocation")
|
||||
//
|
||||
// The best target is determined by scoring: the less poisoning we have to do
|
||||
// the better the target is.
|
||||
func coreCalculateFixups(local Type, targets []namedType, relos coreRelos) ([]COREFixup, error) {
|
||||
func coreCalculateFixups(local Type, targets []NamedType, relos coreRelos) ([]COREFixup, error) {
|
||||
localID := local.ID()
|
||||
local, err := copyType(local, skipQualifierAndTypedef)
|
||||
if err != nil {
|
||||
@@ -467,8 +467,8 @@ func parseCoreAccessor(accessor string) (coreAccessor, error) {
|
||||
return nil, fmt.Errorf("empty accessor")
|
||||
}
|
||||
|
||||
var result coreAccessor
|
||||
parts := strings.Split(accessor, ":")
|
||||
result := make(coreAccessor, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
// 31 bits to avoid overflowing int on 32 bit platforms.
|
||||
index, err := strconv.ParseUint(part, 10, 31)
|
||||
@@ -564,7 +564,7 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie
|
||||
|
||||
// This is an anonymous struct or union, ignore it.
|
||||
local = localMember.Type
|
||||
localOffset += localMember.Offset
|
||||
localOffset += localMember.OffsetBits
|
||||
localMaybeFlex = false
|
||||
continue
|
||||
}
|
||||
@@ -585,10 +585,10 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie
|
||||
|
||||
local = localMember.Type
|
||||
localMaybeFlex = acc == len(localMembers)-1
|
||||
localOffset += localMember.Offset
|
||||
localOffset += localMember.OffsetBits
|
||||
target = targetMember.Type
|
||||
targetMaybeFlex = last
|
||||
targetOffset += targetMember.Offset
|
||||
targetOffset += targetMember.OffsetBits
|
||||
|
||||
case *Array:
|
||||
// For arrays, acc is the index in the target.
|
||||
@@ -639,7 +639,7 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie
|
||||
|
||||
// coreFindMember finds a member in a composite type while handling anonymous
|
||||
// structs and unions.
|
||||
func coreFindMember(typ composite, name Name) (Member, bool, error) {
|
||||
func coreFindMember(typ composite, name string) (Member, bool, error) {
|
||||
if name == "" {
|
||||
return Member{}, false, errors.New("can't search for anonymous member")
|
||||
}
|
||||
@@ -670,7 +670,7 @@ func coreFindMember(typ composite, name Name) (Member, bool, error) {
|
||||
for j, member := range members {
|
||||
if member.Name == name {
|
||||
// NB: This is safe because member is a copy.
|
||||
member.Offset += target.offset
|
||||
member.OffsetBits += target.offset
|
||||
return member, j == len(members)-1, nil
|
||||
}
|
||||
|
||||
@@ -685,7 +685,7 @@ func coreFindMember(typ composite, name Name) (Member, bool, error) {
|
||||
return Member{}, false, fmt.Errorf("anonymous non-composite type %T not allowed", member.Type)
|
||||
}
|
||||
|
||||
targets = append(targets, offsetTarget{comp, target.offset + member.Offset})
|
||||
targets = append(targets, offsetTarget{comp, target.offset + member.OffsetBits})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,9 +704,9 @@ func coreFindEnumValue(local Type, localAcc coreAccessor, target Type) (localVal
|
||||
return nil, nil, errImpossibleRelocation
|
||||
}
|
||||
|
||||
localName := localValue.Name.essentialName()
|
||||
localName := essentialName(localValue.Name)
|
||||
for i, targetValue := range targetEnum.Values {
|
||||
if targetValue.Name.essentialName() != localName {
|
||||
if essentialName(targetValue.Name) != localName {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -813,6 +813,7 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
||||
* least one of enums should be anonymous;
|
||||
* - for ENUMs, check sizes, names are ignored;
|
||||
* - for INT, size and signedness are ignored;
|
||||
* - any two FLOATs are always compatible;
|
||||
* - for ARRAY, dimensionality is ignored, element types are checked for
|
||||
* compatibility recursively;
|
||||
* [ NB: coreAreMembersCompatible doesn't recurse, this check is done
|
||||
@@ -848,16 +849,16 @@ func coreAreMembersCompatible(localType Type, targetType Type) error {
|
||||
}
|
||||
|
||||
switch lv := localType.(type) {
|
||||
case *Array, *Pointer:
|
||||
case *Array, *Pointer, *Float:
|
||||
return nil
|
||||
|
||||
case *Enum:
|
||||
tv := targetType.(*Enum)
|
||||
return doNamesMatch(lv.name(), tv.name())
|
||||
return doNamesMatch(lv.Name, tv.Name)
|
||||
|
||||
case *Fwd:
|
||||
tv := targetType.(*Fwd)
|
||||
return doNamesMatch(lv.name(), tv.name())
|
||||
return doNamesMatch(lv.Name, tv.Name)
|
||||
|
||||
case *Int:
|
||||
tv := targetType.(*Int)
|
||||
|
||||
15
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
15
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
@@ -7,7 +7,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/cilium/ebpf/asm"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
@@ -64,7 +63,7 @@ func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (f
|
||||
|
||||
// Of course, the .BTF.ext header has different semantics than the
|
||||
// .BTF ext header. We need to ignore non-null values.
|
||||
_, err = io.CopyN(ioutil.Discard, r, remainder)
|
||||
_, err = io.CopyN(io.Discard, r, remainder)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("header padding: %v", err)
|
||||
}
|
||||
@@ -114,11 +113,16 @@ type extInfoRecord struct {
|
||||
}
|
||||
|
||||
type extInfo struct {
|
||||
byteOrder binary.ByteOrder
|
||||
recordSize uint32
|
||||
records []extInfoRecord
|
||||
}
|
||||
|
||||
func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) {
|
||||
if other.byteOrder != ei.byteOrder {
|
||||
return extInfo{}, fmt.Errorf("ext_info byte order mismatch, want %v (got %v)", ei.byteOrder, other.byteOrder)
|
||||
}
|
||||
|
||||
if other.recordSize != ei.recordSize {
|
||||
return extInfo{}, fmt.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize)
|
||||
}
|
||||
@@ -131,10 +135,14 @@ func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) {
|
||||
Opaque: info.Opaque,
|
||||
})
|
||||
}
|
||||
return extInfo{ei.recordSize, records}, nil
|
||||
return extInfo{ei.byteOrder, ei.recordSize, records}, nil
|
||||
}
|
||||
|
||||
func (ei extInfo) MarshalBinary() ([]byte, error) {
|
||||
if ei.byteOrder != internal.NativeEndian {
|
||||
return nil, fmt.Errorf("%s is not the native byte order", ei.byteOrder)
|
||||
}
|
||||
|
||||
if len(ei.records) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -197,6 +205,7 @@ func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[st
|
||||
}
|
||||
|
||||
result[secName] = extInfo{
|
||||
bo,
|
||||
recordSize,
|
||||
records,
|
||||
}
|
||||
|
||||
1
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go
generated
vendored
1
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/fuzz.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build gofuzz
|
||||
// +build gofuzz
|
||||
|
||||
// Use with https://github.com/dvyukov/go-fuzz
|
||||
|
||||
48
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/info.go
generated
vendored
Normal file
48
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/info.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package btf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/cilium/ebpf/internal"
|
||||
)
|
||||
|
||||
// info describes a BTF object.
|
||||
type info struct {
|
||||
BTF *Spec
|
||||
ID ID
|
||||
// Name is an identifying name for the BTF, currently only used by the
|
||||
// kernel.
|
||||
Name string
|
||||
// KernelBTF is true if the BTf originated with the kernel and not
|
||||
// userspace.
|
||||
KernelBTF bool
|
||||
}
|
||||
|
||||
func newInfoFromFd(fd *internal.FD) (*info, error) {
|
||||
// We invoke the syscall once with a empty BTF and name buffers to get size
|
||||
// information to allocate buffers. Then we invoke it a second time with
|
||||
// buffers to receive the data.
|
||||
bpfInfo, err := bpfGetBTFInfoByFD(fd, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
btfBuffer := make([]byte, bpfInfo.btfSize)
|
||||
nameBuffer := make([]byte, bpfInfo.nameLen)
|
||||
bpfInfo, err = bpfGetBTFInfoByFD(fd, btfBuffer, nameBuffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spec, err := loadRawSpec(bytes.NewReader(btfBuffer), internal.NativeEndian, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &info{
|
||||
BTF: spec,
|
||||
ID: ID(bpfInfo.id),
|
||||
Name: internal.CString(nameBuffer),
|
||||
KernelBTF: bpfInfo.kernelBTF != 0,
|
||||
}, nil
|
||||
}
|
||||
8
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/strings.go
generated
vendored
8
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/strings.go
generated
vendored
@@ -5,13 +5,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type stringTable []byte
|
||||
|
||||
func readStringTable(r io.Reader) (stringTable, error) {
|
||||
contents, err := ioutil.ReadAll(r)
|
||||
contents, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read string table: %v", err)
|
||||
}
|
||||
@@ -53,8 +52,3 @@ func (st stringTable) Lookup(offset uint32) (string, error) {
|
||||
|
||||
return string(str[:end]), nil
|
||||
}
|
||||
|
||||
func (st stringTable) LookupName(offset uint32) (Name, error) {
|
||||
str, err := st.Lookup(offset)
|
||||
return Name(str), err
|
||||
}
|
||||
|
||||
31
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/syscalls.go
generated
vendored
Normal file
31
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/syscalls.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package btf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf/internal"
|
||||
)
|
||||
|
||||
type bpfBTFInfo struct {
|
||||
btf internal.Pointer
|
||||
btfSize uint32
|
||||
id uint32
|
||||
name internal.Pointer
|
||||
nameLen uint32
|
||||
kernelBTF uint32
|
||||
}
|
||||
|
||||
func bpfGetBTFInfoByFD(fd *internal.FD, btf, name []byte) (*bpfBTFInfo, error) {
|
||||
info := bpfBTFInfo{
|
||||
btf: internal.NewSlicePointer(btf),
|
||||
btfSize: uint32(len(btf)),
|
||||
name: internal.NewSlicePointer(name),
|
||||
nameLen: uint32(len(name)),
|
||||
}
|
||||
if err := internal.BPFObjGetInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil {
|
||||
return nil, fmt.Errorf("can't get program info: %w", err)
|
||||
}
|
||||
|
||||
return &info, nil
|
||||
}
|
||||
190
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
190
src/runtime/vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
@@ -30,27 +30,26 @@ type Type interface {
|
||||
walk(*typeDeque)
|
||||
}
|
||||
|
||||
// namedType is a type with a name.
|
||||
//
|
||||
// Most named types simply embed Name.
|
||||
type namedType interface {
|
||||
// NamedType is a type with a name.
|
||||
type NamedType interface {
|
||||
Type
|
||||
name() string
|
||||
essentialName() string
|
||||
|
||||
// Name of the type, empty for anonymous types.
|
||||
TypeName() string
|
||||
}
|
||||
|
||||
// Name identifies a type.
|
||||
//
|
||||
// Anonymous types have an empty name.
|
||||
type Name string
|
||||
|
||||
func (n Name) name() string {
|
||||
return string(n)
|
||||
}
|
||||
|
||||
func (n Name) essentialName() string {
|
||||
return essentialName(string(n))
|
||||
}
|
||||
var (
|
||||
_ NamedType = (*Int)(nil)
|
||||
_ NamedType = (*Struct)(nil)
|
||||
_ NamedType = (*Union)(nil)
|
||||
_ NamedType = (*Enum)(nil)
|
||||
_ NamedType = (*Fwd)(nil)
|
||||
_ NamedType = (*Func)(nil)
|
||||
_ NamedType = (*Typedef)(nil)
|
||||
_ NamedType = (*Var)(nil)
|
||||
_ NamedType = (*Datasec)(nil)
|
||||
_ NamedType = (*Float)(nil)
|
||||
)
|
||||
|
||||
// Void is the unit type of BTF.
|
||||
type Void struct{}
|
||||
@@ -72,19 +71,17 @@ const (
|
||||
// Int is an integer of a given length.
|
||||
type Int struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
|
||||
// The size of the integer in bytes.
|
||||
Size uint32
|
||||
Encoding IntEncoding
|
||||
// Offset is the starting bit offset. Currently always 0.
|
||||
// OffsetBits is the starting bit offset. Currently always 0.
|
||||
// See https://www.kernel.org/doc/html/latest/bpf/btf.html#btf-kind-int
|
||||
Offset uint32
|
||||
Bits byte
|
||||
OffsetBits uint32
|
||||
Bits byte
|
||||
}
|
||||
|
||||
var _ namedType = (*Int)(nil)
|
||||
|
||||
func (i *Int) String() string {
|
||||
var s strings.Builder
|
||||
|
||||
@@ -110,15 +107,16 @@ func (i *Int) String() string {
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (i *Int) size() uint32 { return i.Size }
|
||||
func (i *Int) walk(*typeDeque) {}
|
||||
func (i *Int) TypeName() string { return i.Name }
|
||||
func (i *Int) size() uint32 { return i.Size }
|
||||
func (i *Int) walk(*typeDeque) {}
|
||||
func (i *Int) copy() Type {
|
||||
cpy := *i
|
||||
return &cpy
|
||||
}
|
||||
|
||||
func (i *Int) isBitfield() bool {
|
||||
return i.Offset > 0
|
||||
return i.OffsetBits > 0
|
||||
}
|
||||
|
||||
// Pointer is a pointer to another type.
|
||||
@@ -158,7 +156,7 @@ func (arr *Array) copy() Type {
|
||||
// Struct is a compound type of consecutive members.
|
||||
type Struct struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
// The size of the struct including padding, in bytes
|
||||
Size uint32
|
||||
Members []Member
|
||||
@@ -168,6 +166,8 @@ func (s *Struct) String() string {
|
||||
return fmt.Sprintf("struct#%d[%q]", s.TypeID, s.Name)
|
||||
}
|
||||
|
||||
func (s *Struct) TypeName() string { return s.Name }
|
||||
|
||||
func (s *Struct) size() uint32 { return s.Size }
|
||||
|
||||
func (s *Struct) walk(tdq *typeDeque) {
|
||||
@@ -189,7 +189,7 @@ func (s *Struct) members() []Member {
|
||||
// Union is a compound type where members occupy the same memory.
|
||||
type Union struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
// The size of the union including padding, in bytes.
|
||||
Size uint32
|
||||
Members []Member
|
||||
@@ -199,6 +199,8 @@ func (u *Union) String() string {
|
||||
return fmt.Sprintf("union#%d[%q]", u.TypeID, u.Name)
|
||||
}
|
||||
|
||||
func (u *Union) TypeName() string { return u.Name }
|
||||
|
||||
func (u *Union) size() uint32 { return u.Size }
|
||||
|
||||
func (u *Union) walk(tdq *typeDeque) {
|
||||
@@ -236,17 +238,17 @@ var (
|
||||
//
|
||||
// It is not a valid Type.
|
||||
type Member struct {
|
||||
Name
|
||||
Name string
|
||||
Type Type
|
||||
// Offset is the bit offset of this member
|
||||
Offset uint32
|
||||
// OffsetBits is the bit offset of this member.
|
||||
OffsetBits uint32
|
||||
BitfieldSize uint32
|
||||
}
|
||||
|
||||
// Enum lists possible values.
|
||||
type Enum struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
Values []EnumValue
|
||||
}
|
||||
|
||||
@@ -254,11 +256,13 @@ func (e *Enum) String() string {
|
||||
return fmt.Sprintf("enum#%d[%q]", e.TypeID, e.Name)
|
||||
}
|
||||
|
||||
func (e *Enum) TypeName() string { return e.Name }
|
||||
|
||||
// EnumValue is part of an Enum
|
||||
//
|
||||
// Is is not a valid Type
|
||||
type EnumValue struct {
|
||||
Name
|
||||
Name string
|
||||
Value int32
|
||||
}
|
||||
|
||||
@@ -294,7 +298,7 @@ func (fk FwdKind) String() string {
|
||||
// Fwd is a forward declaration of a Type.
|
||||
type Fwd struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
Kind FwdKind
|
||||
}
|
||||
|
||||
@@ -302,6 +306,8 @@ func (f *Fwd) String() string {
|
||||
return fmt.Sprintf("fwd#%d[%s %q]", f.TypeID, f.Kind, f.Name)
|
||||
}
|
||||
|
||||
func (f *Fwd) TypeName() string { return f.Name }
|
||||
|
||||
func (f *Fwd) walk(*typeDeque) {}
|
||||
func (f *Fwd) copy() Type {
|
||||
cpy := *f
|
||||
@@ -311,7 +317,7 @@ func (f *Fwd) copy() Type {
|
||||
// Typedef is an alias of a Type.
|
||||
type Typedef struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
Type Type
|
||||
}
|
||||
|
||||
@@ -319,6 +325,8 @@ func (td *Typedef) String() string {
|
||||
return fmt.Sprintf("typedef#%d[%q #%d]", td.TypeID, td.Name, td.Type.ID())
|
||||
}
|
||||
|
||||
func (td *Typedef) TypeName() string { return td.Name }
|
||||
|
||||
func (td *Typedef) walk(tdq *typeDeque) { tdq.push(&td.Type) }
|
||||
func (td *Typedef) copy() Type {
|
||||
cpy := *td
|
||||
@@ -379,7 +387,7 @@ func (r *Restrict) copy() Type {
|
||||
// Func is a function definition.
|
||||
type Func struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
Type Type
|
||||
Linkage FuncLinkage
|
||||
}
|
||||
@@ -388,6 +396,8 @@ func (f *Func) String() string {
|
||||
return fmt.Sprintf("func#%d[%s %q proto=#%d]", f.TypeID, f.Linkage, f.Name, f.Type.ID())
|
||||
}
|
||||
|
||||
func (f *Func) TypeName() string { return f.Name }
|
||||
|
||||
func (f *Func) walk(tdq *typeDeque) { tdq.push(&f.Type) }
|
||||
func (f *Func) copy() Type {
|
||||
cpy := *f
|
||||
@@ -426,14 +436,14 @@ func (fp *FuncProto) copy() Type {
|
||||
}
|
||||
|
||||
type FuncParam struct {
|
||||
Name
|
||||
Name string
|
||||
Type Type
|
||||
}
|
||||
|
||||
// Var is a global variable.
|
||||
type Var struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
Type Type
|
||||
Linkage VarLinkage
|
||||
}
|
||||
@@ -442,6 +452,8 @@ func (v *Var) String() string {
|
||||
return fmt.Sprintf("var#%d[%s %q]", v.TypeID, v.Linkage, v.Name)
|
||||
}
|
||||
|
||||
func (v *Var) TypeName() string { return v.Name }
|
||||
|
||||
func (v *Var) walk(tdq *typeDeque) { tdq.push(&v.Type) }
|
||||
func (v *Var) copy() Type {
|
||||
cpy := *v
|
||||
@@ -451,7 +463,7 @@ func (v *Var) copy() Type {
|
||||
// Datasec is a global program section containing data.
|
||||
type Datasec struct {
|
||||
TypeID
|
||||
Name
|
||||
Name string
|
||||
Size uint32
|
||||
Vars []VarSecinfo
|
||||
}
|
||||
@@ -460,6 +472,8 @@ func (ds *Datasec) String() string {
|
||||
return fmt.Sprintf("section#%d[%q]", ds.TypeID, ds.Name)
|
||||
}
|
||||
|
||||
func (ds *Datasec) TypeName() string { return ds.Name }
|
||||
|
||||
func (ds *Datasec) size() uint32 { return ds.Size }
|
||||
|
||||
func (ds *Datasec) walk(tdq *typeDeque) {
|
||||
@@ -475,7 +489,7 @@ func (ds *Datasec) copy() Type {
|
||||
return &cpy
|
||||
}
|
||||
|
||||
// VarSecinfo describes variable in a Datasec
|
||||
// VarSecinfo describes variable in a Datasec.
|
||||
//
|
||||
// It is not a valid Type.
|
||||
type VarSecinfo struct {
|
||||
@@ -484,6 +498,27 @@ type VarSecinfo struct {
|
||||
Size uint32
|
||||
}
|
||||
|
||||
// Float is a float of a given length.
|
||||
type Float struct {
|
||||
TypeID
|
||||
Name string
|
||||
|
||||
// The size of the float in bytes.
|
||||
Size uint32
|
||||
}
|
||||
|
||||
func (f *Float) String() string {
|
||||
return fmt.Sprintf("float%d#%d[%q]", f.Size*8, f.TypeID, f.Name)
|
||||
}
|
||||
|
||||
func (f *Float) TypeName() string { return f.Name }
|
||||
func (f *Float) size() uint32 { return f.Size }
|
||||
func (f *Float) walk(*typeDeque) {}
|
||||
func (f *Float) copy() Type {
|
||||
cpy := *f
|
||||
return &cpy
|
||||
}
|
||||
|
||||
type sizer interface {
|
||||
size() uint32
|
||||
}
|
||||
@@ -565,14 +600,36 @@ func Sizeof(typ Type) (int, error) {
|
||||
//
|
||||
// Returns any errors from transform verbatim.
|
||||
func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) {
|
||||
var (
|
||||
copies = make(map[Type]Type)
|
||||
work typeDeque
|
||||
)
|
||||
copies := make(copier)
|
||||
return typ, copies.copy(&typ, transform)
|
||||
}
|
||||
|
||||
for t := &typ; t != nil; t = work.pop() {
|
||||
// copy a slice of Types recursively.
|
||||
//
|
||||
// Types may form a cycle.
|
||||
//
|
||||
// Returns any errors from transform verbatim.
|
||||
func copyTypes(types []Type, transform func(Type) (Type, error)) ([]Type, error) {
|
||||
result := make([]Type, len(types))
|
||||
copy(result, types)
|
||||
|
||||
copies := make(copier)
|
||||
for i := range result {
|
||||
if err := copies.copy(&result[i], transform); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type copier map[Type]Type
|
||||
|
||||
func (c copier) copy(typ *Type, transform func(Type) (Type, error)) error {
|
||||
var work typeDeque
|
||||
for t := typ; t != nil; t = work.pop() {
|
||||
// *t is the identity of the type.
|
||||
if cpy := copies[*t]; cpy != nil {
|
||||
if cpy := c[*t]; cpy != nil {
|
||||
*t = cpy
|
||||
continue
|
||||
}
|
||||
@@ -581,21 +638,21 @@ func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) {
|
||||
if transform != nil {
|
||||
tf, err := transform(*t)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copy %s: %w", typ, err)
|
||||
return fmt.Errorf("copy %s: %w", *t, err)
|
||||
}
|
||||
cpy = tf.copy()
|
||||
} else {
|
||||
cpy = (*t).copy()
|
||||
}
|
||||
|
||||
copies[*t] = cpy
|
||||
c[*t] = cpy
|
||||
*t = cpy
|
||||
|
||||
// Mark any nested types for copying.
|
||||
cpy.walk(&work)
|
||||
}
|
||||
|
||||
return typ, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// typeDeque keeps track of pointers to types which still
|
||||
@@ -606,6 +663,10 @@ type typeDeque struct {
|
||||
mask uint64
|
||||
}
|
||||
|
||||
func (dq *typeDeque) empty() bool {
|
||||
return dq.read == dq.write
|
||||
}
|
||||
|
||||
// push adds a type to the stack.
|
||||
func (dq *typeDeque) push(t *Type) {
|
||||
if dq.write-dq.read < uint64(len(dq.types)) {
|
||||
@@ -632,7 +693,7 @@ func (dq *typeDeque) push(t *Type) {
|
||||
|
||||
// shift returns the first element or null.
|
||||
func (dq *typeDeque) shift() *Type {
|
||||
if dq.read == dq.write {
|
||||
if dq.empty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -645,7 +706,7 @@ func (dq *typeDeque) shift() *Type {
|
||||
|
||||
// pop returns the last element or null.
|
||||
func (dq *typeDeque) pop() *Type {
|
||||
if dq.read == dq.write {
|
||||
if dq.empty() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -674,7 +735,7 @@ func (dq *typeDeque) all() []*Type {
|
||||
// Returns a map of named types (so, where NameOff is non-zero) and a slice of types
|
||||
// indexed by TypeID. Since BTF ignores compilation units, multiple types may share
|
||||
// the same name. A Type may form a cyclic graph by pointing at itself.
|
||||
func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, namedTypes map[string][]namedType, err error) {
|
||||
func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, namedTypes map[string][]NamedType, err error) {
|
||||
type fixupDef struct {
|
||||
id TypeID
|
||||
expectedKind btfKind
|
||||
@@ -691,17 +752,17 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type,
|
||||
// work, since otherwise append might re-allocate members.
|
||||
members := make([]Member, 0, len(raw))
|
||||
for i, btfMember := range raw {
|
||||
name, err := rawStrings.LookupName(btfMember.NameOff)
|
||||
name, err := rawStrings.Lookup(btfMember.NameOff)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get name for member %d: %w", i, err)
|
||||
}
|
||||
m := Member{
|
||||
Name: name,
|
||||
Offset: btfMember.Offset,
|
||||
Name: name,
|
||||
OffsetBits: btfMember.Offset,
|
||||
}
|
||||
if kindFlag {
|
||||
m.BitfieldSize = btfMember.Offset >> 24
|
||||
m.Offset &= 0xffffff
|
||||
m.OffsetBits &= 0xffffff
|
||||
}
|
||||
members = append(members, m)
|
||||
}
|
||||
@@ -713,7 +774,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type,
|
||||
|
||||
types = make([]Type, 0, len(rawTypes))
|
||||
types = append(types, (*Void)(nil))
|
||||
namedTypes = make(map[string][]namedType)
|
||||
namedTypes = make(map[string][]NamedType)
|
||||
|
||||
for i, raw := range rawTypes {
|
||||
var (
|
||||
@@ -723,7 +784,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type,
|
||||
typ Type
|
||||
)
|
||||
|
||||
name, err := rawStrings.LookupName(raw.NameOff)
|
||||
name, err := rawStrings.Lookup(raw.NameOff)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("get name for type id %d: %w", id, err)
|
||||
}
|
||||
@@ -765,7 +826,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type,
|
||||
rawvals := raw.data.([]btfEnum)
|
||||
vals := make([]EnumValue, 0, len(rawvals))
|
||||
for i, btfVal := range rawvals {
|
||||
name, err := rawStrings.LookupName(btfVal.NameOff)
|
||||
name, err := rawStrings.Lookup(btfVal.NameOff)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("get name for enum value %d: %s", i, err)
|
||||
}
|
||||
@@ -812,7 +873,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type,
|
||||
rawparams := raw.data.([]btfParam)
|
||||
params := make([]FuncParam, 0, len(rawparams))
|
||||
for i, param := range rawparams {
|
||||
name, err := rawStrings.LookupName(param.NameOff)
|
||||
name, err := rawStrings.Lookup(param.NameOff)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("get name for func proto parameter %d: %s", i, err)
|
||||
}
|
||||
@@ -848,14 +909,17 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type,
|
||||
}
|
||||
typ = &Datasec{id, name, raw.SizeType, vars}
|
||||
|
||||
case kindFloat:
|
||||
typ = &Float{id, name, raw.Size()}
|
||||
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
|
||||
}
|
||||
|
||||
types = append(types, typ)
|
||||
|
||||
if named, ok := typ.(namedType); ok {
|
||||
if name := essentialName(named.name()); name != "" {
|
||||
if named, ok := typ.(NamedType); ok {
|
||||
if name := essentialName(named.TypeName()); name != "" {
|
||||
namedTypes[name] = append(namedTypes[name], named)
|
||||
}
|
||||
}
|
||||
|
||||
4
src/runtime/vendor/github.com/cilium/ebpf/internal/cpu.go
generated
vendored
4
src/runtime/vendor/github.com/cilium/ebpf/internal/cpu.go
generated
vendored
@@ -2,7 +2,7 @@ package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
@@ -24,7 +24,7 @@ func PossibleCPUs() (int, error) {
|
||||
}
|
||||
|
||||
func parseCPUsFromFile(path string) (int, error) {
|
||||
spec, err := ioutil.ReadFile(path)
|
||||
spec, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
1
src/runtime/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go
generated
vendored
1
src/runtime/vendor/github.com/cilium/ebpf/internal/ptr_32_be.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build armbe || mips || mips64p32
|
||||
// +build armbe mips mips64p32
|
||||
|
||||
package internal
|
||||
|
||||
1
src/runtime/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go
generated
vendored
1
src/runtime/vendor/github.com/cilium/ebpf/internal/ptr_32_le.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build 386 || amd64p32 || arm || mipsle || mips64p32le
|
||||
// +build 386 amd64p32 arm mipsle mips64p32le
|
||||
|
||||
package internal
|
||||
|
||||
4
src/runtime/vendor/github.com/cilium/ebpf/internal/ptr_64.go
generated
vendored
4
src/runtime/vendor/github.com/cilium/ebpf/internal/ptr_64.go
generated
vendored
@@ -1,5 +1,5 @@
|
||||
// +build !386,!amd64p32,!arm,!mipsle,!mips64p32le
|
||||
// +build !armbe,!mips,!mips64p32
|
||||
//go:build !386 && !amd64p32 && !arm && !mipsle && !mips64p32le && !armbe && !mips && !mips64p32
|
||||
// +build !386,!amd64p32,!arm,!mipsle,!mips64p32le,!armbe,!mips,!mips64p32
|
||||
|
||||
package internal
|
||||
|
||||
|
||||
59
src/runtime/vendor/github.com/cilium/ebpf/internal/syscall.go
generated
vendored
59
src/runtime/vendor/github.com/cilium/ebpf/internal/syscall.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -68,6 +69,48 @@ func BPF(cmd BPFCmd, attr unsafe.Pointer, size uintptr) (uintptr, error) {
|
||||
return r1, err
|
||||
}
|
||||
|
||||
type BPFProgLoadAttr struct {
|
||||
ProgType uint32
|
||||
InsCount uint32
|
||||
Instructions Pointer
|
||||
License Pointer
|
||||
LogLevel uint32
|
||||
LogSize uint32
|
||||
LogBuf Pointer
|
||||
KernelVersion uint32 // since 4.1 2541517c32be
|
||||
ProgFlags uint32 // since 4.11 e07b98d9bffe
|
||||
ProgName BPFObjName // since 4.15 067cae47771c
|
||||
ProgIfIndex uint32 // since 4.15 1f6f4cb7ba21
|
||||
ExpectedAttachType uint32 // since 4.17 5e43f899b03a
|
||||
ProgBTFFd uint32
|
||||
FuncInfoRecSize uint32
|
||||
FuncInfo Pointer
|
||||
FuncInfoCnt uint32
|
||||
LineInfoRecSize uint32
|
||||
LineInfo Pointer
|
||||
LineInfoCnt uint32
|
||||
AttachBTFID uint32
|
||||
AttachProgFd uint32
|
||||
}
|
||||
|
||||
// BPFProgLoad wraps BPF_PROG_LOAD.
|
||||
func BPFProgLoad(attr *BPFProgLoadAttr) (*FD, error) {
|
||||
for {
|
||||
fd, err := BPF(BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||
// As of ~4.20 the verifier can be interrupted by a signal,
|
||||
// and returns EAGAIN in that case.
|
||||
if errors.Is(err, unix.EAGAIN) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewFD(uint32(fd)), nil
|
||||
}
|
||||
}
|
||||
|
||||
type BPFProgAttachAttr struct {
|
||||
TargetFd uint32
|
||||
AttachBpfFd uint32
|
||||
@@ -180,6 +223,22 @@ func BPFObjGetInfoByFD(fd *FD, info unsafe.Pointer, size uintptr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type bpfGetFDByIDAttr struct {
|
||||
id uint32
|
||||
next uint32
|
||||
}
|
||||
|
||||
// BPFObjGetInfoByFD wraps BPF_*_GET_FD_BY_ID.
|
||||
//
|
||||
// Available from 4.13.
|
||||
func BPFObjGetFDByID(cmd BPFCmd, id uint32) (*FD, error) {
|
||||
attr := bpfGetFDByIDAttr{
|
||||
id: id,
|
||||
}
|
||||
ptr, err := BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||
return NewFD(uint32(ptr)), err
|
||||
}
|
||||
|
||||
// BPFObjName is a null-terminated string made up of
|
||||
// 'A-Za-z0-9_' characters.
|
||||
type BPFObjName [unix.BPF_OBJ_NAME_LEN]byte
|
||||
|
||||
16
src/runtime/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
16
src/runtime/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package unix
|
||||
@@ -20,10 +21,11 @@ const (
|
||||
EPERM = linux.EPERM
|
||||
ESRCH = linux.ESRCH
|
||||
ENODEV = linux.ENODEV
|
||||
EBADF = linux.EBADF
|
||||
E2BIG = linux.E2BIG
|
||||
// ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP
|
||||
ENOTSUPP = syscall.Errno(0x20c)
|
||||
|
||||
EBADF = linux.EBADF
|
||||
BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC
|
||||
BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE
|
||||
BPF_F_RDONLY = linux.BPF_F_RDONLY
|
||||
@@ -35,6 +37,9 @@ const (
|
||||
BPF_F_INNER_MAP = linux.BPF_F_INNER_MAP
|
||||
BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN
|
||||
BPF_TAG_SIZE = linux.BPF_TAG_SIZE
|
||||
BPF_RINGBUF_BUSY_BIT = linux.BPF_RINGBUF_BUSY_BIT
|
||||
BPF_RINGBUF_DISCARD_BIT = linux.BPF_RINGBUF_DISCARD_BIT
|
||||
BPF_RINGBUF_HDR_SZ = linux.BPF_RINGBUF_HDR_SZ
|
||||
SYS_BPF = linux.SYS_BPF
|
||||
F_DUPFD_CLOEXEC = linux.F_DUPFD_CLOEXEC
|
||||
EPOLL_CTL_ADD = linux.EPOLL_CTL_ADD
|
||||
@@ -69,11 +74,6 @@ type Statfs_t = linux.Statfs_t
|
||||
// Rlimit is a wrapper
|
||||
type Rlimit = linux.Rlimit
|
||||
|
||||
// Setrlimit is a wrapper
|
||||
func Setrlimit(resource int, rlim *Rlimit) (err error) {
|
||||
return linux.Setrlimit(resource, rlim)
|
||||
}
|
||||
|
||||
// Syscall is a wrapper
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return linux.Syscall(trap, a1, a2, a3)
|
||||
@@ -202,3 +202,7 @@ func KernelRelease() (string, error) {
|
||||
release := string(uname.Release[:end])
|
||||
return release, nil
|
||||
}
|
||||
|
||||
func Prlimit(pid, resource int, new, old *Rlimit) error {
|
||||
return linux.Prlimit(pid, resource, new, old)
|
||||
}
|
||||
|
||||
14
src/runtime/vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
14
src/runtime/vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
@@ -1,3 +1,4 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package unix
|
||||
@@ -21,6 +22,7 @@ const (
|
||||
ESRCH = syscall.ESRCH
|
||||
ENODEV = syscall.ENODEV
|
||||
EBADF = syscall.Errno(0)
|
||||
E2BIG = syscall.Errno(0)
|
||||
// ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP
|
||||
ENOTSUPP = syscall.Errno(0x20c)
|
||||
|
||||
@@ -35,6 +37,9 @@ const (
|
||||
BPF_F_INNER_MAP = 0
|
||||
BPF_OBJ_NAME_LEN = 0x10
|
||||
BPF_TAG_SIZE = 0x8
|
||||
BPF_RINGBUF_BUSY_BIT = 0
|
||||
BPF_RINGBUF_DISCARD_BIT = 0
|
||||
BPF_RINGBUF_HDR_SZ = 0
|
||||
SYS_BPF = 321
|
||||
F_DUPFD_CLOEXEC = 0x406
|
||||
EPOLLIN = 0x1
|
||||
@@ -86,11 +91,6 @@ type Rlimit struct {
|
||||
Max uint64
|
||||
}
|
||||
|
||||
// Setrlimit is a wrapper
|
||||
func Setrlimit(resource int, rlim *Rlimit) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
// Syscall is a wrapper
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
return 0, 0, syscall.Errno(1)
|
||||
@@ -261,3 +261,7 @@ func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags
|
||||
func KernelRelease() (string, error) {
|
||||
return "", errNonLinux
|
||||
}
|
||||
|
||||
func Prlimit(pid, resource int, new, old *Rlimit) error {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
4
src/runtime/vendor/github.com/cilium/ebpf/internal/version.go
generated
vendored
4
src/runtime/vendor/github.com/cilium/ebpf/internal/version.go
generated
vendored
@@ -2,7 +2,7 @@ package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"sync"
|
||||
|
||||
@@ -109,7 +109,7 @@ func detectKernelVersion() (Version, error) {
|
||||
// Example format: Ubuntu 4.15.0-91.92-generic 4.15.18
|
||||
// This method exists in the kernel itself, see d18acd15c
|
||||
// ("perf tools: Fix kernel version error in ubuntu").
|
||||
if pvs, err := ioutil.ReadFile("/proc/version_signature"); err == nil {
|
||||
if pvs, err := os.ReadFile("/proc/version_signature"); err == nil {
|
||||
// If /proc/version_signature exists, failing to parse it is an error.
|
||||
// It only exists on Ubuntu, where the real patch level is not obtainable
|
||||
// through any other method.
|
||||
|
||||
88
src/runtime/vendor/github.com/cilium/ebpf/link/freplace.go
generated
vendored
Normal file
88
src/runtime/vendor/github.com/cilium/ebpf/link/freplace.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/internal/btf"
|
||||
)
|
||||
|
||||
type FreplaceLink struct {
|
||||
RawLink
|
||||
}
|
||||
|
||||
// AttachFreplace attaches the given eBPF program to the function it replaces.
|
||||
//
|
||||
// The program and name can either be provided at link time, or can be provided
|
||||
// at program load time. If they were provided at load time, they should be nil
|
||||
// and empty respectively here, as they will be ignored by the kernel.
|
||||
// Examples:
|
||||
//
|
||||
// AttachFreplace(dispatcher, "function", replacement)
|
||||
// AttachFreplace(nil, "", replacement)
|
||||
func AttachFreplace(targetProg *ebpf.Program, name string, prog *ebpf.Program) (*FreplaceLink, error) {
|
||||
if (name == "") != (targetProg == nil) {
|
||||
return nil, fmt.Errorf("must provide both or neither of name and targetProg: %w", errInvalidInput)
|
||||
}
|
||||
if prog == nil {
|
||||
return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
|
||||
}
|
||||
if prog.Type() != ebpf.Extension {
|
||||
return nil, fmt.Errorf("eBPF program type %s is not an Extension: %w", prog.Type(), errInvalidInput)
|
||||
}
|
||||
|
||||
var (
|
||||
target int
|
||||
typeID btf.TypeID
|
||||
)
|
||||
if targetProg != nil {
|
||||
info, err := targetProg.Info()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
btfID, ok := info.BTFID()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not get BTF ID for program %s: %w", info.Name, errInvalidInput)
|
||||
}
|
||||
btfHandle, err := btf.NewHandleFromID(btfID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer btfHandle.Close()
|
||||
|
||||
var function *btf.Func
|
||||
if err := btfHandle.Spec().FindType(name, &function); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
target = targetProg.FD()
|
||||
typeID = function.ID()
|
||||
}
|
||||
|
||||
link, err := AttachRawLink(RawLinkOptions{
|
||||
Target: target,
|
||||
Program: prog,
|
||||
Attach: ebpf.AttachNone,
|
||||
BTF: typeID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &FreplaceLink{*link}, nil
|
||||
}
|
||||
|
||||
// Update implements the Link interface.
|
||||
func (f *FreplaceLink) Update(new *ebpf.Program) error {
|
||||
return fmt.Errorf("freplace update: %w", ErrNotSupported)
|
||||
}
|
||||
|
||||
// LoadPinnedFreplace loads a pinned iterator from a bpffs.
|
||||
func LoadPinnedFreplace(fileName string, opts *ebpf.LoadPinOptions) (*FreplaceLink, error) {
|
||||
link, err := LoadPinnedRawLink(fileName, TracingType, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &FreplaceLink{*link}, err
|
||||
}
|
||||
38
src/runtime/vendor/github.com/cilium/ebpf/link/kprobe.go
generated
vendored
38
src/runtime/vendor/github.com/cilium/ebpf/link/kprobe.go
generated
vendored
@@ -5,7 +5,6 @@ import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -72,10 +71,11 @@ func (pt probeType) RetprobeBit() (uint64, error) {
|
||||
// given kernel symbol starts executing. See /proc/kallsyms for available
|
||||
// symbols. For example, printk():
|
||||
//
|
||||
// Kprobe("printk", prog)
|
||||
// kp, err := Kprobe("printk", prog)
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources.
|
||||
// Losing the reference to the resulting Link (kp) will close the Kprobe
|
||||
// and prevent further execution of prog. The Link must be Closed during
|
||||
// program shutdown to avoid leaking system resources.
|
||||
func Kprobe(symbol string, prog *ebpf.Program) (Link, error) {
|
||||
k, err := kprobe(symbol, prog, false)
|
||||
if err != nil {
|
||||
@@ -95,10 +95,11 @@ func Kprobe(symbol string, prog *ebpf.Program) (Link, error) {
|
||||
// before the given kernel symbol exits, with the function stack left intact.
|
||||
// See /proc/kallsyms for available symbols. For example, printk():
|
||||
//
|
||||
// Kretprobe("printk", prog)
|
||||
// kp, err := Kretprobe("printk", prog)
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources.
|
||||
// Losing the reference to the resulting Link (kp) will close the Kretprobe
|
||||
// and prevent further execution of prog. The Link must be Closed during
|
||||
// program shutdown to avoid leaking system resources.
|
||||
func Kretprobe(symbol string, prog *ebpf.Program) (Link, error) {
|
||||
k, err := kprobe(symbol, prog, true)
|
||||
if err != nil {
|
||||
@@ -157,7 +158,7 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
|
||||
// pmuKprobe opens a perf event based on the kprobe PMU.
|
||||
// Returns os.ErrNotExist if the given symbol does not exist in the kernel.
|
||||
func pmuKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
return pmuProbe(kprobeType, symbol, "", 0, ret)
|
||||
return pmuProbe(kprobeType, symbol, "", 0, perfAllThreads, ret)
|
||||
}
|
||||
|
||||
// pmuProbe opens a perf event based on a Performance Monitoring Unit.
|
||||
@@ -167,7 +168,7 @@ func pmuKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
// 33ea4b24277b "perf/core: Implement the 'perf_uprobe' PMU"
|
||||
//
|
||||
// Returns ErrNotSupported if the kernel doesn't support perf_[k,u]probe PMU
|
||||
func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
func pmuProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
|
||||
// Getting the PMU type will fail if the kernel doesn't support
|
||||
// the perf_[k,u]probe PMU.
|
||||
et, err := getPMUEventType(typ)
|
||||
@@ -191,7 +192,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per
|
||||
switch typ {
|
||||
case kprobeType:
|
||||
// Create a pointer to a NUL-terminated string for the kernel.
|
||||
sp, err := unsafeStringPtr(symbol)
|
||||
sp, err = unsafeStringPtr(symbol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -202,7 +203,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per
|
||||
Config: config, // Retprobe flag
|
||||
}
|
||||
case uprobeType:
|
||||
sp, err := unsafeStringPtr(path)
|
||||
sp, err = unsafeStringPtr(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -220,7 +221,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per
|
||||
}
|
||||
}
|
||||
|
||||
fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
|
||||
fd, err := unix.PerfEventOpen(&attr, pid, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
|
||||
|
||||
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
|
||||
// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
|
||||
@@ -228,6 +229,11 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per
|
||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
||||
return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, os.ErrNotExist)
|
||||
}
|
||||
// Since at least commit cb9a19fe4aa51, ENOTSUPP is returned
|
||||
// when attempting to set a uprobe on a trap instruction.
|
||||
if errors.Is(err, unix.ENOTSUPP) {
|
||||
return nil, fmt.Errorf("failed setting uprobe on offset %#x (possible trap insn): %w", offset, err)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening perf event: %w", err)
|
||||
}
|
||||
@@ -246,7 +252,7 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per
|
||||
|
||||
// tracefsKprobe creates a Kprobe tracefs entry.
|
||||
func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
return tracefsProbe(kprobeType, symbol, "", 0, ret)
|
||||
return tracefsProbe(kprobeType, symbol, "", 0, perfAllThreads, ret)
|
||||
}
|
||||
|
||||
// tracefsProbe creates a trace event by writing an entry to <tracefs>/[k,u]probe_events.
|
||||
@@ -255,7 +261,7 @@ func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
// Path and offset are only set in the case of uprobe(s) and are used to set
|
||||
// the executable/library path on the filesystem and the offset where the probe is inserted.
|
||||
// A perf event is then opened on the newly-created trace event and returned to the caller.
|
||||
func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
func tracefsProbe(typ probeType, symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
|
||||
// Generate a random string for each trace event we attempt to create.
|
||||
// This value is used as the 'group' token in tracefs to allow creating
|
||||
// multiple kprobe trace events with the same name.
|
||||
@@ -288,7 +294,7 @@ func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) (
|
||||
}
|
||||
|
||||
// Kprobes are ephemeral tracepoints and share the same perf event type.
|
||||
fd, err := openTracepointPerfEvent(tid)
|
||||
fd, err := openTracepointPerfEvent(tid, pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -413,7 +419,7 @@ func probePrefix(ret bool) string {
|
||||
func determineRetprobeBit(typ probeType) (uint64, error) {
|
||||
p := filepath.Join("/sys/bus/event_source/devices/", typ.String(), "/format/retprobe")
|
||||
|
||||
data, err := ioutil.ReadFile(p)
|
||||
data, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
14
src/runtime/vendor/github.com/cilium/ebpf/link/link.go
generated
vendored
14
src/runtime/vendor/github.com/cilium/ebpf/link/link.go
generated
vendored
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
"github.com/cilium/ebpf/internal/btf"
|
||||
)
|
||||
|
||||
var ErrNotSupported = internal.ErrNotSupported
|
||||
@@ -29,8 +30,8 @@ type Link interface {
|
||||
|
||||
// Close frees resources.
|
||||
//
|
||||
// The link will be broken unless it has been pinned. A link
|
||||
// may continue past the lifetime of the process if Close is
|
||||
// The link will be broken unless it has been successfully pinned.
|
||||
// A link may continue past the lifetime of the process if Close is
|
||||
// not called.
|
||||
Close() error
|
||||
|
||||
@@ -49,6 +50,8 @@ type RawLinkOptions struct {
|
||||
Program *ebpf.Program
|
||||
// Attach must match the attach type of Program.
|
||||
Attach ebpf.AttachType
|
||||
// BTF is the BTF of the attachment target.
|
||||
BTF btf.TypeID
|
||||
}
|
||||
|
||||
// RawLinkInfo contains metadata on a link.
|
||||
@@ -83,9 +86,10 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
|
||||
}
|
||||
|
||||
attr := bpfLinkCreateAttr{
|
||||
targetFd: uint32(opts.Target),
|
||||
progFd: uint32(progFd),
|
||||
attachType: opts.Attach,
|
||||
targetFd: uint32(opts.Target),
|
||||
progFd: uint32(progFd),
|
||||
attachType: opts.Attach,
|
||||
targetBTFID: uint32(opts.BTF),
|
||||
}
|
||||
fd, err := bpfLinkCreate(&attr)
|
||||
if err != nil {
|
||||
|
||||
7
src/runtime/vendor/github.com/cilium/ebpf/link/perf_event.go
generated
vendored
7
src/runtime/vendor/github.com/cilium/ebpf/link/perf_event.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -236,7 +235,7 @@ func getPMUEventType(typ probeType) (uint64, error) {
|
||||
// openTracepointPerfEvent opens a tracepoint-type perf event. System-wide
|
||||
// [k,u]probes created by writing to <tracefs>/[k,u]probe_events are tracepoints
|
||||
// behind the scenes, and can be attached to using these perf events.
|
||||
func openTracepointPerfEvent(tid uint64) (*internal.FD, error) {
|
||||
func openTracepointPerfEvent(tid uint64, pid int) (*internal.FD, error) {
|
||||
attr := unix.PerfEventAttr{
|
||||
Type: unix.PERF_TYPE_TRACEPOINT,
|
||||
Config: tid,
|
||||
@@ -245,7 +244,7 @@ func openTracepointPerfEvent(tid uint64) (*internal.FD, error) {
|
||||
Wakeup: 1,
|
||||
}
|
||||
|
||||
fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
|
||||
fd, err := unix.PerfEventOpen(&attr, pid, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening tracepoint perf event: %w", err)
|
||||
}
|
||||
@@ -263,7 +262,7 @@ func uint64FromFile(base string, path ...string) (uint64, error) {
|
||||
return 0, fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(p)
|
||||
data, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading file %s: %w", p, err)
|
||||
}
|
||||
|
||||
9
src/runtime/vendor/github.com/cilium/ebpf/link/syscalls.go
generated
vendored
9
src/runtime/vendor/github.com/cilium/ebpf/link/syscalls.go
generated
vendored
@@ -88,10 +88,11 @@ var haveProgAttachReplace = internal.FeatureTest("BPF_PROG_ATTACH atomic replace
|
||||
})
|
||||
|
||||
type bpfLinkCreateAttr struct {
|
||||
progFd uint32
|
||||
targetFd uint32
|
||||
attachType ebpf.AttachType
|
||||
flags uint32
|
||||
progFd uint32
|
||||
targetFd uint32
|
||||
attachType ebpf.AttachType
|
||||
flags uint32
|
||||
targetBTFID uint32
|
||||
}
|
||||
|
||||
func bpfLinkCreate(attr *bpfLinkCreateAttr) (*internal.FD, error) {
|
||||
|
||||
8
src/runtime/vendor/github.com/cilium/ebpf/link/tracepoint.go
generated
vendored
8
src/runtime/vendor/github.com/cilium/ebpf/link/tracepoint.go
generated
vendored
@@ -11,7 +11,11 @@ import (
|
||||
// tracepoints. The top-level directory is the group, the event's subdirectory
|
||||
// is the name. Example:
|
||||
//
|
||||
// Tracepoint("syscalls", "sys_enter_fork", prog)
|
||||
// tp, err := Tracepoint("syscalls", "sys_enter_fork", prog)
|
||||
//
|
||||
// Losing the reference to the resulting Link (tp) will close the Tracepoint
|
||||
// and prevent further execution of prog. The Link must be Closed during
|
||||
// program shutdown to avoid leaking system resources.
|
||||
//
|
||||
// Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is
|
||||
// only possible as of kernel 4.14 (commit cf5f5ce).
|
||||
@@ -34,7 +38,7 @@ func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fd, err := openTracepointPerfEvent(tid)
|
||||
fd, err := openTracepointPerfEvent(tid, perfAllThreads)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
135
src/runtime/vendor/github.com/cilium/ebpf/link/uprobe.go
generated
vendored
135
src/runtime/vendor/github.com/cilium/ebpf/link/uprobe.go
generated
vendored
@@ -25,14 +25,18 @@ var (
|
||||
value uint64
|
||||
err error
|
||||
}{}
|
||||
|
||||
// ErrNoSymbol indicates that the given symbol was not found
|
||||
// in the ELF symbols table.
|
||||
ErrNoSymbol = errors.New("not found")
|
||||
)
|
||||
|
||||
// Executable defines an executable program on the filesystem.
|
||||
type Executable struct {
|
||||
// Path of the executable on the filesystem.
|
||||
path string
|
||||
// Parsed ELF symbols and dynamic symbols.
|
||||
symbols map[string]elf.Symbol
|
||||
// Parsed ELF symbols and dynamic symbols offsets.
|
||||
offsets map[string]uint64
|
||||
}
|
||||
|
||||
// UprobeOptions defines additional parameters that will be used
|
||||
@@ -41,6 +45,9 @@ type UprobeOptions struct {
|
||||
// Symbol offset. Must be provided in case of external symbols (shared libs).
|
||||
// If set, overrides the offset eventually parsed from the executable.
|
||||
Offset uint64
|
||||
// Only set the uprobe on the given process ID. Useful when tracing
|
||||
// shared library calls or programs that have many running instances.
|
||||
PID int
|
||||
}
|
||||
|
||||
// To open a new Executable, use:
|
||||
@@ -64,42 +71,84 @@ func OpenExecutable(path string) (*Executable, error) {
|
||||
return nil, fmt.Errorf("parse ELF file: %w", err)
|
||||
}
|
||||
|
||||
var ex = Executable{
|
||||
path: path,
|
||||
symbols: make(map[string]elf.Symbol),
|
||||
}
|
||||
if err := ex.addSymbols(se.Symbols); err != nil {
|
||||
return nil, err
|
||||
if se.Type != elf.ET_EXEC && se.Type != elf.ET_DYN {
|
||||
// ELF is not an executable or a shared object.
|
||||
return nil, errors.New("the given file is not an executable or a shared object")
|
||||
}
|
||||
|
||||
if err := ex.addSymbols(se.DynamicSymbols); err != nil {
|
||||
ex := Executable{
|
||||
path: path,
|
||||
offsets: make(map[string]uint64),
|
||||
}
|
||||
|
||||
if err := ex.load(se); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ex, nil
|
||||
}
|
||||
|
||||
func (ex *Executable) addSymbols(f func() ([]elf.Symbol, error)) error {
|
||||
// elf.Symbols and elf.DynamicSymbols return ErrNoSymbols if the section is not found.
|
||||
syms, err := f()
|
||||
func (ex *Executable) load(f *internal.SafeELFFile) error {
|
||||
syms, err := f.Symbols()
|
||||
if err != nil && !errors.Is(err, elf.ErrNoSymbols) {
|
||||
return err
|
||||
}
|
||||
|
||||
dynsyms, err := f.DynamicSymbols()
|
||||
if err != nil && !errors.Is(err, elf.ErrNoSymbols) {
|
||||
return err
|
||||
}
|
||||
|
||||
syms = append(syms, dynsyms...)
|
||||
|
||||
for _, s := range syms {
|
||||
if elf.ST_TYPE(s.Info) != elf.STT_FUNC {
|
||||
// Symbol not associated with a function or other executable code.
|
||||
continue
|
||||
}
|
||||
ex.symbols[s.Name] = s
|
||||
|
||||
off := s.Value
|
||||
|
||||
// Loop over ELF segments.
|
||||
for _, prog := range f.Progs {
|
||||
// Skip uninteresting segments.
|
||||
if prog.Type != elf.PT_LOAD || (prog.Flags&elf.PF_X) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if prog.Vaddr <= s.Value && s.Value < (prog.Vaddr+prog.Memsz) {
|
||||
// If the symbol value is contained in the segment, calculate
|
||||
// the symbol offset.
|
||||
//
|
||||
// fn symbol offset = fn symbol VA - .text VA + .text offset
|
||||
//
|
||||
// stackoverflow.com/a/40249502
|
||||
off = s.Value - prog.Vaddr + prog.Off
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ex.offsets[s.Name] = off
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) {
|
||||
if s, ok := ex.symbols[symbol]; ok {
|
||||
return &s, nil
|
||||
func (ex *Executable) offset(symbol string) (uint64, error) {
|
||||
if off, ok := ex.offsets[symbol]; ok {
|
||||
// Symbols with location 0 from section undef are shared library calls and
|
||||
// are relocated before the binary is executed. Dynamic linking is not
|
||||
// implemented by the library, so mark this as unsupported for now.
|
||||
//
|
||||
// Since only offset values are stored and not elf.Symbol, if the value is 0,
|
||||
// assume it's an external symbol.
|
||||
if off == 0 {
|
||||
return 0, fmt.Errorf("cannot resolve %s library call '%s', "+
|
||||
"consider providing the offset via options: %w", ex.path, symbol, ErrNotSupported)
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
return nil, fmt.Errorf("symbol %s not found", symbol)
|
||||
return 0, fmt.Errorf("symbol %s: %w", symbol, ErrNoSymbol)
|
||||
}
|
||||
|
||||
// Uprobe attaches the given eBPF program to a perf event that fires when the
|
||||
@@ -112,11 +161,14 @@ func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) {
|
||||
// When using symbols which belongs to shared libraries,
|
||||
// an offset must be provided via options:
|
||||
//
|
||||
// ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||
// up, err := ex.Uprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources. Functions provided by shared libraries can currently not
|
||||
// be traced and will result in an ErrNotSupported.
|
||||
// Losing the reference to the resulting Link (up) will close the Uprobe
|
||||
// and prevent further execution of prog. The Link must be Closed during
|
||||
// program shutdown to avoid leaking system resources.
|
||||
//
|
||||
// Functions provided by shared libraries can currently not be traced and
|
||||
// will result in an ErrNotSupported.
|
||||
func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) {
|
||||
u, err := ex.uprobe(symbol, prog, opts, false)
|
||||
if err != nil {
|
||||
@@ -141,11 +193,14 @@ func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
||||
// When using symbols which belongs to shared libraries,
|
||||
// an offset must be provided via options:
|
||||
//
|
||||
// ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||
// up, err := ex.Uretprobe("main", prog, &UprobeOptions{Offset: 0x123})
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources. Functions provided by shared libraries can currently not
|
||||
// be traced and will result in an ErrNotSupported.
|
||||
// Losing the reference to the resulting Link (up) will close the Uprobe
|
||||
// and prevent further execution of prog. The Link must be Closed during
|
||||
// program shutdown to avoid leaking system resources.
|
||||
//
|
||||
// Functions provided by shared libraries can currently not be traced and
|
||||
// will result in an ErrNotSupported.
|
||||
func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program, opts *UprobeOptions) (Link, error) {
|
||||
u, err := ex.uprobe(symbol, prog, opts, true)
|
||||
if err != nil {
|
||||
@@ -175,24 +230,20 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
||||
if opts != nil && opts.Offset != 0 {
|
||||
offset = opts.Offset
|
||||
} else {
|
||||
sym, err := ex.symbol(symbol)
|
||||
off, err := ex.offset(symbol)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, err)
|
||||
return nil, err
|
||||
}
|
||||
offset = off
|
||||
}
|
||||
|
||||
// Symbols with location 0 from section undef are shared library calls and
|
||||
// are relocated before the binary is executed. Dynamic linking is not
|
||||
// implemented by the library, so mark this as unsupported for now.
|
||||
if sym.Section == elf.SHN_UNDEF && sym.Value == 0 {
|
||||
return nil, fmt.Errorf("cannot resolve %s library call '%s', "+
|
||||
"consider providing the offset via options: %w", ex.path, symbol, ErrNotSupported)
|
||||
}
|
||||
|
||||
offset = sym.Value
|
||||
pid := perfAllThreads
|
||||
if opts != nil && opts.PID != 0 {
|
||||
pid = opts.PID
|
||||
}
|
||||
|
||||
// Use uprobe PMU if the kernel has it available.
|
||||
tp, err := pmuUprobe(symbol, ex.path, offset, ret)
|
||||
tp, err := pmuUprobe(symbol, ex.path, offset, pid, ret)
|
||||
if err == nil {
|
||||
return tp, nil
|
||||
}
|
||||
@@ -201,7 +252,7 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
||||
}
|
||||
|
||||
// Use tracefs if uprobe PMU is missing.
|
||||
tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, ret)
|
||||
tp, err = tracefsUprobe(uprobeSanitizedSymbol(symbol), ex.path, offset, pid, ret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating trace event '%s:%s' in tracefs: %w", ex.path, symbol, err)
|
||||
}
|
||||
@@ -210,13 +261,13 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
||||
}
|
||||
|
||||
// pmuUprobe opens a perf event based on the uprobe PMU.
|
||||
func pmuUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
return pmuProbe(uprobeType, symbol, path, offset, ret)
|
||||
func pmuUprobe(symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
|
||||
return pmuProbe(uprobeType, symbol, path, offset, pid, ret)
|
||||
}
|
||||
|
||||
// tracefsUprobe creates a Uprobe tracefs entry.
|
||||
func tracefsUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
return tracefsProbe(uprobeType, symbol, path, offset, ret)
|
||||
func tracefsUprobe(symbol, path string, offset uint64, pid int, ret bool) (*perfEvent, error) {
|
||||
return tracefsProbe(uprobeType, symbol, path, offset, pid, ret)
|
||||
}
|
||||
|
||||
// uprobeSanitizedSymbol replaces every invalid characted for the tracefs api with an underscore.
|
||||
|
||||
23
src/runtime/vendor/github.com/cilium/ebpf/linker.go
generated
vendored
23
src/runtime/vendor/github.com/cilium/ebpf/linker.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cilium/ebpf/asm"
|
||||
"github.com/cilium/ebpf/internal/btf"
|
||||
)
|
||||
|
||||
// link resolves bpf-to-bpf calls.
|
||||
@@ -40,7 +39,7 @@ func link(prog *ProgramSpec, libs []*ProgramSpec) error {
|
||||
pending = append(pending, lib.Instructions)
|
||||
|
||||
if prog.BTF != nil && lib.BTF != nil {
|
||||
if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil {
|
||||
if err := prog.BTF.Append(lib.BTF); err != nil {
|
||||
return fmt.Errorf("linking BTF of %s: %w", lib.Name, err)
|
||||
}
|
||||
}
|
||||
@@ -136,5 +135,25 @@ func fixupJumpsAndCalls(insns asm.Instructions) error {
|
||||
}
|
||||
}
|
||||
|
||||
// fixupBPFCalls replaces bpf_probe_read_{kernel,user}[_str] with bpf_probe_read[_str] on older kernels
|
||||
// https://github.com/libbpf/libbpf/blob/master/src/libbpf.c#L6009
|
||||
iter = insns.Iterate()
|
||||
for iter.Next() {
|
||||
ins := iter.Ins
|
||||
if !ins.IsBuiltinCall() {
|
||||
continue
|
||||
}
|
||||
switch asm.BuiltinFunc(ins.Constant) {
|
||||
case asm.FnProbeReadKernel, asm.FnProbeReadUser:
|
||||
if err := haveProbeReadKernel(); err != nil {
|
||||
ins.Constant = int64(asm.FnProbeRead)
|
||||
}
|
||||
case asm.FnProbeReadKernelStr, asm.FnProbeReadUserStr:
|
||||
if err := haveProbeReadKernel(); err != nil {
|
||||
ins.Constant = int64(asm.FnProbeReadStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
95
src/runtime/vendor/github.com/cilium/ebpf/map.go
generated
vendored
95
src/runtime/vendor/github.com/cilium/ebpf/map.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package ebpf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -65,6 +66,11 @@ type MapSpec struct {
|
||||
// InnerMap is used as a template for ArrayOfMaps and HashOfMaps
|
||||
InnerMap *MapSpec
|
||||
|
||||
// Extra trailing bytes found in the ELF map definition when using structs
|
||||
// larger than libbpf's bpf_map_def. Must be empty before instantiating
|
||||
// the MapSpec into a Map.
|
||||
Extra bytes.Reader
|
||||
|
||||
// The BTF associated with this map.
|
||||
BTF *btf.Map
|
||||
}
|
||||
@@ -82,9 +88,12 @@ func (ms *MapSpec) Copy() *MapSpec {
|
||||
}
|
||||
|
||||
cpy := *ms
|
||||
|
||||
cpy.Contents = make([]MapKV, len(ms.Contents))
|
||||
copy(cpy.Contents, ms.Contents)
|
||||
|
||||
cpy.InnerMap = ms.InnerMap.Copy()
|
||||
|
||||
return &cpy
|
||||
}
|
||||
|
||||
@@ -188,14 +197,24 @@ func NewMap(spec *MapSpec) (*Map, error) {
|
||||
//
|
||||
// The caller is responsible for ensuring the process' rlimit is set
|
||||
// sufficiently high for locking memory during map creation. This can be done
|
||||
// by calling unix.Setrlimit with unix.RLIMIT_MEMLOCK prior to calling NewMapWithOptions.
|
||||
// by calling rlimit.RemoveMemlock() prior to calling NewMapWithOptions.
|
||||
//
|
||||
// May return an error wrapping ErrMapIncompatible.
|
||||
func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) {
|
||||
handles := newHandleCache()
|
||||
defer handles.close()
|
||||
|
||||
return newMapWithOptions(spec, opts, handles)
|
||||
m, err := newMapWithOptions(spec, opts, handles)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating map: %w", err)
|
||||
}
|
||||
|
||||
err = m.finalize(spec)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("populating map: %w", err)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ *Map, err error) {
|
||||
@@ -207,8 +226,12 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_
|
||||
|
||||
switch spec.Pinning {
|
||||
case PinByName:
|
||||
if spec.Name == "" || opts.PinPath == "" {
|
||||
return nil, fmt.Errorf("pin by name: missing Name or PinPath")
|
||||
if spec.Name == "" {
|
||||
return nil, fmt.Errorf("pin by name: missing Name")
|
||||
}
|
||||
|
||||
if opts.PinPath == "" {
|
||||
return nil, fmt.Errorf("pin by name: missing MapOptions.PinPath")
|
||||
}
|
||||
|
||||
path := filepath.Join(opts.PinPath, spec.Name)
|
||||
@@ -244,16 +267,19 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_
|
||||
return nil, errors.New("inner maps cannot be pinned")
|
||||
}
|
||||
|
||||
template, err := createMap(spec.InnerMap, nil, opts, handles)
|
||||
template, err := spec.InnerMap.createMap(nil, opts, handles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("inner map: %w", err)
|
||||
}
|
||||
defer template.Close()
|
||||
|
||||
// Intentionally skip populating and freezing (finalizing)
|
||||
// the inner map template since it will be removed shortly.
|
||||
|
||||
innerFd = template.fd
|
||||
}
|
||||
|
||||
m, err := createMap(spec, innerFd, opts, handles)
|
||||
m, err := spec.createMap(innerFd, opts, handles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -269,7 +295,9 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *handleCache) (_ *Map, err error) {
|
||||
// createMap validates the spec's properties and creates the map in the kernel
|
||||
// using the given opts. It does not populate or freeze the map.
|
||||
func (spec *MapSpec) createMap(inner *internal.FD, opts MapOptions, handles *handleCache) (_ *Map, err error) {
|
||||
closeOnError := func(closer io.Closer) {
|
||||
if err != nil {
|
||||
closer.Close()
|
||||
@@ -278,10 +306,16 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand
|
||||
|
||||
spec = spec.Copy()
|
||||
|
||||
// Kernels 4.13 through 5.4 used a struct bpf_map_def that contained
|
||||
// additional 'inner_map_idx' and later 'numa_node' fields.
|
||||
// In order to support loading these definitions, tolerate the presence of
|
||||
// extra bytes, but require them to be zeroes.
|
||||
if _, err := io.Copy(internal.DiscardZeroes{}, &spec.Extra); err != nil {
|
||||
return nil, errors.New("extra contains unhandled non-zero bytes, drain before creating map")
|
||||
}
|
||||
|
||||
switch spec.Type {
|
||||
case ArrayOfMaps:
|
||||
fallthrough
|
||||
case HashOfMaps:
|
||||
case ArrayOfMaps, HashOfMaps:
|
||||
if err := haveNestedMaps(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -350,7 +384,7 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand
|
||||
|
||||
var btfDisabled bool
|
||||
if spec.BTF != nil {
|
||||
handle, err := handles.btfHandle(btf.MapSpec(spec.BTF))
|
||||
handle, err := handles.btfHandle(spec.BTF.Spec)
|
||||
btfDisabled = errors.Is(err, btf.ErrNotSupported)
|
||||
if err != nil && !btfDisabled {
|
||||
return nil, fmt.Errorf("load BTF: %w", err)
|
||||
@@ -358,15 +392,15 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand
|
||||
|
||||
if handle != nil {
|
||||
attr.BTFFd = uint32(handle.FD())
|
||||
attr.BTFKeyTypeID = uint32(btf.MapKey(spec.BTF).ID())
|
||||
attr.BTFValueTypeID = uint32(btf.MapValue(spec.BTF).ID())
|
||||
attr.BTFKeyTypeID = uint32(spec.BTF.Key.ID())
|
||||
attr.BTFValueTypeID = uint32(spec.BTF.Value.ID())
|
||||
}
|
||||
}
|
||||
|
||||
fd, err := internal.BPFMapCreate(&attr)
|
||||
if err != nil {
|
||||
if errors.Is(err, unix.EPERM) {
|
||||
return nil, fmt.Errorf("map create: RLIMIT_MEMLOCK may be too low: %w", err)
|
||||
return nil, fmt.Errorf("map create: %w (MEMLOCK bay be too low, consider rlimit.RemoveMemlock)", err)
|
||||
}
|
||||
if btfDisabled {
|
||||
return nil, fmt.Errorf("map create without BTF: %w", err)
|
||||
@@ -380,19 +414,11 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand
|
||||
return nil, fmt.Errorf("map create: %w", err)
|
||||
}
|
||||
|
||||
if err := m.populate(spec.Contents); err != nil {
|
||||
return nil, fmt.Errorf("map create: can't set initial contents: %w", err)
|
||||
}
|
||||
|
||||
if spec.Freeze {
|
||||
if err := m.Freeze(); err != nil {
|
||||
return nil, fmt.Errorf("can't freeze map: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// newMap allocates and returns a new Map structure.
|
||||
// Sets the fullValueSize on per-CPU maps.
|
||||
func newMap(fd *internal.FD, name string, typ MapType, keySize, valueSize, maxEntries, flags uint32) (*Map, error) {
|
||||
m := &Map{
|
||||
name,
|
||||
@@ -415,7 +441,7 @@ func newMap(fd *internal.FD, name string, typ MapType, keySize, valueSize, maxEn
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.fullValueSize = align(int(valueSize), 8) * possibleCPUs
|
||||
m.fullValueSize = internal.Align(int(valueSize), 8) * possibleCPUs
|
||||
return m, nil
|
||||
}
|
||||
|
||||
@@ -892,12 +918,21 @@ func (m *Map) Freeze() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Map) populate(contents []MapKV) error {
|
||||
for _, kv := range contents {
|
||||
// finalize populates the Map according to the Contents specified
|
||||
// in spec and freezes the Map if requested by spec.
|
||||
func (m *Map) finalize(spec *MapSpec) error {
|
||||
for _, kv := range spec.Contents {
|
||||
if err := m.Put(kv.Key, kv.Value); err != nil {
|
||||
return fmt.Errorf("key %v: %w", kv.Key, err)
|
||||
return fmt.Errorf("putting value: key %v: %w", kv.Key, err)
|
||||
}
|
||||
}
|
||||
|
||||
if spec.Freeze {
|
||||
if err := m.Freeze(); err != nil {
|
||||
return fmt.Errorf("freezing map: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1212,7 +1247,7 @@ func MapGetNextID(startID MapID) (MapID, error) {
|
||||
//
|
||||
// Returns ErrNotExist, if there is no eBPF map with the given id.
|
||||
func NewMapFromID(id MapID) (*Map, error) {
|
||||
fd, err := bpfObjGetFDByID(internal.BPF_MAP_GET_FD_BY_ID, uint32(id))
|
||||
fd, err := internal.BPFObjGetFDByID(internal.BPF_MAP_GET_FD_BY_ID, uint32(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
63
src/runtime/vendor/github.com/cilium/ebpf/marshalers.go
generated
vendored
63
src/runtime/vendor/github.com/cilium/ebpf/marshalers.go
generated
vendored
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf/internal"
|
||||
@@ -39,6 +40,10 @@ func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
|
||||
// Returns an error if the given value isn't representable in exactly
|
||||
// length bytes.
|
||||
func marshalBytes(data interface{}, length int) (buf []byte, err error) {
|
||||
if data == nil {
|
||||
return nil, errors.New("can't marshal a nil value")
|
||||
}
|
||||
|
||||
switch value := data.(type) {
|
||||
case encoding.BinaryMarshaler:
|
||||
buf, err = value.MarshalBinary()
|
||||
@@ -77,22 +82,30 @@ func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) {
|
||||
return internal.NewSlicePointer(buf), buf
|
||||
}
|
||||
|
||||
var bytesReaderPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(bytes.Reader)
|
||||
},
|
||||
}
|
||||
|
||||
// unmarshalBytes converts a byte buffer into an arbitrary value.
|
||||
//
|
||||
// Prefer using Map.unmarshalKey and Map.unmarshalValue if possible, since
|
||||
// those have special cases that allow more types to be encoded.
|
||||
//
|
||||
// The common int32 and int64 types are directly handled to avoid
|
||||
// unnecessary heap allocations as happening in the default case.
|
||||
func unmarshalBytes(data interface{}, buf []byte) error {
|
||||
switch value := data.(type) {
|
||||
case unsafe.Pointer:
|
||||
// This could be solved in Go 1.17 by unsafe.Slice instead. (https://github.com/golang/go/issues/19367)
|
||||
// We could opt for removing unsafe.Pointer support in the lib as well.
|
||||
sh := &reflect.SliceHeader{ //nolint:govet
|
||||
Data: uintptr(value),
|
||||
Len: len(buf),
|
||||
Cap: len(buf),
|
||||
}
|
||||
var dst []byte
|
||||
// Use unsafe.Slice when we drop support for pre1.17 (https://github.com/golang/go/issues/19367)
|
||||
// We could opt for removing unsafe.Pointer support in the lib as well
|
||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&dst))
|
||||
sh.Data = uintptr(value)
|
||||
sh.Len = len(buf)
|
||||
sh.Cap = len(buf)
|
||||
|
||||
dst := *(*[]byte)(unsafe.Pointer(sh))
|
||||
copy(dst, buf)
|
||||
runtime.KeepAlive(value)
|
||||
return nil
|
||||
@@ -106,12 +119,38 @@ func unmarshalBytes(data interface{}, buf []byte) error {
|
||||
case *[]byte:
|
||||
*value = buf
|
||||
return nil
|
||||
case *int32:
|
||||
if len(buf) < 4 {
|
||||
return errors.New("int32 requires 4 bytes")
|
||||
}
|
||||
*value = int32(internal.NativeEndian.Uint32(buf))
|
||||
return nil
|
||||
case *uint32:
|
||||
if len(buf) < 4 {
|
||||
return errors.New("uint32 requires 4 bytes")
|
||||
}
|
||||
*value = internal.NativeEndian.Uint32(buf)
|
||||
return nil
|
||||
case *int64:
|
||||
if len(buf) < 8 {
|
||||
return errors.New("int64 requires 8 bytes")
|
||||
}
|
||||
*value = int64(internal.NativeEndian.Uint64(buf))
|
||||
return nil
|
||||
case *uint64:
|
||||
if len(buf) < 8 {
|
||||
return errors.New("uint64 requires 8 bytes")
|
||||
}
|
||||
*value = internal.NativeEndian.Uint64(buf)
|
||||
return nil
|
||||
case string:
|
||||
return errors.New("require pointer to string")
|
||||
case []byte:
|
||||
return errors.New("require pointer to []byte")
|
||||
default:
|
||||
rd := bytes.NewReader(buf)
|
||||
rd := bytesReaderPool.Get().(*bytes.Reader)
|
||||
rd.Reset(buf)
|
||||
defer bytesReaderPool.Put(rd)
|
||||
if err := binary.Read(rd, internal.NativeEndian, value); err != nil {
|
||||
return fmt.Errorf("decoding %T: %v", value, err)
|
||||
}
|
||||
@@ -142,7 +181,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er
|
||||
return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs")
|
||||
}
|
||||
|
||||
alignedElemLength := align(elemLength, 8)
|
||||
alignedElemLength := internal.Align(elemLength, 8)
|
||||
buf := make([]byte, alignedElemLength*possibleCPUs)
|
||||
|
||||
for i := 0; i < sliceLen; i++ {
|
||||
@@ -212,7 +251,3 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro
|
||||
reflect.ValueOf(slicePtr).Elem().Set(slice)
|
||||
return nil
|
||||
}
|
||||
|
||||
func align(n, alignment int) int {
|
||||
return (int(n) + alignment - 1) / alignment * alignment
|
||||
}
|
||||
|
||||
123
src/runtime/vendor/github.com/cilium/ebpf/prog.go
generated
vendored
123
src/runtime/vendor/github.com/cilium/ebpf/prog.go
generated
vendored
@@ -57,16 +57,21 @@ type ProgramSpec struct {
|
||||
// Name is passed to the kernel as a debug aid. Must only contain
|
||||
// alpha numeric and '_' characters.
|
||||
Name string
|
||||
|
||||
// Type determines at which hook in the kernel a program will run.
|
||||
Type ProgramType
|
||||
AttachType AttachType
|
||||
// Name of a kernel data structure to attach to. It's interpretation
|
||||
// depends on Type and AttachType.
|
||||
AttachTo string
|
||||
// Name of a kernel data structure or function to attach to. Its
|
||||
// interpretation depends on Type and AttachType.
|
||||
AttachTo string
|
||||
// The program to attach to. Must be provided manually.
|
||||
AttachTarget *Program
|
||||
Instructions asm.Instructions
|
||||
|
||||
// Flags is passed to the kernel and specifies additional program
|
||||
// load attributes.
|
||||
Flags uint32
|
||||
|
||||
// License of the program. Some helpers are only available if
|
||||
// the license is deemed compatible with the GPL.
|
||||
//
|
||||
@@ -146,7 +151,7 @@ func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
|
||||
|
||||
func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *handleCache) (*Program, error) {
|
||||
if len(spec.Instructions) == 0 {
|
||||
return nil, errors.New("Instructions cannot be empty")
|
||||
return nil, errors.New("instructions cannot be empty")
|
||||
}
|
||||
|
||||
if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian {
|
||||
@@ -166,16 +171,16 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
kv = v.Kernel()
|
||||
}
|
||||
|
||||
attr := &bpfProgLoadAttr{
|
||||
progType: spec.Type,
|
||||
progFlags: spec.Flags,
|
||||
expectedAttachType: spec.AttachType,
|
||||
license: internal.NewStringPointer(spec.License),
|
||||
kernelVersion: kv,
|
||||
attr := &internal.BPFProgLoadAttr{
|
||||
ProgType: uint32(spec.Type),
|
||||
ProgFlags: spec.Flags,
|
||||
ExpectedAttachType: uint32(spec.AttachType),
|
||||
License: internal.NewStringPointer(spec.License),
|
||||
KernelVersion: kv,
|
||||
}
|
||||
|
||||
if haveObjName() == nil {
|
||||
attr.progName = internal.NewBPFObjName(spec.Name)
|
||||
attr.ProgName = internal.NewBPFObjName(spec.Name)
|
||||
}
|
||||
|
||||
var err error
|
||||
@@ -190,35 +195,35 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
var btfDisabled bool
|
||||
var core btf.COREFixups
|
||||
if spec.BTF != nil {
|
||||
core, err = btf.ProgramFixups(spec.BTF, targetBTF)
|
||||
core, err = spec.BTF.Fixups(targetBTF)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CO-RE relocations: %w", err)
|
||||
}
|
||||
|
||||
handle, err := handles.btfHandle(btf.ProgramSpec(spec.BTF))
|
||||
handle, err := handles.btfHandle(spec.BTF.Spec())
|
||||
btfDisabled = errors.Is(err, btf.ErrNotSupported)
|
||||
if err != nil && !btfDisabled {
|
||||
return nil, fmt.Errorf("load BTF: %w", err)
|
||||
}
|
||||
|
||||
if handle != nil {
|
||||
attr.progBTFFd = uint32(handle.FD())
|
||||
attr.ProgBTFFd = uint32(handle.FD())
|
||||
|
||||
recSize, bytes, err := btf.ProgramLineInfos(spec.BTF)
|
||||
recSize, bytes, err := spec.BTF.LineInfos()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get BTF line infos: %w", err)
|
||||
}
|
||||
attr.lineInfoRecSize = recSize
|
||||
attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
|
||||
attr.lineInfo = internal.NewSlicePointer(bytes)
|
||||
attr.LineInfoRecSize = recSize
|
||||
attr.LineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
|
||||
attr.LineInfo = internal.NewSlicePointer(bytes)
|
||||
|
||||
recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF)
|
||||
recSize, bytes, err = spec.BTF.FuncInfos()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get BTF function infos: %w", err)
|
||||
}
|
||||
attr.funcInfoRecSize = recSize
|
||||
attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
|
||||
attr.funcInfo = internal.NewSlicePointer(bytes)
|
||||
attr.FuncInfoRecSize = recSize
|
||||
attr.FuncInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
|
||||
attr.FuncInfo = internal.NewSlicePointer(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,16 +243,41 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
}
|
||||
|
||||
bytecode := buf.Bytes()
|
||||
attr.instructions = internal.NewSlicePointer(bytecode)
|
||||
attr.insCount = uint32(len(bytecode) / asm.InstructionSize)
|
||||
attr.Instructions = internal.NewSlicePointer(bytecode)
|
||||
attr.InsCount = uint32(len(bytecode) / asm.InstructionSize)
|
||||
|
||||
if spec.AttachTo != "" {
|
||||
if spec.AttachTarget != nil {
|
||||
info, err := spec.AttachTarget.Info()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load target BTF: %w", err)
|
||||
}
|
||||
|
||||
btfID, ok := info.BTFID()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("load target BTF: no BTF info available")
|
||||
}
|
||||
btfHandle, err := btf.NewHandleFromID(btfID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load target BTF: %w", err)
|
||||
}
|
||||
defer btfHandle.Close()
|
||||
|
||||
targetBTF = btfHandle.Spec()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load target BTF: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
target, err := resolveBTFType(targetBTF, spec.AttachTo, spec.Type, spec.AttachType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if target != nil {
|
||||
attr.attachBTFID = target.ID()
|
||||
attr.AttachBTFID = uint32(target.ID())
|
||||
}
|
||||
if spec.AttachTarget != nil {
|
||||
attr.AttachProgFd = uint32(spec.AttachTarget.FD())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,12 +289,12 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
var logBuf []byte
|
||||
if opts.LogLevel > 0 {
|
||||
logBuf = make([]byte, logSize)
|
||||
attr.logLevel = opts.LogLevel
|
||||
attr.logSize = uint32(len(logBuf))
|
||||
attr.logBuf = internal.NewSlicePointer(logBuf)
|
||||
attr.LogLevel = opts.LogLevel
|
||||
attr.LogSize = uint32(len(logBuf))
|
||||
attr.LogBuf = internal.NewSlicePointer(logBuf)
|
||||
}
|
||||
|
||||
fd, err := bpfProgLoad(attr)
|
||||
fd, err := internal.BPFProgLoad(attr)
|
||||
if err == nil {
|
||||
return &Program{internal.CString(logBuf), fd, spec.Name, "", spec.Type}, nil
|
||||
}
|
||||
@@ -273,17 +303,20 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
if opts.LogLevel == 0 && opts.LogSize >= 0 {
|
||||
// Re-run with the verifier enabled to get better error messages.
|
||||
logBuf = make([]byte, logSize)
|
||||
attr.logLevel = 1
|
||||
attr.logSize = uint32(len(logBuf))
|
||||
attr.logBuf = internal.NewSlicePointer(logBuf)
|
||||
attr.LogLevel = 1
|
||||
attr.LogSize = uint32(len(logBuf))
|
||||
attr.LogBuf = internal.NewSlicePointer(logBuf)
|
||||
|
||||
_, logErr = bpfProgLoad(attr)
|
||||
fd, logErr = internal.BPFProgLoad(attr)
|
||||
if logErr == nil {
|
||||
fd.Close()
|
||||
}
|
||||
}
|
||||
|
||||
if errors.Is(logErr, unix.EPERM) && logBuf[0] == 0 {
|
||||
// EPERM due to RLIMIT_MEMLOCK happens before the verifier, so we can
|
||||
// check that the log is empty to reduce false positives.
|
||||
return nil, fmt.Errorf("load program: RLIMIT_MEMLOCK may be too low: %w", logErr)
|
||||
return nil, fmt.Errorf("load program: %w (MEMLOCK bay be too low, consider rlimit.RemoveMemlock)", logErr)
|
||||
}
|
||||
|
||||
err = internal.ErrorWithLog(err, logBuf, logErr)
|
||||
@@ -310,7 +343,7 @@ func NewProgramFromFD(fd int) (*Program, error) {
|
||||
//
|
||||
// Returns ErrNotExist, if there is no eBPF program with the given id.
|
||||
func NewProgramFromID(id ProgramID) (*Program, error) {
|
||||
fd, err := bpfObjGetFDByID(internal.BPF_PROG_GET_FD_BY_ID, uint32(id))
|
||||
fd, err := internal.BPFObjGetFDByID(internal.BPF_PROG_GET_FD_BY_ID, uint32(id))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get program by id: %w", err)
|
||||
}
|
||||
@@ -677,45 +710,44 @@ func ProgramGetNextID(startID ProgramID) (ProgramID, error) {
|
||||
//
|
||||
// Deprecated: use ProgramInfo.ID() instead.
|
||||
func (p *Program) ID() (ProgramID, error) {
|
||||
info, err := bpfGetProgInfoByFD(p.fd)
|
||||
info, err := bpfGetProgInfoByFD(p.fd, nil)
|
||||
if err != nil {
|
||||
return ProgramID(0), err
|
||||
}
|
||||
return ProgramID(info.id), nil
|
||||
}
|
||||
|
||||
func resolveBTFType(kernel *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.Type, error) {
|
||||
func resolveBTFType(spec *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.Type, error) {
|
||||
type match struct {
|
||||
p ProgramType
|
||||
a AttachType
|
||||
}
|
||||
|
||||
var target btf.Type
|
||||
var typeName, featureName string
|
||||
switch (match{progType, attachType}) {
|
||||
case match{LSM, AttachLSMMac}:
|
||||
target = new(btf.Func)
|
||||
typeName = "bpf_lsm_" + name
|
||||
featureName = name + " LSM hook"
|
||||
|
||||
case match{Tracing, AttachTraceIter}:
|
||||
target = new(btf.Func)
|
||||
typeName = "bpf_iter_" + name
|
||||
featureName = name + " iterator"
|
||||
|
||||
case match{Extension, AttachNone}:
|
||||
typeName = name
|
||||
featureName = fmt.Sprintf("freplace %s", name)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if kernel == nil {
|
||||
if spec == nil {
|
||||
var err error
|
||||
kernel, err = btf.LoadKernelSpec()
|
||||
spec, err = btf.LoadKernelSpec()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load kernel spec: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err := kernel.FindType(typeName, target)
|
||||
var target *btf.Func
|
||||
err := spec.FindType(typeName, &target)
|
||||
if errors.Is(err, btf.ErrNotFound) {
|
||||
return nil, &internal.UnsupportedFeatureError{
|
||||
Name: featureName,
|
||||
@@ -724,5 +756,6 @@ func resolveBTFType(kernel *btf.Spec, name string, progType ProgramType, attachT
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolve BTF for %s: %w", featureName, err)
|
||||
}
|
||||
|
||||
return target, nil
|
||||
}
|
||||
|
||||
22
src/runtime/vendor/github.com/cilium/ebpf/run-tests.sh
generated
vendored
22
src/runtime/vendor/github.com/cilium/ebpf/run-tests.sh
generated
vendored
@@ -5,7 +5,7 @@
|
||||
# Run all tests on a 5.4 kernel
|
||||
# $ ./run-tests.sh 5.4
|
||||
# Run a subset of tests:
|
||||
# $ ./run-tests.sh 5.4 go test ./link
|
||||
# $ ./run-tests.sh 5.4 ./link
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -48,15 +48,17 @@ if [[ "${1:-}" = "--exec-vm" ]]; then
|
||||
rm "${output}/fake-stdin"
|
||||
fi
|
||||
|
||||
$sudo virtme-run --kimg "${input}/bzImage" --memory 768M --pwd \
|
||||
--rwdir="${testdir}=${testdir}" \
|
||||
--rodir=/run/input="${input}" \
|
||||
--rwdir=/run/output="${output}" \
|
||||
--script-sh "PATH=\"$PATH\" \"$script\" --exec-test $cmd" \
|
||||
--qemu-opts -smp 2 # need at least two CPUs for some tests
|
||||
if ! $sudo virtme-run --kimg "${input}/bzImage" --memory 768M --pwd \
|
||||
--rwdir="${testdir}=${testdir}" \
|
||||
--rodir=/run/input="${input}" \
|
||||
--rwdir=/run/output="${output}" \
|
||||
--script-sh "PATH=\"$PATH\" \"$script\" --exec-test $cmd" \
|
||||
--kopt possible_cpus=2; then # need at least two CPUs for some tests
|
||||
exit 23
|
||||
fi
|
||||
|
||||
if [[ ! -e "${output}/success" ]]; then
|
||||
exit 1
|
||||
exit 42
|
||||
fi
|
||||
|
||||
$sudo rm -r "$output"
|
||||
@@ -74,7 +76,7 @@ elif [[ "${1:-}" = "--exec-test" ]]; then
|
||||
dmesg -C
|
||||
if ! "$@"; then
|
||||
dmesg
|
||||
exit 1
|
||||
exit 1 # this return code is "swallowed" by qemu
|
||||
fi
|
||||
touch "/run/output/success"
|
||||
exit 0
|
||||
@@ -108,7 +110,7 @@ else
|
||||
echo "No selftests found, disabling"
|
||||
fi
|
||||
|
||||
args=(-v -short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...)
|
||||
args=(-short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...)
|
||||
if (( $# > 0 )); then
|
||||
args=("$@")
|
||||
fi
|
||||
|
||||
94
src/runtime/vendor/github.com/cilium/ebpf/syscalls.go
generated
vendored
94
src/runtime/vendor/github.com/cilium/ebpf/syscalls.go
generated
vendored
@@ -1,13 +1,14 @@
|
||||
package ebpf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf/asm"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
"github.com/cilium/ebpf/internal/btf"
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
)
|
||||
|
||||
@@ -73,30 +74,6 @@ type bpfMapInfo struct {
|
||||
btf_value_type_id uint32
|
||||
}
|
||||
|
||||
type bpfProgLoadAttr struct {
|
||||
progType ProgramType
|
||||
insCount uint32
|
||||
instructions internal.Pointer
|
||||
license internal.Pointer
|
||||
logLevel uint32
|
||||
logSize uint32
|
||||
logBuf internal.Pointer
|
||||
kernelVersion uint32 // since 4.1 2541517c32be
|
||||
progFlags uint32 // since 4.11 e07b98d9bffe
|
||||
progName internal.BPFObjName // since 4.15 067cae47771c
|
||||
progIfIndex uint32 // since 4.15 1f6f4cb7ba21
|
||||
expectedAttachType AttachType // since 4.17 5e43f899b03a
|
||||
progBTFFd uint32
|
||||
funcInfoRecSize uint32
|
||||
funcInfo internal.Pointer
|
||||
funcInfoCnt uint32
|
||||
lineInfoRecSize uint32
|
||||
lineInfo internal.Pointer
|
||||
lineInfoCnt uint32
|
||||
attachBTFID btf.TypeID
|
||||
attachProgFd uint32
|
||||
}
|
||||
|
||||
type bpfProgInfo struct {
|
||||
prog_type uint32
|
||||
id uint32
|
||||
@@ -107,7 +84,7 @@ type bpfProgInfo struct {
|
||||
xlated_prog_insns internal.Pointer
|
||||
load_time uint64 // since 4.15 cb4d2b3f03d8
|
||||
created_by_uid uint32
|
||||
nr_map_ids uint32
|
||||
nr_map_ids uint32 // since 4.15 cb4d2b3f03d8
|
||||
map_ids internal.Pointer
|
||||
name internal.BPFObjName // since 4.15 067cae47771c
|
||||
ifindex uint32
|
||||
@@ -145,11 +122,6 @@ type bpfProgTestRunAttr struct {
|
||||
duration uint32
|
||||
}
|
||||
|
||||
type bpfGetFDByIDAttr struct {
|
||||
id uint32
|
||||
next uint32
|
||||
}
|
||||
|
||||
type bpfMapFreezeAttr struct {
|
||||
mapFd uint32
|
||||
}
|
||||
@@ -160,23 +132,6 @@ type bpfObjGetNextIDAttr struct {
|
||||
openFlags uint32
|
||||
}
|
||||
|
||||
func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) {
|
||||
for {
|
||||
fd, err := internal.BPF(internal.BPF_PROG_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||
// As of ~4.20 the verifier can be interrupted by a signal,
|
||||
// and returns EAGAIN in that case.
|
||||
if errors.Is(err, unix.EAGAIN) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return internal.NewFD(uint32(fd)), nil
|
||||
}
|
||||
}
|
||||
|
||||
func bpfProgTestRun(attr *bpfProgTestRunAttr) error {
|
||||
_, err := internal.BPF(internal.BPF_PROG_TEST_RUN, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||
return err
|
||||
@@ -372,6 +327,10 @@ func wrapMapError(err error) error {
|
||||
return internal.SyscallError(ErrNotSupported, unix.ENOTSUPP)
|
||||
}
|
||||
|
||||
if errors.Is(err, unix.E2BIG) {
|
||||
return fmt.Errorf("key too big for map: %w", err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -388,8 +347,13 @@ func bpfMapFreeze(m *internal.FD) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) {
|
||||
func bpfGetProgInfoByFD(fd *internal.FD, ids []MapID) (*bpfProgInfo, error) {
|
||||
var info bpfProgInfo
|
||||
if len(ids) > 0 {
|
||||
info.nr_map_ids = uint32(len(ids))
|
||||
info.map_ids = internal.NewPointer(unsafe.Pointer(&ids[0]))
|
||||
}
|
||||
|
||||
if err := internal.BPFObjGetInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil {
|
||||
return nil, fmt.Errorf("can't get program info: %w", err)
|
||||
}
|
||||
@@ -471,10 +435,30 @@ var haveBatchAPI = internal.FeatureTest("map batch api", "5.6", func() error {
|
||||
return nil
|
||||
})
|
||||
|
||||
func bpfObjGetFDByID(cmd internal.BPFCmd, id uint32) (*internal.FD, error) {
|
||||
attr := bpfGetFDByIDAttr{
|
||||
id: id,
|
||||
var haveProbeReadKernel = internal.FeatureTest("bpf_probe_read_kernel", "5.5", func() error {
|
||||
insns := asm.Instructions{
|
||||
asm.Mov.Reg(asm.R1, asm.R10),
|
||||
asm.Add.Imm(asm.R1, -8),
|
||||
asm.Mov.Imm(asm.R2, 8),
|
||||
asm.Mov.Imm(asm.R3, 0),
|
||||
asm.FnProbeReadKernel.Call(),
|
||||
asm.Return(),
|
||||
}
|
||||
ptr, err := internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||
return internal.NewFD(uint32(ptr)), err
|
||||
}
|
||||
buf := bytes.NewBuffer(make([]byte, 0, len(insns)*asm.InstructionSize))
|
||||
if err := insns.Marshal(buf, internal.NativeEndian); err != nil {
|
||||
return err
|
||||
}
|
||||
bytecode := buf.Bytes()
|
||||
|
||||
fd, err := internal.BPFProgLoad(&internal.BPFProgLoadAttr{
|
||||
ProgType: uint32(Kprobe),
|
||||
License: internal.NewStringPointer("GPL"),
|
||||
Instructions: internal.NewSlicePointer(bytecode),
|
||||
InsCount: uint32(len(bytecode) / asm.InstructionSize),
|
||||
})
|
||||
if err != nil {
|
||||
return internal.ErrNotSupported
|
||||
}
|
||||
_ = fd.Close()
|
||||
return nil
|
||||
})
|
||||
|
||||
36
src/runtime/vendor/github.com/cilium/ebpf/types.go
generated
vendored
36
src/runtime/vendor/github.com/cilium/ebpf/types.go
generated
vendored
@@ -4,12 +4,17 @@ import (
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
)
|
||||
|
||||
//go:generate stringer -output types_string.go -type=MapType,ProgramType,AttachType,PinType
|
||||
//go:generate stringer -output types_string.go -type=MapType,ProgramType,PinType
|
||||
|
||||
// MapType indicates the type map structure
|
||||
// that will be initialized in the kernel.
|
||||
type MapType uint32
|
||||
|
||||
// Max returns the latest supported MapType.
|
||||
func (_ MapType) Max() MapType {
|
||||
return maxMapType - 1
|
||||
}
|
||||
|
||||
// All the various map types that can be created
|
||||
const (
|
||||
UnspecifiedMap MapType = iota
|
||||
@@ -85,15 +90,28 @@ const (
|
||||
SkStorage
|
||||
// DevMapHash - Hash-based indexing scheme for references to network devices.
|
||||
DevMapHash
|
||||
StructOpts
|
||||
// StructOpsMap - This map holds a kernel struct with its function pointer implemented in a BPF
|
||||
// program.
|
||||
StructOpsMap
|
||||
// RingBuf - Similar to PerfEventArray, but shared across all CPUs.
|
||||
RingBuf
|
||||
// InodeStorage - Specialized local storage map for inodes.
|
||||
InodeStorage
|
||||
// TaskStorage - Specialized local storage map for task_struct.
|
||||
TaskStorage
|
||||
// maxMapType - Bound enum of MapTypes, has to be last in enum.
|
||||
maxMapType
|
||||
)
|
||||
|
||||
// Deprecated: StructOpts was a typo, use StructOpsMap instead.
|
||||
//
|
||||
// Declared as a variable to prevent stringer from picking it up
|
||||
// as an enum value.
|
||||
var StructOpts MapType = StructOpsMap
|
||||
|
||||
// hasPerCPUValue returns true if the Map stores a value per CPU.
|
||||
func (mt MapType) hasPerCPUValue() bool {
|
||||
return mt == PerCPUHash || mt == PerCPUArray || mt == LRUCPUHash
|
||||
return mt == PerCPUHash || mt == PerCPUArray || mt == LRUCPUHash || mt == PerCPUCGroupStorage
|
||||
}
|
||||
|
||||
// canStoreMap returns true if the map type accepts a map fd
|
||||
@@ -111,6 +129,11 @@ func (mt MapType) canStoreProgram() bool {
|
||||
// ProgramType of the eBPF program
|
||||
type ProgramType uint32
|
||||
|
||||
// Max return the latest supported ProgramType.
|
||||
func (_ ProgramType) Max() ProgramType {
|
||||
return maxProgramType - 1
|
||||
}
|
||||
|
||||
// eBPF program types
|
||||
const (
|
||||
UnspecifiedProgram ProgramType = iota
|
||||
@@ -144,6 +167,7 @@ const (
|
||||
Extension
|
||||
LSM
|
||||
SkLookup
|
||||
maxProgramType
|
||||
)
|
||||
|
||||
// AttachType of the eBPF program, needed to differentiate allowed context accesses in
|
||||
@@ -151,6 +175,8 @@ const (
|
||||
// Will cause invalid argument (EINVAL) at program load time if set incorrectly.
|
||||
type AttachType uint32
|
||||
|
||||
//go:generate stringer -type AttachType -trimprefix Attach
|
||||
|
||||
// AttachNone is an alias for AttachCGroupInetIngress for readability reasons.
|
||||
const AttachNone AttachType = 0
|
||||
|
||||
@@ -193,6 +219,10 @@ const (
|
||||
AttachXDPCPUMap
|
||||
AttachSkLookup
|
||||
AttachXDP
|
||||
AttachSkSKBVerdict
|
||||
AttachSkReuseportSelect
|
||||
AttachSkReuseportSelectOrMigrate
|
||||
AttachPerfEvent
|
||||
)
|
||||
|
||||
// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command
|
||||
|
||||
69
src/runtime/vendor/github.com/cilium/ebpf/types_string.go
generated
vendored
69
src/runtime/vendor/github.com/cilium/ebpf/types_string.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
// Code generated by "stringer -output types_string.go -type=MapType,ProgramType,AttachType,PinType"; DO NOT EDIT.
|
||||
// Code generated by "stringer -output types_string.go -type=MapType,ProgramType,PinType"; DO NOT EDIT.
|
||||
|
||||
package ebpf
|
||||
|
||||
@@ -34,15 +34,16 @@ func _() {
|
||||
_ = x[Stack-23]
|
||||
_ = x[SkStorage-24]
|
||||
_ = x[DevMapHash-25]
|
||||
_ = x[StructOpts-26]
|
||||
_ = x[StructOpsMap-26]
|
||||
_ = x[RingBuf-27]
|
||||
_ = x[InodeStorage-28]
|
||||
_ = x[TaskStorage-29]
|
||||
_ = x[maxMapType-30]
|
||||
}
|
||||
|
||||
const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHashStructOptsRingBufInodeStorageTaskStorage"
|
||||
const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHashStructOpsMapRingBufInodeStorageTaskStoragemaxMapType"
|
||||
|
||||
var _MapType_index = [...]uint16{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248, 258, 265, 277, 288}
|
||||
var _MapType_index = [...]uint16{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248, 260, 267, 279, 290, 300}
|
||||
|
||||
func (i MapType) String() string {
|
||||
if i >= MapType(len(_MapType_index)-1) {
|
||||
@@ -85,11 +86,12 @@ func _() {
|
||||
_ = x[Extension-28]
|
||||
_ = x[LSM-29]
|
||||
_ = x[SkLookup-30]
|
||||
_ = x[maxProgramType-31]
|
||||
}
|
||||
|
||||
const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockoptTracingStructOpsExtensionLSMSkLookup"
|
||||
const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockoptTracingStructOpsExtensionLSMSkLookupmaxProgramType"
|
||||
|
||||
var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258, 265, 274, 283, 286, 294}
|
||||
var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258, 265, 274, 283, 286, 294, 308}
|
||||
|
||||
func (i ProgramType) String() string {
|
||||
if i >= ProgramType(len(_ProgramType_index)-1) {
|
||||
@@ -97,61 +99,6 @@ func (i ProgramType) String() string {
|
||||
}
|
||||
return _ProgramType_name[_ProgramType_index[i]:_ProgramType_index[i+1]]
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[AttachNone-0]
|
||||
_ = x[AttachCGroupInetIngress-0]
|
||||
_ = x[AttachCGroupInetEgress-1]
|
||||
_ = x[AttachCGroupInetSockCreate-2]
|
||||
_ = x[AttachCGroupSockOps-3]
|
||||
_ = x[AttachSkSKBStreamParser-4]
|
||||
_ = x[AttachSkSKBStreamVerdict-5]
|
||||
_ = x[AttachCGroupDevice-6]
|
||||
_ = x[AttachSkMsgVerdict-7]
|
||||
_ = x[AttachCGroupInet4Bind-8]
|
||||
_ = x[AttachCGroupInet6Bind-9]
|
||||
_ = x[AttachCGroupInet4Connect-10]
|
||||
_ = x[AttachCGroupInet6Connect-11]
|
||||
_ = x[AttachCGroupInet4PostBind-12]
|
||||
_ = x[AttachCGroupInet6PostBind-13]
|
||||
_ = x[AttachCGroupUDP4Sendmsg-14]
|
||||
_ = x[AttachCGroupUDP6Sendmsg-15]
|
||||
_ = x[AttachLircMode2-16]
|
||||
_ = x[AttachFlowDissector-17]
|
||||
_ = x[AttachCGroupSysctl-18]
|
||||
_ = x[AttachCGroupUDP4Recvmsg-19]
|
||||
_ = x[AttachCGroupUDP6Recvmsg-20]
|
||||
_ = x[AttachCGroupGetsockopt-21]
|
||||
_ = x[AttachCGroupSetsockopt-22]
|
||||
_ = x[AttachTraceRawTp-23]
|
||||
_ = x[AttachTraceFEntry-24]
|
||||
_ = x[AttachTraceFExit-25]
|
||||
_ = x[AttachModifyReturn-26]
|
||||
_ = x[AttachLSMMac-27]
|
||||
_ = x[AttachTraceIter-28]
|
||||
_ = x[AttachCgroupInet4GetPeername-29]
|
||||
_ = x[AttachCgroupInet6GetPeername-30]
|
||||
_ = x[AttachCgroupInet4GetSockname-31]
|
||||
_ = x[AttachCgroupInet6GetSockname-32]
|
||||
_ = x[AttachXDPDevMap-33]
|
||||
_ = x[AttachCgroupInetSockRelease-34]
|
||||
_ = x[AttachXDPCPUMap-35]
|
||||
_ = x[AttachSkLookup-36]
|
||||
_ = x[AttachXDP-37]
|
||||
}
|
||||
|
||||
const _AttachType_name = "AttachNoneAttachCGroupInetEgressAttachCGroupInetSockCreateAttachCGroupSockOpsAttachSkSKBStreamParserAttachSkSKBStreamVerdictAttachCGroupDeviceAttachSkMsgVerdictAttachCGroupInet4BindAttachCGroupInet6BindAttachCGroupInet4ConnectAttachCGroupInet6ConnectAttachCGroupInet4PostBindAttachCGroupInet6PostBindAttachCGroupUDP4SendmsgAttachCGroupUDP6SendmsgAttachLircMode2AttachFlowDissectorAttachCGroupSysctlAttachCGroupUDP4RecvmsgAttachCGroupUDP6RecvmsgAttachCGroupGetsockoptAttachCGroupSetsockoptAttachTraceRawTpAttachTraceFEntryAttachTraceFExitAttachModifyReturnAttachLSMMacAttachTraceIterAttachCgroupInet4GetPeernameAttachCgroupInet6GetPeernameAttachCgroupInet4GetSocknameAttachCgroupInet6GetSocknameAttachXDPDevMapAttachCgroupInetSockReleaseAttachXDPCPUMapAttachSkLookupAttachXDP"
|
||||
|
||||
var _AttachType_index = [...]uint16{0, 10, 32, 58, 77, 100, 124, 142, 160, 181, 202, 226, 250, 275, 300, 323, 346, 361, 380, 398, 421, 444, 466, 488, 504, 521, 537, 555, 567, 582, 610, 638, 666, 694, 709, 736, 751, 765, 774}
|
||||
|
||||
func (i AttachType) String() string {
|
||||
if i >= AttachType(len(_AttachType_index)-1) {
|
||||
return "AttachType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _AttachType_name[_AttachType_index[i]:_AttachType_index[i+1]]
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
|
||||
12
src/runtime/vendor/github.com/containerd/containerd/runtime/v2/shim/shim.go
generated
vendored
12
src/runtime/vendor/github.com/containerd/containerd/runtime/v2/shim/shim.go
generated
vendored
@@ -169,7 +169,7 @@ func setLogger(ctx context.Context, id string) (context.Context, error) {
|
||||
l.Logger.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
f, err := openLog(ctx, id)
|
||||
if err != nil {
|
||||
if err != nil { //nolint:staticcheck // Ignore SA4023 as some platforms always return error
|
||||
return ctx, err
|
||||
}
|
||||
l.Logger.SetOutput(f)
|
||||
@@ -255,12 +255,12 @@ func run(ctx context.Context, manager Manager, initFunc Init, name string, confi
|
||||
setRuntime()
|
||||
|
||||
signals, err := setupSignals(config)
|
||||
if err != nil {
|
||||
if err != nil { //nolint:staticcheck // Ignore SA4023 as some platforms always return error
|
||||
return err
|
||||
}
|
||||
|
||||
if !config.NoSubreaper {
|
||||
if err := subreaper(); err != nil {
|
||||
if err := subreaper(); err != nil { //nolint:staticcheck // Ignore SA4023 as some platforms always return error
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -418,7 +418,7 @@ func run(ctx context.Context, manager Manager, initFunc Init, name string, confi
|
||||
}
|
||||
|
||||
server, err := newServer()
|
||||
if err != nil {
|
||||
if err != nil { //nolint:staticcheck // Ignore SA4023 as some platforms always return error
|
||||
return fmt.Errorf("failed creating server: %w", err)
|
||||
}
|
||||
|
||||
@@ -428,7 +428,7 @@ func run(ctx context.Context, manager Manager, initFunc Init, name string, confi
|
||||
}
|
||||
}
|
||||
|
||||
if err := serve(ctx, server, signals, sd.Shutdown); err != nil {
|
||||
if err := serve(ctx, server, signals, sd.Shutdown); err != nil { //nolint:staticcheck // Ignore SA4023 as some platforms always return error
|
||||
if err != shutdown.ErrShutdown {
|
||||
return err
|
||||
}
|
||||
@@ -460,7 +460,7 @@ func serve(ctx context.Context, server *ttrpc.Server, signals chan os.Signal, sh
|
||||
}
|
||||
|
||||
l, err := serveListener(socketFlag)
|
||||
if err != nil {
|
||||
if err != nil { //nolint:staticcheck // Ignore SA4023 as some platforms always return error
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
|
||||
2
src/runtime/vendor/github.com/containerd/containerd/version/version.go
generated
vendored
2
src/runtime/vendor/github.com/containerd/containerd/version/version.go
generated
vendored
@@ -23,7 +23,7 @@ var (
|
||||
Package = "github.com/containerd/containerd"
|
||||
|
||||
// Version holds the complete version number. Filled in at linking time.
|
||||
Version = "1.6.1+unknown"
|
||||
Version = "1.6.6+unknown"
|
||||
|
||||
// Revision is filled with the VCS (e.g. git) revision being used to build
|
||||
// the program at linking time.
|
||||
|
||||
6
src/runtime/vendor/github.com/containernetworking/cni/pkg/skel/skel.go
generated
vendored
6
src/runtime/vendor/github.com/containernetworking/cni/pkg/skel/skel.go
generated
vendored
@@ -196,6 +196,7 @@ func (t *dispatcher) pluginMain(cmdAdd, cmdCheck, cmdDel func(_ *CmdArgs) error,
|
||||
// Print the about string to stderr when no command is set
|
||||
if err.Code == types.ErrInvalidEnvironmentVariables && t.Getenv("CNI_COMMAND") == "" && about != "" {
|
||||
_, _ = fmt.Fprintln(t.Stderr, about)
|
||||
_, _ = fmt.Fprintf(t.Stderr, "CNI protocol versions supported: %s\n", strings.Join(versionInfo.SupportedVersions(), ", "))
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
@@ -248,10 +249,7 @@ func (t *dispatcher) pluginMain(cmdAdd, cmdCheck, cmdDel func(_ *CmdArgs) error,
|
||||
return types.NewError(types.ErrInvalidEnvironmentVariables, fmt.Sprintf("unknown CNI_COMMAND: %v", cmd), "")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// PluginMainWithError is the core "main" for a plugin. It accepts
|
||||
|
||||
4
src/runtime/vendor/github.com/containernetworking/cni/pkg/version/plugin.go
generated
vendored
4
src/runtime/vendor/github.com/containernetworking/cni/pkg/version/plugin.go
generated
vendored
@@ -86,8 +86,8 @@ func (*PluginDecoder) Decode(jsonBytes []byte) (PluginInfo, error) {
|
||||
// minor, and micro numbers or returns an error
|
||||
func ParseVersion(version string) (int, int, int, error) {
|
||||
var major, minor, micro int
|
||||
if version == "" {
|
||||
return -1, -1, -1, fmt.Errorf("invalid version %q: the version is empty", version)
|
||||
if version == "" { // special case: no version declared == v0.1.0
|
||||
return 0, 1, 0, nil
|
||||
}
|
||||
|
||||
parts := strings.Split(version, ".")
|
||||
|
||||
4
src/runtime/vendor/github.com/containernetworking/plugins/pkg/ns/ns_linux.go
generated
vendored
4
src/runtime/vendor/github.com/containernetworking/plugins/pkg/ns/ns_linux.go
generated
vendored
@@ -106,8 +106,8 @@ var _ NetNS = &netNS{}
|
||||
|
||||
const (
|
||||
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/magic.h
|
||||
NSFS_MAGIC = 0x6e736673
|
||||
PROCFS_MAGIC = 0x9fa0
|
||||
NSFS_MAGIC = unix.NSFS_MAGIC
|
||||
PROCFS_MAGIC = unix.PROC_SUPER_MAGIC
|
||||
)
|
||||
|
||||
type NSPathNotExistErr struct{ msg string }
|
||||
|
||||
@@ -53,7 +53,7 @@ func NewNS() (ns.NetNS, error) {
|
||||
nsRunDir := getNsRunDir()
|
||||
|
||||
b := make([]byte, 16)
|
||||
_, err := rand.Reader.Read(b)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate random netns name: %v", err)
|
||||
}
|
||||
|
||||
@@ -14,14 +14,12 @@ D-Bus message bus system.
|
||||
|
||||
### Installation
|
||||
|
||||
This packages requires Go 1.7. If you installed it and set up your GOPATH, just run:
|
||||
This packages requires Go 1.12 or later. It can be installed by running the command below:
|
||||
|
||||
```
|
||||
go get github.com/godbus/dbus
|
||||
go get github.com/godbus/dbus/v5
|
||||
```
|
||||
|
||||
If you want to use the subpackages, you can install them the same way.
|
||||
|
||||
### Usage
|
||||
|
||||
The complete package documentation and some simple examples are available at
|
||||
@@ -30,10 +28,12 @@ The complete package documentation and some simple examples are available at
|
||||
gives a short overview over the basic usage.
|
||||
|
||||
#### Projects using godbus
|
||||
- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
|
||||
- [fyne](https://github.com/fyne-io/fyne) a cross platform GUI in Go inspired by Material Design.
|
||||
- [fynedesk](https://github.com/fyne-io/fynedesk) a full desktop environment for Linux/Unix using Fyne.
|
||||
- [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API.
|
||||
- [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players.
|
||||
- [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd".
|
||||
- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
|
||||
- [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players.
|
||||
|
||||
Please note that the API is considered unstable for now and may change without
|
||||
further notice.
|
||||
15
src/runtime/vendor/github.com/godbus/dbus/v5/auth.go
generated
vendored
15
src/runtime/vendor/github.com/godbus/dbus/v5/auth.go
generated
vendored
@@ -53,7 +53,7 @@ type Auth interface {
|
||||
// bus. Auth must not be called on shared connections.
|
||||
func (conn *Conn) Auth(methods []Auth) error {
|
||||
if methods == nil {
|
||||
uid := strconv.Itoa(os.Getuid())
|
||||
uid := strconv.Itoa(os.Geteuid())
|
||||
methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())}
|
||||
}
|
||||
in := bufio.NewReader(conn.transport)
|
||||
@@ -75,9 +75,9 @@ func (conn *Conn) Auth(methods []Auth) error {
|
||||
s = s[1:]
|
||||
for _, v := range s {
|
||||
for _, m := range methods {
|
||||
if name, data, status := m.FirstData(); bytes.Equal(v, name) {
|
||||
if name, _, status := m.FirstData(); bytes.Equal(v, name) {
|
||||
var ok bool
|
||||
err = authWriteLine(conn.transport, []byte("AUTH"), v, data)
|
||||
err = authWriteLine(conn.transport, []byte("AUTH"), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -194,11 +194,14 @@ func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, boo
|
||||
}
|
||||
conn.uuid = string(s[1])
|
||||
return nil, true
|
||||
case state == waitingForOk && string(s[0]) == "DATA":
|
||||
err = authWriteLine(conn.transport, []byte("DATA"))
|
||||
if err != nil {
|
||||
return err, false
|
||||
}
|
||||
case state == waitingForOk && string(s[0]) == "REJECTED":
|
||||
return nil, false
|
||||
case state == waitingForOk && (string(s[0]) == "DATA" ||
|
||||
string(s[0]) == "ERROR"):
|
||||
|
||||
case state == waitingForOk && string(s[0]) == "ERROR":
|
||||
err = authWriteLine(conn.transport, []byte("CANCEL"))
|
||||
if err != nil {
|
||||
return err, false
|
||||
|
||||
36
src/runtime/vendor/github.com/godbus/dbus/v5/conn.go
generated
vendored
36
src/runtime/vendor/github.com/godbus/dbus/v5/conn.go
generated
vendored
@@ -73,7 +73,7 @@ func SessionBus() (conn *Conn, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func getSessionBusAddress() (string, error) {
|
||||
func getSessionBusAddress(autolaunch bool) (string, error) {
|
||||
if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
|
||||
return address, nil
|
||||
|
||||
@@ -81,12 +81,26 @@ func getSessionBusAddress() (string, error) {
|
||||
os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
|
||||
return address, nil
|
||||
}
|
||||
if !autolaunch {
|
||||
return "", errors.New("dbus: couldn't determine address of session bus")
|
||||
}
|
||||
return getSessionBusPlatformAddress()
|
||||
}
|
||||
|
||||
// SessionBusPrivate returns a new private connection to the session bus.
|
||||
func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
|
||||
address, err := getSessionBusAddress()
|
||||
address, err := getSessionBusAddress(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return Dial(address, opts...)
|
||||
}
|
||||
|
||||
// SessionBusPrivate returns a new private connection to the session bus. If
|
||||
// the session bus is not already open, do not attempt to launch it.
|
||||
func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) {
|
||||
address, err := getSessionBusAddress(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -121,7 +135,7 @@ func SystemBus() (conn *Conn, err error) {
|
||||
|
||||
// ConnectSessionBus connects to the session bus.
|
||||
func ConnectSessionBus(opts ...ConnOption) (*Conn, error) {
|
||||
address, err := getSessionBusAddress()
|
||||
address, err := getSessionBusAddress(true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -180,7 +194,7 @@ func Dial(address string, opts ...ConnOption) (*Conn, error) {
|
||||
//
|
||||
// Deprecated: use Dial with options instead.
|
||||
func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
|
||||
return Dial(address, WithSignalHandler(signalHandler))
|
||||
return Dial(address, WithHandler(handler), WithSignalHandler(signalHandler))
|
||||
}
|
||||
|
||||
// ConnOption is a connection option.
|
||||
@@ -478,14 +492,24 @@ func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
|
||||
conn.outInt(msg)
|
||||
}
|
||||
err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
|
||||
conn.calls.handleSendError(msg, err)
|
||||
if err != nil {
|
||||
conn.serialGen.RetireSerial(msg.serial)
|
||||
conn.handleSendError(msg, err)
|
||||
} else if msg.Type != TypeMethodCall {
|
||||
conn.serialGen.RetireSerial(msg.serial)
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *Conn) handleSendError(msg *Message, err error) {
|
||||
if msg.Type == TypeMethodCall {
|
||||
conn.calls.handleSendError(msg, err)
|
||||
} else if msg.Type == TypeMethodReply {
|
||||
if _, ok := err.(FormatError); ok {
|
||||
conn.sendError(err, msg.Headers[FieldDestination].value.(string), msg.Headers[FieldReplySerial].value.(uint32))
|
||||
}
|
||||
}
|
||||
conn.serialGen.RetireSerial(msg.serial)
|
||||
}
|
||||
|
||||
// Send sends the given message to the message bus. You usually don't need to
|
||||
// use this; use the higher-level equivalents (Call / Go, Emit and Export)
|
||||
// instead. If msg is a method call and NoReplyExpected is not set, a non-nil
|
||||
|
||||
16
src/runtime/vendor/github.com/godbus/dbus/v5/decoder.go
generated
vendored
16
src/runtime/vendor/github.com/godbus/dbus/v5/decoder.go
generated
vendored
@@ -10,14 +10,16 @@ type decoder struct {
|
||||
in io.Reader
|
||||
order binary.ByteOrder
|
||||
pos int
|
||||
fds []int
|
||||
}
|
||||
|
||||
// newDecoder returns a new decoder that reads values from in. The input is
|
||||
// expected to be in the given byte order.
|
||||
func newDecoder(in io.Reader, order binary.ByteOrder) *decoder {
|
||||
func newDecoder(in io.Reader, order binary.ByteOrder, fds []int) *decoder {
|
||||
dec := new(decoder)
|
||||
dec.in = in
|
||||
dec.order = order
|
||||
dec.fds = fds
|
||||
return dec
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ func (dec *decoder) Decode(sig Signature) (vs []interface{}, err error) {
|
||||
vs = make([]interface{}, 0)
|
||||
s := sig.str
|
||||
for s != "" {
|
||||
err, rem := validSingle(s, 0)
|
||||
err, rem := validSingle(s, &depthCounter{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -150,7 +152,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
|
||||
if len(sig.str) == 0 {
|
||||
panic(FormatError("variant signature is empty"))
|
||||
}
|
||||
err, rem := validSingle(sig.str, 0)
|
||||
err, rem := validSingle(sig.str, &depthCounter{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -161,7 +163,11 @@ func (dec *decoder) decode(s string, depth int) interface{} {
|
||||
variant.value = dec.decode(sig.str, depth+1)
|
||||
return variant
|
||||
case 'h':
|
||||
return UnixFDIndex(dec.decode("u", depth).(uint32))
|
||||
idx := dec.decode("u", depth).(uint32)
|
||||
if int(idx) < len(dec.fds) {
|
||||
return UnixFD(dec.fds[idx])
|
||||
}
|
||||
return UnixFDIndex(idx)
|
||||
case 'a':
|
||||
if len(s) > 1 && s[1] == '{' {
|
||||
ksig := s[2:3]
|
||||
@@ -219,7 +225,7 @@ func (dec *decoder) decode(s string, depth int) interface{} {
|
||||
v := make([]interface{}, 0)
|
||||
s = s[1 : len(s)-1]
|
||||
for s != "" {
|
||||
err, rem := validSingle(s, 0)
|
||||
err, rem := validSingle(s, &depthCounter{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
61
src/runtime/vendor/github.com/godbus/dbus/v5/encoder.go
generated
vendored
61
src/runtime/vendor/github.com/godbus/dbus/v5/encoder.go
generated
vendored
@@ -5,28 +5,33 @@ import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// An encoder encodes values to the D-Bus wire format.
|
||||
type encoder struct {
|
||||
out io.Writer
|
||||
fds []int
|
||||
order binary.ByteOrder
|
||||
pos int
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to out in the given byte order.
|
||||
func newEncoder(out io.Writer, order binary.ByteOrder) *encoder {
|
||||
return newEncoderAtOffset(out, 0, order)
|
||||
func newEncoder(out io.Writer, order binary.ByteOrder, fds []int) *encoder {
|
||||
enc := newEncoderAtOffset(out, 0, order, fds)
|
||||
return enc
|
||||
}
|
||||
|
||||
// newEncoderAtOffset returns a new encoder that writes to out in the given
|
||||
// byte order. Specify the offset to initialize pos for proper alignment
|
||||
// computation.
|
||||
func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder) *encoder {
|
||||
func newEncoderAtOffset(out io.Writer, offset int, order binary.ByteOrder, fds []int) *encoder {
|
||||
enc := new(encoder)
|
||||
enc.out = out
|
||||
enc.order = order
|
||||
enc.pos = offset
|
||||
enc.fds = fds
|
||||
return enc
|
||||
}
|
||||
|
||||
@@ -75,6 +80,9 @@ func (enc *encoder) Encode(vs ...interface{}) (err error) {
|
||||
// encode encodes the given value to the writer and panics on error. depth holds
|
||||
// the depth of the container nesting.
|
||||
func (enc *encoder) encode(v reflect.Value, depth int) {
|
||||
if depth > 64 {
|
||||
panic(FormatError("input exceeds depth limitation"))
|
||||
}
|
||||
enc.align(alignment(v.Type()))
|
||||
switch v.Kind() {
|
||||
case reflect.Uint8:
|
||||
@@ -97,7 +105,14 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
|
||||
enc.binwrite(uint16(v.Uint()))
|
||||
enc.pos += 2
|
||||
case reflect.Int, reflect.Int32:
|
||||
enc.binwrite(int32(v.Int()))
|
||||
if v.Type() == unixFDType {
|
||||
fd := v.Int()
|
||||
idx := len(enc.fds)
|
||||
enc.fds = append(enc.fds, int(fd))
|
||||
enc.binwrite(uint32(idx))
|
||||
} else {
|
||||
enc.binwrite(int32(v.Int()))
|
||||
}
|
||||
enc.pos += 4
|
||||
case reflect.Uint, reflect.Uint32:
|
||||
enc.binwrite(uint32(v.Uint()))
|
||||
@@ -112,9 +127,21 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
|
||||
enc.binwrite(v.Float())
|
||||
enc.pos += 8
|
||||
case reflect.String:
|
||||
enc.encode(reflect.ValueOf(uint32(len(v.String()))), depth)
|
||||
str := v.String()
|
||||
if !utf8.ValidString(str) {
|
||||
panic(FormatError("input has a not-utf8 char in string"))
|
||||
}
|
||||
if strings.IndexByte(str, byte(0)) != -1 {
|
||||
panic(FormatError("input has a null char('\\000') in string"))
|
||||
}
|
||||
if v.Type() == objectPathType {
|
||||
if !ObjectPath(str).IsValid() {
|
||||
panic(FormatError("invalid object path"))
|
||||
}
|
||||
}
|
||||
enc.encode(reflect.ValueOf(uint32(len(str))), depth)
|
||||
b := make([]byte, v.Len()+1)
|
||||
copy(b, v.String())
|
||||
copy(b, str)
|
||||
b[len(b)-1] = 0
|
||||
n, err := enc.out.Write(b)
|
||||
if err != nil {
|
||||
@@ -124,20 +151,23 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
|
||||
case reflect.Ptr:
|
||||
enc.encode(v.Elem(), depth)
|
||||
case reflect.Slice, reflect.Array:
|
||||
if depth >= 64 {
|
||||
panic(FormatError("input exceeds container depth limit"))
|
||||
}
|
||||
// Lookahead offset: 4 bytes for uint32 length (with alignment),
|
||||
// plus alignment for elements.
|
||||
n := enc.padding(0, 4) + 4
|
||||
offset := enc.pos + n + enc.padding(n, alignment(v.Type().Elem()))
|
||||
|
||||
var buf bytes.Buffer
|
||||
bufenc := newEncoderAtOffset(&buf, offset, enc.order)
|
||||
bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds)
|
||||
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
bufenc.encode(v.Index(i), depth+1)
|
||||
}
|
||||
|
||||
if buf.Len() > 1<<26 {
|
||||
panic(FormatError("input exceeds array size limitation"))
|
||||
}
|
||||
|
||||
enc.fds = bufenc.fds
|
||||
enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
|
||||
length := buf.Len()
|
||||
enc.align(alignment(v.Type().Elem()))
|
||||
@@ -146,13 +176,10 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
|
||||
}
|
||||
enc.pos += length
|
||||
case reflect.Struct:
|
||||
if depth >= 64 && v.Type() != signatureType {
|
||||
panic(FormatError("input exceeds container depth limit"))
|
||||
}
|
||||
switch t := v.Type(); t {
|
||||
case signatureType:
|
||||
str := v.Field(0)
|
||||
enc.encode(reflect.ValueOf(byte(str.Len())), depth+1)
|
||||
enc.encode(reflect.ValueOf(byte(str.Len())), depth)
|
||||
b := make([]byte, str.Len()+1)
|
||||
copy(b, str.String())
|
||||
b[len(b)-1] = 0
|
||||
@@ -176,9 +203,6 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
|
||||
case reflect.Map:
|
||||
// Maps are arrays of structures, so they actually increase the depth by
|
||||
// 2.
|
||||
if depth >= 63 {
|
||||
panic(FormatError("input exceeds container depth limit"))
|
||||
}
|
||||
if !isKeyType(v.Type().Key()) {
|
||||
panic(InvalidTypeError{v.Type()})
|
||||
}
|
||||
@@ -189,12 +213,13 @@ func (enc *encoder) encode(v reflect.Value, depth int) {
|
||||
offset := enc.pos + n + enc.padding(n, 8)
|
||||
|
||||
var buf bytes.Buffer
|
||||
bufenc := newEncoderAtOffset(&buf, offset, enc.order)
|
||||
bufenc := newEncoderAtOffset(&buf, offset, enc.order, enc.fds)
|
||||
for _, k := range keys {
|
||||
bufenc.align(8)
|
||||
bufenc.encode(k, depth+2)
|
||||
bufenc.encode(v.MapIndex(k), depth+2)
|
||||
}
|
||||
enc.fds = bufenc.fds
|
||||
enc.encode(reflect.ValueOf(uint32(buf.Len())), depth)
|
||||
length := buf.Len()
|
||||
enc.align(8)
|
||||
|
||||
37
src/runtime/vendor/github.com/godbus/dbus/v5/export.go
generated
vendored
37
src/runtime/vendor/github.com/godbus/dbus/v5/export.go
generated
vendored
@@ -26,6 +26,27 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func MakeNoObjectError(path ObjectPath) Error {
|
||||
return Error{
|
||||
"org.freedesktop.DBus.Error.NoSuchObject",
|
||||
[]interface{}{fmt.Sprintf("No such object '%s'", string(path))},
|
||||
}
|
||||
}
|
||||
|
||||
func MakeUnknownMethodError(methodName string) Error {
|
||||
return Error{
|
||||
"org.freedesktop.DBus.Error.UnknownMethod",
|
||||
[]interface{}{fmt.Sprintf("Unknown / invalid method '%s'", methodName)},
|
||||
}
|
||||
}
|
||||
|
||||
func MakeUnknownInterfaceError(ifaceName string) Error {
|
||||
return Error{
|
||||
"org.freedesktop.DBus.Error.UnknownInterface",
|
||||
[]interface{}{fmt.Sprintf("Object does not implement the interface '%s'", ifaceName)},
|
||||
}
|
||||
}
|
||||
|
||||
func MakeFailedError(err error) *Error {
|
||||
return &Error{
|
||||
"org.freedesktop.DBus.Error.Failed",
|
||||
@@ -128,6 +149,11 @@ func (conn *Conn) handleCall(msg *Message) {
|
||||
ifaceName, _ := msg.Headers[FieldInterface].value.(string)
|
||||
sender, hasSender := msg.Headers[FieldSender].value.(string)
|
||||
serial := msg.serial
|
||||
|
||||
if len(name) == 0 {
|
||||
conn.sendError(ErrMsgUnknownMethod, sender, serial)
|
||||
}
|
||||
|
||||
if ifaceName == "org.freedesktop.DBus.Peer" {
|
||||
switch name {
|
||||
case "Ping":
|
||||
@@ -135,29 +161,26 @@ func (conn *Conn) handleCall(msg *Message) {
|
||||
case "GetMachineId":
|
||||
conn.sendReply(sender, serial, conn.uuid)
|
||||
default:
|
||||
conn.sendError(ErrMsgUnknownMethod, sender, serial)
|
||||
conn.sendError(MakeUnknownMethodError(name), sender, serial)
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(name) == 0 {
|
||||
conn.sendError(ErrMsgUnknownMethod, sender, serial)
|
||||
}
|
||||
|
||||
object, ok := conn.handler.LookupObject(path)
|
||||
if !ok {
|
||||
conn.sendError(ErrMsgNoObject, sender, serial)
|
||||
conn.sendError(MakeNoObjectError(path), sender, serial)
|
||||
return
|
||||
}
|
||||
|
||||
iface, exists := object.LookupInterface(ifaceName)
|
||||
if !exists {
|
||||
conn.sendError(ErrMsgUnknownInterface, sender, serial)
|
||||
conn.sendError(MakeUnknownInterfaceError(ifaceName), sender, serial)
|
||||
return
|
||||
}
|
||||
|
||||
m, exists := iface.LookupMethod(name)
|
||||
if !exists {
|
||||
conn.sendError(ErrMsgUnknownMethod, sender, serial)
|
||||
conn.sendError(MakeUnknownMethodError(name), sender, serial)
|
||||
return
|
||||
}
|
||||
args, err := conn.decodeArguments(m, sender, msg)
|
||||
|
||||
73
src/runtime/vendor/github.com/godbus/dbus/v5/message.go
generated
vendored
73
src/runtime/vendor/github.com/godbus/dbus/v5/message.go
generated
vendored
@@ -118,11 +118,7 @@ type header struct {
|
||||
Variant
|
||||
}
|
||||
|
||||
// DecodeMessage tries to decode a single message in the D-Bus wire format
|
||||
// from the given reader. The byte order is figured out from the first byte.
|
||||
// The possibly returned error can be an error of the underlying reader, an
|
||||
// InvalidMessageError or a FormatError.
|
||||
func DecodeMessage(rd io.Reader) (msg *Message, err error) {
|
||||
func DecodeMessageWithFDs(rd io.Reader, fds []int) (msg *Message, err error) {
|
||||
var order binary.ByteOrder
|
||||
var hlength, length uint32
|
||||
var typ, flags, proto byte
|
||||
@@ -142,7 +138,7 @@ func DecodeMessage(rd io.Reader) (msg *Message, err error) {
|
||||
return nil, InvalidMessageError("invalid byte order")
|
||||
}
|
||||
|
||||
dec := newDecoder(rd, order)
|
||||
dec := newDecoder(rd, order, fds)
|
||||
dec.pos = 1
|
||||
|
||||
msg = new(Message)
|
||||
@@ -166,7 +162,7 @@ func DecodeMessage(rd io.Reader) (msg *Message, err error) {
|
||||
if hlength+length+16 > 1<<27 {
|
||||
return nil, InvalidMessageError("message is too long")
|
||||
}
|
||||
dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order)
|
||||
dec = newDecoder(io.MultiReader(bytes.NewBuffer(b), rd), order, fds)
|
||||
dec.pos = 12
|
||||
vs, err = dec.Decode(Signature{"a(yv)"})
|
||||
if err != nil {
|
||||
@@ -196,7 +192,7 @@ func DecodeMessage(rd io.Reader) (msg *Message, err error) {
|
||||
sig, _ := msg.Headers[FieldSignature].value.(Signature)
|
||||
if sig.str != "" {
|
||||
buf := bytes.NewBuffer(body)
|
||||
dec = newDecoder(buf, order)
|
||||
dec = newDecoder(buf, order, fds)
|
||||
vs, err := dec.Decode(sig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -207,12 +203,32 @@ func DecodeMessage(rd io.Reader) (msg *Message, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// EncodeTo encodes and sends a message to the given writer. The byte order must
|
||||
// be either binary.LittleEndian or binary.BigEndian. If the message is not
|
||||
// valid or an error occurs when writing, an error is returned.
|
||||
func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error {
|
||||
// DecodeMessage tries to decode a single message in the D-Bus wire format
|
||||
// from the given reader. The byte order is figured out from the first byte.
|
||||
// The possibly returned error can be an error of the underlying reader, an
|
||||
// InvalidMessageError or a FormatError.
|
||||
func DecodeMessage(rd io.Reader) (msg *Message, err error) {
|
||||
return DecodeMessageWithFDs(rd, make([]int, 0));
|
||||
}
|
||||
|
||||
type nullwriter struct{}
|
||||
|
||||
func (nullwriter) Write(p []byte) (cnt int, err error) {
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (msg *Message) CountFds() (int, error) {
|
||||
if len(msg.Body) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
enc := newEncoder(nullwriter{}, nativeEndian, make([]int, 0))
|
||||
err := enc.Encode(msg.Body...)
|
||||
return len(enc.fds), err
|
||||
}
|
||||
|
||||
func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds []int, err error) {
|
||||
if err := msg.IsValid(); err != nil {
|
||||
return err
|
||||
return make([]int, 0), err
|
||||
}
|
||||
var vs [7]interface{}
|
||||
switch order {
|
||||
@@ -221,12 +237,16 @@ func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error {
|
||||
case binary.BigEndian:
|
||||
vs[0] = byte('B')
|
||||
default:
|
||||
return errors.New("dbus: invalid byte order")
|
||||
return make([]int, 0), errors.New("dbus: invalid byte order")
|
||||
}
|
||||
body := new(bytes.Buffer)
|
||||
enc := newEncoder(body, order)
|
||||
fds = make([]int, 0)
|
||||
enc := newEncoder(body, order, fds)
|
||||
if len(msg.Body) != 0 {
|
||||
enc.Encode(msg.Body...)
|
||||
err = enc.Encode(msg.Body...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
vs[1] = msg.Type
|
||||
vs[2] = msg.Flags
|
||||
@@ -239,17 +259,28 @@ func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) error {
|
||||
}
|
||||
vs[6] = headers
|
||||
var buf bytes.Buffer
|
||||
enc = newEncoder(&buf, order)
|
||||
enc.Encode(vs[:]...)
|
||||
enc = newEncoder(&buf, order, enc.fds)
|
||||
err = enc.Encode(vs[:]...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
enc.align(8)
|
||||
body.WriteTo(&buf)
|
||||
if buf.Len() > 1<<27 {
|
||||
return InvalidMessageError("message is too long")
|
||||
return make([]int, 0), InvalidMessageError("message is too long")
|
||||
}
|
||||
if _, err := buf.WriteTo(out); err != nil {
|
||||
return err
|
||||
return make([]int, 0), err
|
||||
}
|
||||
return nil
|
||||
return enc.fds, nil
|
||||
}
|
||||
|
||||
// EncodeTo encodes and sends a message to the given writer. The byte order must
|
||||
// be either binary.LittleEndian or binary.BigEndian. If the message is not
|
||||
// valid or an error occurs when writing, an error is returned.
|
||||
func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) (err error) {
|
||||
_, err = msg.EncodeToWithFDs(out, order)
|
||||
return err
|
||||
}
|
||||
|
||||
// IsValid checks whether msg is a valid message and returns an
|
||||
|
||||
66
src/runtime/vendor/github.com/godbus/dbus/v5/sig.go
generated
vendored
66
src/runtime/vendor/github.com/godbus/dbus/v5/sig.go
generated
vendored
@@ -34,7 +34,7 @@ type Signature struct {
|
||||
func SignatureOf(vs ...interface{}) Signature {
|
||||
var s string
|
||||
for _, v := range vs {
|
||||
s += getSignature(reflect.TypeOf(v))
|
||||
s += getSignature(reflect.TypeOf(v), &depthCounter{})
|
||||
}
|
||||
return Signature{s}
|
||||
}
|
||||
@@ -42,11 +42,19 @@ func SignatureOf(vs ...interface{}) Signature {
|
||||
// SignatureOfType returns the signature of the given type. It panics if the
|
||||
// type is not representable in D-Bus.
|
||||
func SignatureOfType(t reflect.Type) Signature {
|
||||
return Signature{getSignature(t)}
|
||||
return Signature{getSignature(t, &depthCounter{})}
|
||||
}
|
||||
|
||||
// getSignature returns the signature of the given type and panics on unknown types.
|
||||
func getSignature(t reflect.Type) string {
|
||||
func getSignature(t reflect.Type, depth *depthCounter) (sig string) {
|
||||
if !depth.Valid() {
|
||||
panic("container nesting too deep")
|
||||
}
|
||||
defer func() {
|
||||
if len(sig) > 255 {
|
||||
panic("signature exceeds the length limitation")
|
||||
}
|
||||
}()
|
||||
// handle simple types first
|
||||
switch t.Kind() {
|
||||
case reflect.Uint8:
|
||||
@@ -74,7 +82,7 @@ func getSignature(t reflect.Type) string {
|
||||
case reflect.Float64:
|
||||
return "d"
|
||||
case reflect.Ptr:
|
||||
return getSignature(t.Elem())
|
||||
return getSignature(t.Elem(), depth)
|
||||
case reflect.String:
|
||||
if t == objectPathType {
|
||||
return "o"
|
||||
@@ -90,17 +98,20 @@ func getSignature(t reflect.Type) string {
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
|
||||
s += getSignature(t.Field(i).Type)
|
||||
s += getSignature(t.Field(i).Type, depth.EnterStruct())
|
||||
}
|
||||
}
|
||||
if len(s) == 0 {
|
||||
panic("empty struct")
|
||||
}
|
||||
return "(" + s + ")"
|
||||
case reflect.Array, reflect.Slice:
|
||||
return "a" + getSignature(t.Elem())
|
||||
return "a" + getSignature(t.Elem(), depth.EnterArray())
|
||||
case reflect.Map:
|
||||
if !isKeyType(t.Key()) {
|
||||
panic(InvalidTypeError{t})
|
||||
}
|
||||
return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}"
|
||||
return "a{" + getSignature(t.Key(), depth.EnterArray().EnterDictEntry()) + getSignature(t.Elem(), depth.EnterArray().EnterDictEntry()) + "}"
|
||||
case reflect.Interface:
|
||||
return "v"
|
||||
}
|
||||
@@ -118,7 +129,7 @@ func ParseSignature(s string) (sig Signature, err error) {
|
||||
}
|
||||
sig.str = s
|
||||
for err == nil && len(s) != 0 {
|
||||
err, s = validSingle(s, 0)
|
||||
err, s = validSingle(s, &depthCounter{})
|
||||
}
|
||||
if err != nil {
|
||||
sig = Signature{""}
|
||||
@@ -144,7 +155,7 @@ func (s Signature) Empty() bool {
|
||||
|
||||
// Single returns whether the signature represents a single, complete type.
|
||||
func (s Signature) Single() bool {
|
||||
err, r := validSingle(s.str, 0)
|
||||
err, r := validSingle(s.str, &depthCounter{})
|
||||
return err != nil && r == ""
|
||||
}
|
||||
|
||||
@@ -164,15 +175,38 @@ func (e SignatureError) Error() string {
|
||||
return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
|
||||
}
|
||||
|
||||
type depthCounter struct {
|
||||
arrayDepth, structDepth, dictEntryDepth int
|
||||
}
|
||||
|
||||
func (cnt *depthCounter) Valid() bool {
|
||||
return cnt.arrayDepth <= 32 && cnt.structDepth <= 32 && cnt.dictEntryDepth <= 32
|
||||
}
|
||||
|
||||
func (cnt depthCounter) EnterArray() *depthCounter {
|
||||
cnt.arrayDepth++
|
||||
return &cnt
|
||||
}
|
||||
|
||||
func (cnt depthCounter) EnterStruct() *depthCounter {
|
||||
cnt.structDepth++
|
||||
return &cnt
|
||||
}
|
||||
|
||||
func (cnt depthCounter) EnterDictEntry() *depthCounter {
|
||||
cnt.dictEntryDepth++
|
||||
return &cnt
|
||||
}
|
||||
|
||||
// Try to read a single type from this string. If it was successful, err is nil
|
||||
// and rem is the remaining unparsed part. Otherwise, err is a non-nil
|
||||
// SignatureError and rem is "". depth is the current recursion depth which may
|
||||
// not be greater than 64 and should be given as 0 on the first call.
|
||||
func validSingle(s string, depth int) (err error, rem string) {
|
||||
func validSingle(s string, depth *depthCounter) (err error, rem string) {
|
||||
if s == "" {
|
||||
return SignatureError{Sig: s, Reason: "empty signature"}, ""
|
||||
}
|
||||
if depth > 64 {
|
||||
if !depth.Valid() {
|
||||
return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
|
||||
}
|
||||
switch s[0] {
|
||||
@@ -187,10 +221,10 @@ func validSingle(s string, depth int) (err error, rem string) {
|
||||
i++
|
||||
rem = s[i+1:]
|
||||
s = s[2:i]
|
||||
if err, _ = validSingle(s[:1], depth+1); err != nil {
|
||||
if err, _ = validSingle(s[:1], depth.EnterArray().EnterDictEntry()); err != nil {
|
||||
return err, ""
|
||||
}
|
||||
err, nr := validSingle(s[1:], depth+1)
|
||||
err, nr := validSingle(s[1:], depth.EnterArray().EnterDictEntry())
|
||||
if err != nil {
|
||||
return err, ""
|
||||
}
|
||||
@@ -199,7 +233,7 @@ func validSingle(s string, depth int) (err error, rem string) {
|
||||
}
|
||||
return nil, rem
|
||||
}
|
||||
return validSingle(s[1:], depth+1)
|
||||
return validSingle(s[1:], depth.EnterArray())
|
||||
case '(':
|
||||
i := findMatching(s, '(', ')')
|
||||
if i == -1 {
|
||||
@@ -208,7 +242,7 @@ func validSingle(s string, depth int) (err error, rem string) {
|
||||
rem = s[i+1:]
|
||||
s = s[1:i]
|
||||
for err == nil && s != "" {
|
||||
err, s = validSingle(s, depth+1)
|
||||
err, s = validSingle(s, depth.EnterStruct())
|
||||
}
|
||||
if err != nil {
|
||||
rem = ""
|
||||
@@ -236,7 +270,7 @@ func findMatching(s string, left, right rune) int {
|
||||
// typeFor returns the type of the given signature. It ignores any left over
|
||||
// characters and panics if s doesn't start with a valid type signature.
|
||||
func typeFor(s string) (t reflect.Type) {
|
||||
err, _ := validSingle(s, 0)
|
||||
err, _ := validSingle(s, &depthCounter{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
10
src/runtime/vendor/github.com/godbus/dbus/v5/transport_generic.go
generated
vendored
10
src/runtime/vendor/github.com/godbus/dbus/v5/transport_generic.go
generated
vendored
@@ -41,10 +41,12 @@ func (t genericTransport) ReadMessage() (*Message, error) {
|
||||
}
|
||||
|
||||
func (t genericTransport) SendMessage(msg *Message) error {
|
||||
for _, v := range msg.Body {
|
||||
if _, ok := v.(UnixFD); ok {
|
||||
return errors.New("dbus: unix fd passing not enabled")
|
||||
}
|
||||
fds, err := msg.CountFds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fds != 0 {
|
||||
return errors.New("dbus: unix fd passing not enabled")
|
||||
}
|
||||
return msg.EncodeTo(t, nativeEndian)
|
||||
}
|
||||
|
||||
24
src/runtime/vendor/github.com/godbus/dbus/v5/transport_unix.go
generated
vendored
24
src/runtime/vendor/github.com/godbus/dbus/v5/transport_unix.go
generated
vendored
@@ -113,7 +113,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
|
||||
if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dec := newDecoder(bytes.NewBuffer(headerdata), order)
|
||||
dec := newDecoder(bytes.NewBuffer(headerdata), order, make([]int, 0))
|
||||
dec.pos = 12
|
||||
vs, err := dec.Decode(Signature{"a(yv)"})
|
||||
if err != nil {
|
||||
@@ -147,7 +147,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, err := DecodeMessage(bytes.NewBuffer(all))
|
||||
msg, err := DecodeMessageWithFDs(bytes.NewBuffer(all), fds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -179,21 +179,21 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
|
||||
}
|
||||
|
||||
func (t *unixTransport) SendMessage(msg *Message) error {
|
||||
fds := make([]int, 0)
|
||||
for i, v := range msg.Body {
|
||||
if fd, ok := v.(UnixFD); ok {
|
||||
msg.Body[i] = UnixFDIndex(len(fds))
|
||||
fds = append(fds, int(fd))
|
||||
}
|
||||
fdcnt, err := msg.CountFds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(fds) != 0 {
|
||||
if fdcnt != 0 {
|
||||
if !t.hasUnixFDs {
|
||||
return errors.New("dbus: unix fd passing not enabled")
|
||||
}
|
||||
msg.Headers[FieldUnixFDs] = MakeVariant(uint32(len(fds)))
|
||||
oob := syscall.UnixRights(fds...)
|
||||
msg.Headers[FieldUnixFDs] = MakeVariant(uint32(fdcnt))
|
||||
buf := new(bytes.Buffer)
|
||||
msg.EncodeTo(buf, nativeEndian)
|
||||
fds, err := msg.EncodeToWithFDs(buf, nativeEndian)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oob := syscall.UnixRights(fds...)
|
||||
n, oobn, err := t.UnixConn.WriteMsgUnix(buf.Bytes(), oob, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
14
src/runtime/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go
generated
vendored
Normal file
14
src/runtime/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package dbus
|
||||
|
||||
import "io"
|
||||
|
||||
func (t *unixTransport) SendNullByte() error {
|
||||
n, _, err := t.UnixConn.WriteMsgUnix([]byte{0}, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != 1 {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
return nil
|
||||
}
|
||||
2
src/runtime/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go
generated
vendored
2
src/runtime/vendor/github.com/opencontainers/selinux/go-selinux/rchcon.go
generated
vendored
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func rchcon(fpath, label string) error {
|
||||
return pwalkdir.Walk(fpath, func(p string, _ fs.DirEntry, _ error) error {
|
||||
e := setFileLabel(p, label)
|
||||
e := lSetFileLabel(p, label)
|
||||
// Walk a file tree can race with removal, so ignore ENOENT.
|
||||
if errors.Is(e, os.ErrNotExist) {
|
||||
return nil
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user