Compare commits

..

5 Commits

Author SHA1 Message Date
6b6ff71c29 Update to containerd 1.6.8
Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2022-08-18 12:15:33 +01:00
bb5b212663 Fix installation script for containerd on armhf
Fixes #295

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2022-08-18 11:19:13 +01:00
9564e64980 Fix issue with provider metrics
https://github.com/openfaas/faas-provider/pull/66

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
2022-08-17 20:33:58 +01:00
6dbc33d045 Bump github.com/containerd/containerd from 1.6.4 to 1.6.6
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.6.4 to 1.6.6.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.6.4...v1.6.6)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-16 14:41:51 +01:00
5cedf28929 Dev.md updated to version 0.16.2
Signed-off-by: Nitishkumar Singh <nitishkumarsingh71@gmail.com>

updated faasd version in terraform script

Signed-off-by: Nitishkumar Singh <nitishkumarsingh71@gmail.com>
2022-07-19 13:08:50 +01:00
189 changed files with 15584 additions and 3439 deletions

View File

@ -1,7 +1,7 @@
Version := $(shell git describe --tags --dirty)
GitCommit := $(shell git rev-parse HEAD)
LDFLAGS := "-s -w -X main.Version=$(Version) -X main.GitCommit=$(GitCommit)"
CONTAINERD_VER := 1.6.4
CONTAINERD_VER := 1.6.8
CNI_VERSION := v0.9.1
ARCH := amd64
@ -33,7 +33,7 @@ hashgen:
.PHONY: prepare-test
prepare-test:
curl -sLSf https://github.com/containerd/containerd/releases/download/v$(CONTAINERD_VER)/containerd-$(CONTAINERD_VER)-linux-amd64.tar.gz > /tmp/containerd.tar.gz && sudo tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/ --strip-components=1
curl -SLfs https://raw.githubusercontent.com/containerd/containerd/v1.6.4/containerd.service | sudo tee /etc/systemd/system/containerd.service
curl -SLfs https://raw.githubusercontent.com/containerd/containerd/v1.6.8/containerd.service | sudo tee /etc/systemd/system/containerd.service
sudo systemctl daemon-reload && sudo systemctl start containerd
sudo /sbin/sysctl -w net.ipv4.conf.all.forwarding=1
sudo mkdir -p /opt/cni/bin

View File

@ -88,7 +88,7 @@ You have three options - binaries for PC, binaries for armhf, or build from sour
* Install containerd `x86_64` only
```bash
export VER=1.6.4
export VER=1.6.8
curl -sSL https://github.com/containerd/containerd/releases/download/v$VER/containerd-$VER-linux-amd64.tar.gz > /tmp/containerd.tar.gz \
&& sudo tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/ --strip-components=1
@ -100,7 +100,7 @@ containerd -version
Building `containerd` on armhf is extremely slow, so I've provided binaries for you.
```bash
curl -sSL https://github.com/alexellis/containerd-armhf/releases/download/v1.6.4/containerd.tgz | sudo tar -xvz --strip-components=2 -C /usr/local/bin/
curl -sSL https://github.com/alexellis/containerd-armhf/releases/download/v1.6.8/containerd.tgz | sudo tar -xvz --strip-components=2 -C /usr/local/bin/
```
* Or clone / build / install [containerd](https://github.com/containerd/containerd) from source:
@ -112,7 +112,7 @@ containerd -version
git clone https://github.com/containerd/containerd
cd containerd
git fetch origin --tags
git checkout v1.6.4
git checkout v1.6.8
make
sudo make install
@ -123,7 +123,7 @@ containerd -version
#### Ensure containerd is running
```bash
curl -sLS https://raw.githubusercontent.com/containerd/containerd/v1.6.4/containerd.service > /tmp/containerd.service
curl -sLS https://raw.githubusercontent.com/containerd/containerd/v1.6.8/containerd.service > /tmp/containerd.service
# Extend the timeouts for low-performance VMs
echo "[Manager]" | tee -a /tmp/containerd.service
@ -237,7 +237,7 @@ export SUFFIX="-armhf"
export SUFFIX="-arm64"
# Then download
curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.13.0/faasd$SUFFIX" \
curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.16.2/faasd$SUFFIX" \
-o "/tmp/faasd" \
&& chmod +x "/tmp/faasd"
sudo mv /tmp/faasd /usr/local/bin/

View File

@ -6,8 +6,8 @@ packages:
- git
runcmd:
- curl -sLSf https://github.com/containerd/containerd/releases/download/v1.6.4/containerd-1.6.4-linux-amd64.tar.gz > /tmp/containerd.tar.gz && tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/ --strip-components=1
- curl -SLfs https://raw.githubusercontent.com/containerd/containerd/v1.6.4/containerd.service | tee /etc/systemd/system/containerd.service
- curl -sLSf https://github.com/containerd/containerd/releases/download/v1.6.8/containerd-1.6.8-linux-amd64.tar.gz > /tmp/containerd.tar.gz && tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/ --strip-components=1
- curl -SLfs https://raw.githubusercontent.com/containerd/containerd/v1.6.8/containerd.service | tee /etc/systemd/system/containerd.service
- systemctl daemon-reload && systemctl start containerd
- /sbin/sysctl -w net.ipv4.conf.all.forwarding=1
- mkdir -p /opt/cni/bin
@ -16,8 +16,8 @@ runcmd:
- mkdir -p /var/lib/faasd/secrets/
- echo ${gw_password} > /var/lib/faasd/secrets/basic-auth-password
- echo admin > /var/lib/faasd/secrets/basic-auth-user
- cd /go/src/github.com/openfaas/ && git clone --depth 1 --branch 0.13.0 https://github.com/openfaas/faasd
- curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.13.0/faasd" --output "/usr/local/bin/faasd" && chmod a+x "/usr/local/bin/faasd"
- cd /go/src/github.com/openfaas/ && git clone --depth 1 --branch 0.16.2 https://github.com/openfaas/faasd
- curl -fSLs "https://github.com/openfaas/faasd/releases/download/0.16.2/faasd" --output "/usr/local/bin/faasd" && chmod a+x "/usr/local/bin/faasd"
- cd /go/src/github.com/openfaas/faasd/ && /usr/local/bin/faasd install
- systemctl status -l containerd --no-pager
- journalctl -u faasd-provider --no-pager

30
go.mod
View File

@ -3,35 +3,34 @@ module github.com/openfaas/faasd
go 1.18
require (
github.com/alexellis/arkade v0.0.0-20220816075441-1a4d561feb3e
github.com/alexellis/go-execute v0.5.0
github.com/alexellis/k3sup v0.0.0-20220105194923-e2bb18116d36
github.com/compose-spec/compose-go v0.0.0-20200528042322-36d8ce368e05
github.com/containerd/containerd v1.6.4
github.com/containerd/go-cni v1.1.5
github.com/containerd/containerd v1.6.6
github.com/containerd/go-cni v1.1.6
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
github.com/docker/cli v0.0.0-20191105005515-99c5edceb48d
github.com/docker/distribution v2.8.1+incompatible
github.com/docker/docker v17.12.0-ce-rc1.0.20191113042239-ea84732a7725+incompatible // indirect
github.com/docker/docker-credential-helpers v0.6.3 // indirect
github.com/docker/go-units v0.4.0
github.com/gorilla/mux v1.8.0
github.com/morikuni/aec v1.0.0
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/openfaas/faas-provider v0.19.0
github.com/openfaas/faas/gateway v0.0.0-20220509091830-4e868f5f9d81
github.com/openfaas/faas-provider v0.19.1
github.com/openfaas/faas/gateway v0.0.0-20220811112234-2cdc7f308316
github.com/pkg/errors v0.9.1
github.com/sethvargo/go-password v0.2.0
github.com/spf13/cobra v1.4.0
github.com/spf13/cobra v1.5.0
github.com/spf13/pflag v1.0.5
github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f
golang.org/x/sys v0.0.0-20220702020025-31831981b65f
k8s.io/apimachinery v0.24.0
github.com/vishvananda/netlink v1.2.1-beta.2
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab
k8s.io/apimachinery v0.24.3
)
require (
github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/Microsoft/hcsshim v0.9.2 // indirect
github.com/Microsoft/hcsshim v0.9.4 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/containerd/cgroups v1.0.3 // indirect
@ -39,7 +38,8 @@ require (
github.com/containerd/fifo v1.0.0 // indirect
github.com/containerd/ttrpc v1.1.0 // indirect
github.com/containerd/typeurl v1.0.2 // indirect
github.com/containernetworking/cni v1.1.0 // indirect
github.com/containernetworking/cni v1.1.1 // indirect
github.com/docker/docker-credential-helpers v0.6.3 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
github.com/gogo/googleapis v1.4.0 // indirect
@ -58,7 +58,7 @@ require (
github.com/moby/sys/signal v0.6.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/opencontainers/runc v1.1.1 // indirect
github.com/opencontainers/runc v1.1.2 // indirect
github.com/opencontainers/selinux v1.10.1 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
@ -70,7 +70,7 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
google.golang.org/grpc v1.43.0 // indirect

113
go.sum
View File

@ -47,7 +47,6 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@ -66,8 +65,8 @@ github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
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.4 h1:mnUj0ivWy6UzbB1uLFqKR6F+ZyiDc7j4iGgHTpO+5+I=
github.com/Microsoft/hcsshim v0.9.4/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=
@ -82,15 +81,13 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alexellis/go-execute v0.0.0-20200124154445-8697e4e28c5e/go.mod h1:zfRbgnPVxXCSpiKrg1CE72hNUWInqxExiaz2D9ppTts=
github.com/alexellis/arkade v0.0.0-20220816075441-1a4d561feb3e h1:olA8FP3VkMVhoS6cjq/rhmn7/0/WSKWN9ExxJxr/y00=
github.com/alexellis/arkade v0.0.0-20220816075441-1a4d561feb3e/go.mod h1:RgpDLl+/7P6rd8N5wQCs8rnK4y2PTLSp0RxmJggzN1Y=
github.com/alexellis/go-execute v0.5.0 h1:L8kgNlFzNbJov7jrInlaig7i6ZUSz/tYYmqvb8dyD0s=
github.com/alexellis/go-execute v0.5.0/go.mod h1:AgHTcsCF9wrP0mMVTO8N+lFw1Biy71NybBOk8M+qgy8=
github.com/alexellis/k3sup v0.0.0-20220105194923-e2bb18116d36 h1:C2xOUGShRL9OWqO6IuWQdjKKr05OWZFRVdHYGxLCUyQ=
github.com/alexellis/k3sup v0.0.0-20220105194923-e2bb18116d36/go.mod h1:Lme78V4UsBIvvwN5gXZp7r32SI7ebgHb3h8o/VxOFK8=
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
@ -128,8 +125,6 @@ github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
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-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@ -177,8 +172,8 @@ github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09Zvgq
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
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.6.4 h1:SEDZBp10mhCp+hkO3Njz/YhGrI7ah3edNcUlRdUPOgg=
github.com/containerd/containerd v1.6.4/go.mod h1:oWOqbuJUZmOVafhA0lj2NAXbiO1u7F0K5l1bUgdyo94=
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=
@ -197,8 +192,8 @@ github.com/containerd/fifo v1.0.0 h1:6PirWBr9/L7GDamKr+XM0IeUFXu5mf3M/BPpH9gaLBU
github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk=
github.com/containerd/go-cni v1.1.5 h1:WUkuZ6kDkmECdd/qEPetq1czj6ivDkAoaOpL8yv8vO8=
github.com/containerd/go-cni v1.1.5/go.mod h1:Rf2ZrMycr1El589IyuRzn7RkfdRZVKaFGaxSDHVAjj0=
github.com/containerd/go-cni v1.1.6 h1:el5WPymG5nRRLQF1EfB97FWob4Tdc8INg8RZMaXWZlo=
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=
@ -232,8 +227,8 @@ 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.1.0 h1:T00oIz4hef+/p9gpRZa57SnIN+QnbmAHBjbxaOSFo9U=
github.com/containernetworking/cni v1.1.0/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
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/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
@ -258,7 +253,7 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfc
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
@ -351,7 +346,6 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
@ -460,20 +454,11 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/raft v1.3.1/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@ -506,7 +491,6 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.12/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.13 h1:eSvu8Tmq6j2psUJqJrLcWH6K3w5Dwc+qipbaA6eVEN4=
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -521,7 +505,6 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@ -530,10 +513,7 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
@ -544,7 +524,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@ -576,17 +555,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
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/nats-io/jwt v1.2.2/go.mod h1:/xX356yQA6LuXI9xWW7mZNpxgF2mBmGecH+Fj34sP5Q=
github.com/nats-io/jwt/v2 v2.0.2/go.mod h1:VRP+deawSXyhNjXmxPCHskrR6Mq50BqpEI5SEcNiGlY=
github.com/nats-io/nats-server/v2 v2.2.6/go.mod h1:sEnFaxqe09cDmfMgACxZbziXnhQFhwk+aKkZjBBRYrI=
github.com/nats-io/nats-server/v2 v2.3.2/go.mod h1:dUf7Cm5z5LbciFVwWx54owyCKm8x4/hL6p7rrljhLFY=
github.com/nats-io/nats-streaming-server v0.22.0/go.mod h1:Jyu3eUQaUAjwd5TiBuLagKdQRofPrHoIXt1kL0U/e5o=
github.com/nats-io/nats.go v1.11.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
github.com/nats-io/nats.go v1.11.1-0.20210623165838-4b75fc59ae30/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nats-io/stan.go v0.9.0/go.mod h1:0jEuBXKauB1HHJswHM/lx05K48TJ1Yxj6VIfM4k+aB4=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@ -634,8 +602,8 @@ github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runc v1.1.1 h1:PJ9DSs2sVwE0iVr++pAHE6QkS9tzcVWozlPifdwMgrU=
github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
github.com/opencontainers/runc v1.1.2 h1:2VSZwLx5k/BfsBxMMipG/LYUnmqOD/BPkIVgQUcTlLw=
github.com/opencontainers/runc v1.1.2/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
@ -650,14 +618,10 @@ github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xA
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/openfaas/faas-provider v0.18.6/go.mod h1:fq1JL0mX4rNvVVvRLaLRJ3H6o667sHuyP5p/7SZEe98=
github.com/openfaas/faas-provider v0.18.7/go.mod h1:S217qfIaMrv+XKJxgbhBzJzCfyFvoIF+BvYdDo6XIDQ=
github.com/openfaas/faas-provider v0.19.0 h1:1dv4HDkWa9/yVkUll23/06y9lf8+tISOxYoHwBXZaJI=
github.com/openfaas/faas-provider v0.19.0/go.mod h1:Farrp+9Med8LeK3aoYpqplMP8f5ebTILbCSLg2LPLZk=
github.com/openfaas/faas/gateway v0.0.0-20220509091830-4e868f5f9d81 h1:vWFZEznP2EbynX0uMygpFLAmKwv2uUAdCABnjARr7Wo=
github.com/openfaas/faas/gateway v0.0.0-20220509091830-4e868f5f9d81/go.mod h1:EFFnEVTvUdC9Bulh6rcKIq6e+XwDCG106gVzLKcj/+M=
github.com/openfaas/nats-queue-worker v0.0.0-20210726161954-ada9a31504c9/go.mod h1:ajlN2z+D8JPBq3kWNv4WLT6mtKPqlgeE3dYEx39d1tk=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/openfaas/faas-provider v0.19.1 h1:xH8lTWabfDZwzIvC0u1AO48ghD3BNw6Vo231DLqTeI0=
github.com/openfaas/faas-provider v0.19.1/go.mod h1:Farrp+9Med8LeK3aoYpqplMP8f5ebTILbCSLg2LPLZk=
github.com/openfaas/faas/gateway v0.0.0-20220811112234-2cdc7f308316 h1:0zf2txKmAIfUKSdiR7FrmLHxzk+a4XI+tG5AVyThfMA=
github.com/openfaas/faas/gateway v0.0.0-20220811112234-2cdc7f308316/go.mod h1:czLBBaq5pOcVR6Zwm7rXu57iBe9IxDpBVj37eW8Nw48=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@ -671,13 +635,11 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
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/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
@ -689,7 +651,6 @@ github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
@ -700,7 +661,6 @@ github.com/prometheus/common v0.35.0 h1:Eyr+Pw2VymWejHqCugNaQXkAi6KayVNxaHeu6khm
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@ -745,8 +705,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@ -776,7 +736,6 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG
github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
@ -786,13 +745,13 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5 h1:+UB2BJA852UkGH42H+Oee69djmxS3ANzl2b/JtT1YiA=
github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netlink v1.2.1-beta.2 h1:Llsql0lnQEbHj0I1OuKyp8otXp0r3q0mPkuhwHfStVs=
github.com/vishvananda/netlink v1.2.1-beta.2/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f h1:p4VB7kIXpOQvVn1ZaTIVp+3vuYAXFe3OJEvjbUYJLaA=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@ -829,8 +788,6 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/goleak v1.1.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
@ -844,15 +801,10 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -889,7 +841,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -951,16 +902,15 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -982,7 +932,6 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1008,7 +957,6 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200620081246-981b61492c35/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1031,7 +979,6 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1040,8 +987,8 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220702020025-31831981b65f h1:xdsejrW/0Wf2diT5CPp3XmKUNbr7Xvw8kYilQ+6qjRY=
golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1070,7 +1017,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@ -1083,7 +1029,6 @@ golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDq
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -1272,8 +1217,8 @@ k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
k8s.io/apimachinery v0.24.0 h1:ydFCyC/DjCvFCHK5OPMKBlxayQytB8pxy8YQInd5UyQ=
k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
k8s.io/apimachinery v0.24.3 h1:hrFiNSA2cBZqllakVYyH/VyEh4B581bQRmqATJSeQTg=
k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=

View File

@ -29,7 +29,7 @@ git clone https://github.com/containerd/containerd
cd containerd
git fetch origin --tags
git checkout v1.6.4
git checkout v1.6.8
make
sudo make install

View File

@ -29,7 +29,7 @@ git clone https://github.com/containerd/containerd
cd containerd
git fetch origin --tags
git checkout v1.6.4
git checkout v1.6.8
make
sudo make install

View File

@ -30,7 +30,7 @@ git clone https://github.com/containerd/containerd
cd containerd
git fetch origin --tags
git checkout v1.6.4
git checkout v1.6.8
make
sudo make install

View File

@ -84,9 +84,20 @@ install_cni_plugins() {
}
install_containerd() {
CONTAINERD_VER=v1.6.4
CONTAINERD_VER=v1.6.8
$SUDO systemctl unmask containerd || :
$SUDO $ARKADE system install containerd --systemd --version ${CONTAINERD_VER} --progress=false
arch=$(uname -m)
if [ $arch == "armv7l" ]; then
$SUDO curl -fSLs "https://github.com/alexellis/containerd-arm/releases/download/v${CONTAINERD_VER}/containerd-${CONTAINERD_VER}-linux-armhf.tar.gz" --output "/tmp/containerd.tar.gz"
$SUDO tar -xvf /tmp/containerd.tar.gz -C /usr/local/bin/
$SUDO curl -fSLs https://raw.githubusercontent.com/containerd/containerd/v${CONTAINERD_VER}/containerd.service --output "/etc/systemd/system/containerd.service"
$SUDO systemctl enable containerd
$SUDO systemctl start containerd
else
$SUDO $ARKADE system install containerd --systemd --version v${CONTAINERD_VER} --progress=false
fi
sleep 5
}

View File

@ -11,7 +11,7 @@ import (
"strconv"
"strings"
"github.com/alexellis/k3sup/pkg/env"
"github.com/alexellis/arkade/pkg/env"
"github.com/compose-spec/compose-go/loader"
compose "github.com/compose-spec/compose-go/types"
"github.com/containerd/containerd"

View File

@ -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.

View File

@ -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 {

View 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.Enqueue(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
}

View File

@ -0,0 +1,538 @@
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
// `IOTracking` enables tracking I/O statistics on the job object. More specifically this
// calls SetInformationJobObject with the JobObjectIoAttribution class.
EnableIOTracking 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
}
if options.EnableIOTracking {
if err := enableIOTracking(jobHandle); err != nil {
return nil, err
}
}
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.Dequeue()
}
// 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,
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,
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,
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,
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. This call will error
// if either `EnableIOTracking` wasn't set to true on creation of the job, or SetIOTracking()
// hasn't been called since creation of the job.
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,
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,
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
}
// SetIOTracking enables IO tracking for processes in the job object.
// This enables use of the QueryStorageStats method.
func (job *JobObject) SetIOTracking() error {
job.handleLock.RLock()
defer job.handleLock.RUnlock()
if job.handle == 0 {
return ErrAlreadyClosed
}
return enableIOTracking(job.handle)
}
func enableIOTracking(job windows.Handle) error {
info := winapi.JOBOBJECT_IO_ATTRIBUTION_INFORMATION{
ControlFlags: winapi.JOBOBJECT_IO_ATTRIBUTION_CONTROL_ENABLE,
}
if _, err := windows.SetInformationJobObject(
job,
winapi.JobObjectIoAttribution,
uintptr(unsafe.Pointer(&info)),
uint32(unsafe.Sizeof(info)),
); err != nil {
return fmt.Errorf("failed to enable IO tracking on job object: %w", err)
}
return nil
}

View 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,
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,
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
}

View File

@ -0,0 +1,92 @@
package queue
import (
"errors"
"sync"
)
var ErrQueueClosed = errors.New("the queue is closed for reading and writing")
// 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{}{},
}
}
// Enqueue writes `msg` to the queue.
func (mq *MessageQueue) Enqueue(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
}
// Dequeue will read a value from the queue and remove it. If the queue
// is empty, this will block until the queue is closed or a value gets enqueued.
func (mq *MessageQueue) Dequeue() (interface{}, error) {
mq.m.Lock()
defer mq.m.Unlock()
for !mq.closed && mq.size() == 0 {
mq.c.Wait()
}
// We got woken up, check if it's because the queue got closed.
if mq.closed {
return nil, ErrQueueClosed
}
val := mq.messages[0]
mq.messages[0] = nil
mq.messages = mq.messages[1:]
return val, nil
}
// Size returns the size of the queue.
func (mq *MessageQueue) Size() int {
mq.m.RLock()
defer mq.m.RUnlock()
return mq.size()
}
// Nonexported size check to check if the queue is empty inside already locked functions.
func (mq *MessageQueue) size() int {
return len(mq.messages)
}
// 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, noop
if mq.closed {
return
}
mq.messages = nil
mq.closed = true
// If there's anybody currently waiting on a value from Dequeue, we need to
// broadcast so the read(s) can return ErrQueueClosed.
mq.c.Broadcast()
}

View File

@ -1,3 +0,0 @@
package winapi
//sys GetQueuedCompletionStatus(cphandle windows.Handle, qty *uint32, key *uintptr, overlapped **windows.Overlapped, timeout uint32) (err error)

View File

@ -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,
@ -172,7 +175,7 @@ type JOBOBJECT_ASSOCIATE_COMPLETION_PORT struct {
// LPDWORD lpReturnLength
// );
//
//sys QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo uintptr, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) = kernel32.QueryInformationJobObject
//sys QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo unsafe.Pointer, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) = kernel32.QueryInformationJobObject
// HANDLE OpenJobObjectW(
// DWORD dwDesiredAccess,

View File

@ -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 unsafe.Pointer, 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
}

View File

@ -12,7 +12,8 @@ const STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
// ULONG SystemInformationLength,
// PULONG ReturnLength
// );
//sys NtQuerySystemInformation(systemInfoClass int, systemInformation uintptr, systemInfoLength uint32, returnLength *uint32) (status uint32) = ntdll.NtQuerySystemInformation
//
//sys NtQuerySystemInformation(systemInfoClass int, systemInformation unsafe.Pointer, systemInfoLength uint32, returnLength *uint32) (status uint32) = ntdll.NtQuerySystemInformation
type SYSTEM_PROCESS_INFORMATION struct {
NextEntryOffset uint32 // ULONG

View File

@ -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

View File

@ -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")
@ -100,7 +100,7 @@ func resizePseudoConsole(hPc windows.Handle, size uint32) (hr error) {
return
}
func NtQuerySystemInformation(systemInfoClass int, systemInformation uintptr, systemInfoLength uint32, returnLength *uint32) (status uint32) {
func NtQuerySystemInformation(systemInfoClass int, systemInformation unsafe.Pointer, systemInfoLength uint32, returnLength *uint32) (status uint32) {
r0, _, _ := syscall.Syscall6(procNtQuerySystemInformation.Addr(), 4, uintptr(systemInfoClass), uintptr(systemInformation), uintptr(systemInfoLength), uintptr(unsafe.Pointer(returnLength)), 0, 0)
status = uint32(r0)
return
@ -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 {
@ -164,7 +152,7 @@ func IsProcessInJob(procHandle windows.Handle, jobHandle windows.Handle, result
return
}
func QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo uintptr, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) {
func QueryInformationJobObject(jobHandle windows.Handle, infoClass uint32, jobObjectInfo unsafe.Pointer, jobObjectInformationLength uint32, lpReturnLength *uint32) (err error) {
r1, _, e1 := syscall.Syscall6(procQueryInformationJobObject.Addr(), 5, uintptr(jobHandle), uintptr(infoClass), uintptr(jobObjectInfo), uintptr(jobObjectInformationLength), uintptr(unsafe.Pointer(lpReturnLength)), 0)
if r1 == 0 {
if e1 != 0 {
@ -256,6 +244,12 @@ func LocalFree(ptr uintptr) {
return
}
func NtQueryInformationProcess(processHandle windows.Handle, processInfoClass uint32, processInfo unsafe.Pointer, 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)

View File

@ -1,9 +1,6 @@
MIT License
Copyright (c) 2019-2020 Alex Ellis
Copyright (c) 2020 k3sup author(s)
Exclusions: assets, images and logos.
Copyright (c) 2019 Alex Ellis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

44
vendor/github.com/alexellis/arkade/pkg/env/env.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
// Copyright (c) arkade author(s) 2022. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
package env
import (
"log"
"os"
"path"
"strings"
execute "github.com/alexellis/go-execute/pkg/v1"
)
// GetClientArch returns a pair of arch and os
func GetClientArch() (arch string, os string) {
task := execute.ExecTask{Command: "uname", Args: []string{"-m"}, StreamStdio: false}
res, err := task.Execute()
if err != nil {
log.Println(err)
}
archResult := strings.TrimSpace(res.Stdout)
taskOS := execute.ExecTask{Command: "uname", Args: []string{"-s"}, StreamStdio: false}
resOS, errOS := taskOS.Execute()
if errOS != nil {
log.Println(errOS)
}
osResult := strings.TrimSpace(resOS.Stdout)
return archResult, osResult
}
func LocalBinary(name, subdir string) string {
home := os.Getenv("HOME")
val := path.Join(home, ".arkade/bin/")
if len(subdir) > 0 {
val = path.Join(val, subdir)
}
return path.Join(val, name)
}

View File

@ -1,51 +0,0 @@
package env
import (
"log"
"os"
"path"
"strings"
execute "github.com/alexellis/go-execute/pkg/v1"
)
// GetClientArch returns a pair of arch and os
func GetClientArch() (string, string) {
task := execute.ExecTask{
Command: "uname",
Args: []string{"-m"},
StreamStdio: false,
}
res, err := task.Execute()
if err != nil {
log.Println(err)
}
arch := strings.TrimSpace(res.Stdout)
taskOS := execute.ExecTask{
Command: "uname",
Args: []string{"-s"},
StreamStdio: false,
}
resOS, errOS := taskOS.Execute()
if errOS != nil {
log.Println(errOS)
}
os := strings.TrimSpace(resOS.Stdout)
return arch, os
}
func LocalBinary(name, subdir string) string {
home := os.Getenv("HOME")
val := path.Join(home, ".k3sup/bin/")
if len(subdir) > 0 {
val = path.Join(val, subdir)
}
return path.Join(val, name)
}

View File

@ -91,7 +91,7 @@ EOF
config.vm.provision "install-golang", type: "shell", run: "once" do |sh|
sh.upload_path = "/tmp/vagrant-install-golang"
sh.env = {
'GO_VERSION': ENV['GO_VERSION'] || "1.17.9",
'GO_VERSION': ENV['GO_VERSION'] || "1.17.11",
}
sh.inline = <<~SHELL
#!/usr/bin/env bash
@ -101,6 +101,7 @@ EOF
GOPATH=\\$HOME/go
PATH=\\$GOPATH/bin:\\$PATH
export GOPATH PATH
git config --global --add safe.directory /vagrant
EOF
source /etc/profile.d/sh.local
SHELL
@ -264,7 +265,7 @@ EOF
fi
trap cleanup EXIT
ctr version
critest --parallel=$(nproc) --report-dir="${REPORT_DIR}" --ginkgo.skip='HostIpc is true'
critest --parallel=$[$(nproc)+2] --ginkgo.skip='HostIpc is true' --report-dir="${REPORT_DIR}"
SHELL
end

View File

@ -31,6 +31,7 @@ import (
"time"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/pkg/userns"
"github.com/containerd/continuity/fs"
)
@ -380,6 +381,10 @@ func createTarFile(ctx context.Context, path, extractDir string, hdr *tar.Header
// Lchown is not supported on Windows.
if runtime.GOOS != "windows" {
if err := os.Lchown(path, hdr.Uid, hdr.Gid); err != nil {
err = fmt.Errorf("failed to Lchown %q for UID %d, GID %d: %w", path, hdr.Uid, hdr.Gid, err)
if errors.Is(err, syscall.EINVAL) && userns.RunningInUserNS() {
err = fmt.Errorf("%w (Hint: try increasing the number of subordinate IDs in /etc/subuid and /etc/subgid)", err)
}
return err
}
}

View File

@ -23,7 +23,7 @@ var (
Package = "github.com/containerd/containerd"
// Version holds the complete version number. Filled in at linking time.
Version = "1.6.4+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.

View File

@ -31,12 +31,10 @@ help: ## this help
test: ## run tests, except integration tests and tests that require root
$(Q)go test -v -race $(EXTRA_TESTFLAGS) -count=1 ./...
integration: ## run integration test
integration: bin/integration.test ## run integration test
$(Q)bin/integration.test -test.v -test.count=1 -test.root $(EXTRA_TESTFLAGS) -test.parallel $(TESTFLAGS_PARALLEL)
FORCE:
bin/integration.test: FORCE ## build integration test binary into bin
bin/integration.test: ## build integration test binary into bin
$(Q)cd ./integration && go test -race -c . -o ../bin/integration.test
clean: ## clean up binaries

View File

@ -33,6 +33,8 @@ import (
type CNI interface {
// Setup setup the network for the namespace
Setup(ctx context.Context, id string, path string, opts ...NamespaceOpts) (*Result, error)
// SetupSerially sets up each of the network interfaces for the namespace in serial
SetupSerially(ctx context.Context, id string, path string, opts ...NamespaceOpts) (*Result, error)
// Remove tears down the network of the namespace.
Remove(ctx context.Context, id string, path string, opts ...NamespaceOpts) error
// Check checks if the network is still in desired state
@ -165,6 +167,34 @@ func (c *libcni) Setup(ctx context.Context, id string, path string, opts ...Name
return c.createResult(result)
}
// SetupSerially setups the network in the namespace and returns a Result
func (c *libcni) SetupSerially(ctx context.Context, id string, path string, opts ...NamespaceOpts) (*Result, error) {
if err := c.Status(); err != nil {
return nil, err
}
ns, err := newNamespace(id, path, opts...)
if err != nil {
return nil, err
}
result, err := c.attachNetworksSerially(ctx, ns)
if err != nil {
return nil, err
}
return c.createResult(result)
}
func (c *libcni) attachNetworksSerially(ctx context.Context, ns *Namespace) ([]*types100.Result, error) {
var results []*types100.Result
for _, network := range c.Networks() {
r, err := network.Attach(ctx, ns)
if err != nil {
return nil, err
}
results = append(results, r)
}
return results, nil
}
type asynchAttachResult struct {
index int
res *types100.Result

View File

@ -16,6 +16,7 @@ package invoke
import (
"context"
"encoding/json"
"fmt"
"os"
@ -33,6 +34,43 @@ type Exec interface {
Decode(jsonBytes []byte) (version.PluginInfo, error)
}
// Plugin must return result in same version as specified in netconf; but
// for backwards compatibility reasons if the result version is empty use
// config version (rather than technically correct 0.1.0).
// https://github.com/containernetworking/cni/issues/895
func fixupResultVersion(netconf, result []byte) (string, []byte, error) {
versionDecoder := &version.ConfigDecoder{}
confVersion, err := versionDecoder.Decode(netconf)
if err != nil {
return "", nil, err
}
var rawResult map[string]interface{}
if err := json.Unmarshal(result, &rawResult); err != nil {
return "", nil, fmt.Errorf("failed to unmarshal raw result: %w", err)
}
// Manually decode Result version; we need to know whether its cniVersion
// is empty, while built-in decoders (correctly) substitute 0.1.0 for an
// empty version per the CNI spec.
if resultVerRaw, ok := rawResult["cniVersion"]; ok {
resultVer, ok := resultVerRaw.(string)
if ok && resultVer != "" {
return resultVer, result, nil
}
}
// If the cniVersion is not present or empty, assume the result is
// the same CNI spec version as the config
rawResult["cniVersion"] = confVersion
newBytes, err := json.Marshal(rawResult)
if err != nil {
return "", nil, fmt.Errorf("failed to remarshal fixed result: %w", err)
}
return confVersion, newBytes, nil
}
// For example, a testcase could pass an instance of the following fakeExec
// object to ExecPluginWithResult() to verify the incoming stdin and environment
// and provide a tailored response:
@ -84,7 +122,12 @@ func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte
return nil, err
}
return create.CreateFromBytes(stdoutBytes)
resultVersion, fixedBytes, err := fixupResultVersion(netconf, stdoutBytes)
if err != nil {
return nil, err
}
return create.Create(resultVersion, fixedBytes)
}
func ExecPluginWithoutResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) error {

View File

@ -12,14 +12,14 @@ func NewHttpWriteInterceptor(w http.ResponseWriter) *HttpWriteInterceptor {
type HttpWriteInterceptor struct {
http.ResponseWriter
StatusCode int
statusCode int
}
func (c *HttpWriteInterceptor) Status() int {
if c.StatusCode == 0 {
if c.statusCode == 0 {
return http.StatusOK
}
return c.StatusCode
return c.statusCode
}
func (c *HttpWriteInterceptor) Header() http.Header {
@ -27,11 +27,14 @@ func (c *HttpWriteInterceptor) Header() http.Header {
}
func (c *HttpWriteInterceptor) Write(data []byte) (int, error) {
if c.statusCode == 0 {
c.WriteHeader(http.StatusOK)
}
return c.ResponseWriter.Write(data)
}
func (c *HttpWriteInterceptor) WriteHeader(code int) {
c.StatusCode = code
c.statusCode = code
c.ResponseWriter.WriteHeader(code)
}

View File

@ -53,7 +53,7 @@ func (hm *httpMetrics) InstrumentHandler(next http.Handler, pathOverride string)
defer func() {
hm.RequestsTotal.With(
prometheus.Labels{"code": strconv.Itoa(ww.StatusCode),
prometheus.Labels{"code": strconv.Itoa(ww.Status()),
"method": r.Method,
"path": path,
}).
@ -62,7 +62,7 @@ func (hm *httpMetrics) InstrumentHandler(next http.Handler, pathOverride string)
defer func() {
hm.RequestDurationHistogram.With(
prometheus.Labels{"code": strconv.Itoa(ww.StatusCode),
prometheus.Labels{"code": strconv.Itoa(ww.Status()),
"method": r.Method,
"path": path,
}).

View File

@ -1,51 +0,0 @@
# Cobra Changelog
## v1.1.3
* **Fix:** release-branch.cobra1.1 only: Revert "Deprecate Go < 1.14" to maintain backward compatibility
## v1.1.2
### Notable Changes
* Bump license year to 2021 in golden files (#1309) @Bowbaq
* Enhance PowerShell completion with custom comp (#1208) @Luap99
* Update gopkg.in/yaml.v2 to v2.4.0: The previous breaking change in yaml.v2 v2.3.0 has been reverted, see go-yaml/yaml#670
* Documentation readability improvements (#1228 etc.) @zaataylor etc.
* Use golangci-lint: Repair warnings and errors resulting from linting (#1044) @umarcor
## v1.1.1
* **Fix:** yaml.v2 2.3.0 contained a unintended breaking change. This release reverts to yaml.v2 v2.2.8 which has recent critical CVE fixes, but does not have the breaking changes. See https://github.com/spf13/cobra/pull/1259 for context.
* **Fix:** correct internal formatting for go-md2man v2 (which caused man page generation to be broken). See https://github.com/spf13/cobra/issues/1049 for context.
## v1.1.0
### Notable Changes
* Extend Go completions and revamp zsh comp (#1070)
* Fix man page doc generation - no auto generated tag when `cmd.DisableAutoGenTag = true` (#1104) @jpmcb
* Add completion for help command (#1136)
* Complete subcommands when TraverseChildren is set (#1171)
* Fix stderr printing functions (#894)
* fix: fish output redirection (#1247)
## v1.0.0
Announcing v1.0.0 of Cobra. 🎉
### Notable Changes
* Fish completion (including support for Go custom completion) @marckhouzam
* API (urgent): Rename BashCompDirectives to ShellCompDirectives @marckhouzam
* Remove/replace SetOutput on Command - deprecated @jpmcb
* add support for autolabel stale PR @xchapter7x
* Add Labeler Actions @xchapter7x
* Custom completions coded in Go (instead of Bash) @marckhouzam
* Partial Revert of #922 @jharshman
* Add Makefile to project @jharshman
* Correct documentation for InOrStdin @desponda
* Apply formatting to templates @jharshman
* Revert change so help is printed on stdout again @marckhouzam
* Update md2man to v2.0.0 @pdf
* update viper to v1.4.0 @umarcor
* Update cmd/root.go example in README.md @jharshman

View File

@ -2,7 +2,7 @@
Cobra is a library for creating powerful modern CLI applications.
Cobra is used in many Go projects such as [Kubernetes](http://kubernetes.io/),
Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/),
[Hugo](https://gohugo.io), and [Github CLI](https://github.com/cli/cli) to
name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra.
@ -28,7 +28,7 @@ Cobra provides:
* Automatically generated man pages for your application
* Command aliases so you can change things without breaking them
* The flexibility to define your own help, usage, etc.
* Optional seamless integration with [viper](http://github.com/spf13/viper) for 12-factor apps
* Optional seamless integration with [viper](https://github.com/spf13/viper) for 12-factor apps
# Concepts
@ -102,7 +102,7 @@ It can be installed by running:
go install github.com/spf13/cobra-cli@latest
```
For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/master/README.md)
For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md)
For complete details on using the Cobra library, please read the [The Cobra User Guide](user_guide.md).

49
vendor/github.com/spf13/cobra/active_help.go generated vendored Normal file
View File

@ -0,0 +1,49 @@
package cobra
import (
"fmt"
"os"
"strings"
)
const (
activeHelpMarker = "_activeHelp_ "
// The below values should not be changed: programs will be using them explicitly
// in their user documentation, and users will be using them explicitly.
activeHelpEnvVarSuffix = "_ACTIVE_HELP"
activeHelpGlobalEnvVar = "COBRA_ACTIVE_HELP"
activeHelpGlobalDisable = "0"
)
// AppendActiveHelp adds the specified string to the specified array to be used as ActiveHelp.
// Such strings will be processed by the completion script and will be shown as ActiveHelp
// to the user.
// The array parameter should be the array that will contain the completions.
// This function can be called multiple times before and/or after completions are added to
// the array. Each time this function is called with the same array, the new
// ActiveHelp line will be shown below the previous ones when completion is triggered.
func AppendActiveHelp(compArray []string, activeHelpStr string) []string {
return append(compArray, fmt.Sprintf("%s%s", activeHelpMarker, activeHelpStr))
}
// GetActiveHelpConfig returns the value of the ActiveHelp environment variable
// <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of the root command in upper
// case, with all - replaced by _.
// It will always return "0" if the global environment variable COBRA_ACTIVE_HELP
// is set to "0".
func GetActiveHelpConfig(cmd *Command) string {
activeHelpCfg := os.Getenv(activeHelpGlobalEnvVar)
if activeHelpCfg != activeHelpGlobalDisable {
activeHelpCfg = os.Getenv(activeHelpEnvVar(cmd.Root().Name()))
}
return activeHelpCfg
}
// activeHelpEnvVar returns the name of the program-specific ActiveHelp environment
// variable. It has the format <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of the
// root command in upper case, with all - replaced by _.
func activeHelpEnvVar(name string) string {
// This format should not be changed: users will be using it explicitly.
activeHelpEnvVar := strings.ToUpper(fmt.Sprintf("%s%s", name, activeHelpEnvVarSuffix))
return strings.ReplaceAll(activeHelpEnvVar, "-", "_")
}

157
vendor/github.com/spf13/cobra/active_help.md generated vendored Normal file
View File

@ -0,0 +1,157 @@
# Active Help
Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion.
For example,
```
bash-5.1$ helm repo add [tab]
You must choose a name for the repo you are adding.
bash-5.1$ bin/helm package [tab]
Please specify the path to the chart to package
bash-5.1$ bin/helm package [tab][tab]
bin/ internal/ scripts/ pkg/ testdata/
```
**Hint**: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program.
## Supported shells
Active Help is currently only supported for the following shells:
- Bash (using [bash completion V2](shell_completions.md#bash-completion-v2) only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed.
- Zsh
## Adding Active Help messages
As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to [Shell Completions](shell_completions.md).
Adding Active Help is done through the use of the `cobra.AppendActiveHelp(...)` function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details.
### Active Help for nouns
Adding Active Help when completing a noun is done within the `ValidArgsFunction(...)` of a command. Please notice the use of `cobra.AppendActiveHelp(...)` in the following example:
```go
cmd := &cobra.Command{
Use: "add [NAME] [URL]",
Short: "add a chart repository",
Args: require.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
return addRepo(args)
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
} else if len(args) == 1 {
comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
} else {
comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
}
```
The example above defines the completions (none, in this specific example) as well as the Active Help messages for the `helm repo add` command. It yields the following behavior:
```
bash-5.1$ helm repo add [tab]
You must choose a name for the repo you are adding
bash-5.1$ helm repo add grafana [tab]
You must specify the URL for the repo you are adding
bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab]
This command does not take any more arguments
```
**Hint**: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions.
### Active Help for flags
Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example:
```go
_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 2 {
return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp
}
return compVersionFlag(args[1], toComplete)
})
```
The example above prints an Active Help message when not enough information was given by the user to complete the `--version` flag.
```
bash-5.1$ bin/helm install myrelease --version 2.0.[tab]
You must first specify the chart to install before the --version flag can be completed
bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab]
2.0.1 2.0.2 2.0.3
```
## User control of Active Help
You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any.
Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration.
The way to configure Active Help is to use the program's Active Help environment
variable. That variable is named `<PROGRAM>_ACTIVE_HELP` where `<PROGRAM>` is the name of your
program in uppercase with any `-` replaced by an `_`. The variable should be set by the user to whatever
Active Help configuration values are supported by the program.
For example, say `helm` has chosen to support three levels for Active Help: `on`, `off`, `local`. Then a user
would set the desired behavior to `local` by doing `export HELM_ACTIVE_HELP=local` in their shell.
For simplicity, when in `cmd.ValidArgsFunction(...)` or a flag's completion function, the program should read the
Active Help configuration using the `cobra.GetActiveHelpConfig(cmd)` function and select what Active Help messages
should or should not be added (instead of reading the environment variable directly).
For example:
```go
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
activeHelpLevel := cobra.GetActiveHelpConfig(cmd)
var comps []string
if len(args) == 0 {
if activeHelpLevel != "off" {
comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
}
} else if len(args) == 1 {
if activeHelpLevel != "off" {
comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
}
} else {
if activeHelpLevel == "local" {
comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
}
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
```
**Note 1**: If the `<PROGRAM>_ACTIVE_HELP` environment variable is set to the string "0", Cobra will automatically disable all Active Help output (even if some output was specified by the program using the `cobra.AppendActiveHelp(...)` function). Using "0" can simplify your code in situations where you want to blindly disable Active Help without having to call `cobra.GetActiveHelpConfig(cmd)` explicitly.
**Note 2**: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable `COBRA_ACTIVE_HELP` to "0". In this case `cobra.GetActiveHelpConfig(cmd)` will return "0" no matter what the variable `<PROGRAM>_ACTIVE_HELP` is set to.
**Note 3**: If the user does not set `<PROGRAM>_ACTIVE_HELP` or `COBRA_ACTIVE_HELP` (which will be a common case), the default value for the Active Help configuration returned by `cobra.GetActiveHelpConfig(cmd)` will be the empty string.
## Active Help with Cobra's default completion command
Cobra provides a default `completion` command for programs that wish to use it.
When using the default `completion` command, Active Help is configurable in the same
fashion as described above using environment variables. You may wish to document this in more
details for your users.
## Debugging Active Help
Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra's hidden `__complete` command. Please refer to [debugging shell completion](shell_completions.md#debugging) for details.
When debugging with the `__complete` command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named `<PROGRAM>_ACTIVE_HELP` where any `-` is replaced by an `_`. For example, we can test deactivating some Active Help as shown below:
```
$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h<ENTER>
bitnami/haproxy
bitnami/harbor
_activeHelp_ WARNING: cannot re-use a name that is still in use
:0
Completion ended with directive: ShellCompDirectiveDefault
$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h<ENTER>
bitnami/haproxy
bitnami/harbor
:0
Completion ended with directive: ShellCompDirectiveDefault
```

View File

@ -73,7 +73,8 @@ __%[1]s_handle_go_custom_completion()
# Prepare the command to request completions for the program.
# Calling ${words[0]} instead of directly %[1]s allows to handle aliases
args=("${words[@]:1}")
requestComp="${words[0]} %[2]s ${args[*]}"
# Disable ActiveHelp which is not supported for bash completion v1
requestComp="%[8]s=0 ${words[0]} %[2]s ${args[*]}"
lastParam=${words[$((${#words[@]}-1))]}
lastChar=${lastParam:$((${#lastParam}-1)):1}
@ -99,7 +100,7 @@ __%[1]s_handle_go_custom_completion()
directive=0
fi
__%[1]s_debug "${FUNCNAME[0]}: the completion directive is: ${directive}"
__%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out[*]}"
__%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out}"
if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then
# Error code. No completion.
@ -125,7 +126,7 @@ __%[1]s_handle_go_custom_completion()
local fullFilter filter filteringCmd
# Do not use quotes around the $out variable or else newline
# characters will be kept.
for filter in ${out[*]}; do
for filter in ${out}; do
fullFilter+="$filter|"
done
@ -136,7 +137,7 @@ __%[1]s_handle_go_custom_completion()
# File completion for directories only
local subdir
# Use printf to strip any trailing newline
subdir=$(printf "%%s" "${out[0]}")
subdir=$(printf "%%s" "${out}")
if [ -n "$subdir" ]; then
__%[1]s_debug "Listing directories in $subdir"
__%[1]s_handle_subdirs_in_dir_flag "$subdir"
@ -147,7 +148,7 @@ __%[1]s_handle_go_custom_completion()
else
while IFS='' read -r comp; do
COMPREPLY+=("$comp")
done < <(compgen -W "${out[*]}" -- "$cur")
done < <(compgen -W "${out}" -- "$cur")
fi
}
@ -383,11 +384,11 @@ __%[1]s_handle_word()
`, name, ShellCompNoDescRequestCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name)))
}
func writePostscript(buf io.StringWriter, name string) {
name = strings.Replace(name, ":", "__", -1)
name = strings.ReplaceAll(name, ":", "__")
WriteStringAndCheck(buf, fmt.Sprintf("__start_%s()\n", name))
WriteStringAndCheck(buf, fmt.Sprintf(`{
local cur prev words cword split
@ -645,8 +646,8 @@ func gen(buf io.StringWriter, cmd *Command) {
gen(buf, c)
}
commandName := cmd.CommandPath()
commandName = strings.Replace(commandName, " ", "_", -1)
commandName = strings.Replace(commandName, ":", "__", -1)
commandName = strings.ReplaceAll(commandName, " ", "_")
commandName = strings.ReplaceAll(commandName, ":", "__")
if cmd.Root() == cmd {
WriteStringAndCheck(buf, fmt.Sprintf("_%s_root_command()\n{\n", commandName))

View File

@ -78,7 +78,7 @@ __%[1]s_get_completion_results() {
directive=0
fi
__%[1]s_debug "The completion directive is: ${directive}"
__%[1]s_debug "The completions are: ${out[*]}"
__%[1]s_debug "The completions are: ${out}"
}
__%[1]s_process_completion_results() {
@ -111,13 +111,18 @@ __%[1]s_process_completion_results() {
fi
fi
# Separate activeHelp from normal completions
local completions=()
local activeHelp=()
__%[1]s_extract_activeHelp
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
# File extension filtering
local fullFilter filter filteringCmd
# Do not use quotes around the $out variable or else newline
# Do not use quotes around the $completions variable or else newline
# characters will be kept.
for filter in ${out[*]}; do
for filter in ${completions[*]}; do
fullFilter+="$filter|"
done
@ -129,7 +134,7 @@ __%[1]s_process_completion_results() {
# Use printf to strip any trailing newline
local subdir
subdir=$(printf "%%s" "${out[0]}")
subdir=$(printf "%%s" "${completions[0]}")
if [ -n "$subdir" ]; then
__%[1]s_debug "Listing directories in $subdir"
pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
@ -143,6 +148,43 @@ __%[1]s_process_completion_results() {
__%[1]s_handle_special_char "$cur" :
__%[1]s_handle_special_char "$cur" =
# Print the activeHelp statements before we finish
if [ ${#activeHelp} -ne 0 ]; then
printf "\n";
printf "%%s\n" "${activeHelp[@]}"
printf "\n"
# The prompt format is only available from bash 4.4.
# We test if it is available before using it.
if (x=${PS1@P}) 2> /dev/null; then
printf "%%s" "${PS1@P}${COMP_LINE[@]}"
else
# Can't print the prompt. Just print the
# text the user had typed, it is workable enough.
printf "%%s" "${COMP_LINE[@]}"
fi
fi
}
# Separate activeHelp lines from real completions.
# Fills the $activeHelp and $completions arrays.
__%[1]s_extract_activeHelp() {
local activeHelpMarker="%[8]s"
local endIndex=${#activeHelpMarker}
while IFS='' read -r comp; do
if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then
comp=${comp:endIndex}
__%[1]s_debug "ActiveHelp found: $comp"
if [ -n "$comp" ]; then
activeHelp+=("$comp")
fi
else
# Not an activeHelp line but a normal completion
completions+=("$comp")
fi
done < <(printf "%%s\n" "${out}")
}
__%[1]s_handle_completion_types() {
@ -154,17 +196,16 @@ __%[1]s_handle_completion_types() {
# If the user requested inserting one completion at a time, or all
# completions at once on the command-line we must remove the descriptions.
# https://github.com/spf13/cobra/issues/1508
local tab comp
tab=$(printf '\t')
local tab=$'\t' comp
while IFS='' read -r comp; do
[[ -z $comp ]] && continue
# Strip any description
comp=${comp%%%%$tab*}
# Only consider the completions that match
comp=$(compgen -W "$comp" -- "$cur")
if [ -n "$comp" ]; then
if [[ $comp == "$cur"* ]]; then
COMPREPLY+=("$comp")
fi
done < <(printf "%%s\n" "${out[@]}")
done < <(printf "%%s\n" "${completions[@]}")
;;
*)
@ -175,44 +216,37 @@ __%[1]s_handle_completion_types() {
}
__%[1]s_handle_standard_completion_case() {
local tab comp
tab=$(printf '\t')
local tab=$'\t' comp
# Short circuit to optimize if we don't have descriptions
if [[ "${completions[*]}" != *$tab* ]]; then
IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
return 0
fi
local longest=0
local compline
# Look for the longest completion so that we can format things nicely
while IFS='' read -r comp; do
while IFS='' read -r compline; do
[[ -z $compline ]] && continue
# Strip any description before checking the length
comp=${comp%%%%$tab*}
comp=${compline%%%%$tab*}
# Only consider the completions that match
comp=$(compgen -W "$comp" -- "$cur")
[[ $comp == "$cur"* ]] || continue
COMPREPLY+=("$compline")
if ((${#comp}>longest)); then
longest=${#comp}
fi
done < <(printf "%%s\n" "${out[@]}")
local completions=()
while IFS='' read -r comp; do
if [ -z "$comp" ]; then
continue
fi
__%[1]s_debug "Original comp: $comp"
comp="$(__%[1]s_format_comp_descriptions "$comp" "$longest")"
__%[1]s_debug "Final comp: $comp"
completions+=("$comp")
done < <(printf "%%s\n" "${out[@]}")
while IFS='' read -r comp; do
COMPREPLY+=("$comp")
done < <(compgen -W "${completions[*]}" -- "$cur")
done < <(printf "%%s\n" "${completions[@]}")
# If there is a single completion left, remove the description text
if [ ${#COMPREPLY[*]} -eq 1 ]; then
__%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
comp="${COMPREPLY[0]%%%% *}"
comp="${COMPREPLY[0]%%%%$tab*}"
__%[1]s_debug "Removed description from single completion, which is now: ${comp}"
COMPREPLY=()
COMPREPLY+=("$comp")
COMPREPLY[0]=$comp
else # Format the descriptions
__%[1]s_format_comp_descriptions $longest
fi
}
@ -231,45 +265,48 @@ __%[1]s_handle_special_char()
__%[1]s_format_comp_descriptions()
{
local tab
tab=$(printf '\t')
local comp="$1"
local longest=$2
local tab=$'\t'
local comp desc maxdesclength
local longest=$1
# Properly format the description string which follows a tab character if there is one
if [[ "$comp" == *$tab* ]]; then
desc=${comp#*$tab}
comp=${comp%%%%$tab*}
local i ci
for ci in ${!COMPREPLY[*]}; do
comp=${COMPREPLY[ci]}
# Properly format the description string which follows a tab character if there is one
if [[ "$comp" == *$tab* ]]; then
__%[1]s_debug "Original comp: $comp"
desc=${comp#*$tab}
comp=${comp%%%%$tab*}
# $COLUMNS stores the current shell width.
# Remove an extra 4 because we add 2 spaces and 2 parentheses.
maxdesclength=$(( COLUMNS - longest - 4 ))
# $COLUMNS stores the current shell width.
# Remove an extra 4 because we add 2 spaces and 2 parentheses.
maxdesclength=$(( COLUMNS - longest - 4 ))
# Make sure we can fit a description of at least 8 characters
# if we are to align the descriptions.
if [[ $maxdesclength -gt 8 ]]; then
# Add the proper number of spaces to align the descriptions
for ((i = ${#comp} ; i < longest ; i++)); do
comp+=" "
done
else
# Don't pad the descriptions so we can fit more text after the completion
maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
fi
# If there is enough space for any description text,
# truncate the descriptions that are too long for the shell width
if [ $maxdesclength -gt 0 ]; then
if [ ${#desc} -gt $maxdesclength ]; then
desc=${desc:0:$(( maxdesclength - 1 ))}
desc+="…"
# Make sure we can fit a description of at least 8 characters
# if we are to align the descriptions.
if [[ $maxdesclength -gt 8 ]]; then
# Add the proper number of spaces to align the descriptions
for ((i = ${#comp} ; i < longest ; i++)); do
comp+=" "
done
else
# Don't pad the descriptions so we can fit more text after the completion
maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
fi
comp+=" ($desc)"
fi
fi
# Must use printf to escape all special characters
printf "%%q" "${comp}"
# If there is enough space for any description text,
# truncate the descriptions that are too long for the shell width
if [ $maxdesclength -gt 0 ]; then
if [ ${#desc} -gt $maxdesclength ]; then
desc=${desc:0:$(( maxdesclength - 1 ))}
desc+="…"
fi
comp+=" ($desc)"
fi
COMPREPLY[ci]=$comp
__%[1]s_debug "Final comp: $comp"
fi
done
}
__start_%[1]s()
@ -310,7 +347,8 @@ fi
# ex: ts=4 sw=4 et filetype=sh
`, name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs,
activeHelpMarker))
}
// GenBashCompletionFileV2 generates Bash completion version 2.

View File

@ -18,6 +18,7 @@ package cobra
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
@ -166,7 +167,7 @@ type Command struct {
// errWriter is a writer defined by the user that replaces stderr
errWriter io.Writer
//FParseErrWhitelist flag parse errors to be ignored
// FParseErrWhitelist flag parse errors to be ignored
FParseErrWhitelist FParseErrWhitelist
// CompletionOptions is a set of options to control the handling of shell completion
@ -224,12 +225,23 @@ type Command struct {
SuggestionsMinimumDistance int
}
// Context returns underlying command context. If command wasn't
// executed with ExecuteContext Context returns Background context.
// Context returns underlying command context. If command was executed
// with ExecuteContext or the context was set with SetContext, the
// previously set context will be returned. Otherwise, nil is returned.
//
// Notice that a call to Execute and ExecuteC will replace a nil context of
// a command with a context.Background, so a background context will be
// returned by Context after one of these functions has been called.
func (c *Command) Context() context.Context {
return c.ctx
}
// SetContext sets context for the command. It is set to context.Background by default and will be overwritten by
// Command.ExecuteContext or Command.ExecuteContextC
func (c *Command) SetContext(ctx context.Context) {
c.ctx = ctx
}
// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
// particularly useful when testing.
func (c *Command) SetArgs(a []string) {
@ -852,6 +864,10 @@ func (c *Command) execute(a []string) (err error) {
if err := c.validateRequiredFlags(); err != nil {
return err
}
if err := c.validateFlagGroups(); err != nil {
return err
}
if c.RunE != nil {
if err := c.RunE(c, argWoFlags); err != nil {
return err
@ -975,7 +991,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
if err != nil {
// Always show help if requested, even if SilenceErrors is in
// effect
if err == flag.ErrHelp {
if errors.Is(err, flag.ErrHelp) {
cmd.HelpFunc()(cmd, args)
return cmd, nil
}
@ -997,7 +1013,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
func (c *Command) ValidateArgs(args []string) error {
if c.Args == nil {
return nil
return ArbitraryArgs(c, args)
}
return c.Args(c, args)
}

View File

@ -103,6 +103,14 @@ func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string
return nil, ShellCompDirectiveNoFileComp
}
// FixedCompletions can be used to create a completion function which always
// returns the same results.
func FixedCompletions(choices []string, directive ShellCompDirective) func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
return func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
return choices, directive
}
}
// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.
func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error {
flag := c.Flag(flagName)
@ -170,6 +178,12 @@ func (c *Command) initCompleteCmd(args []string) {
noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd)
for _, comp := range completions {
if GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable {
// Remove all activeHelp entries in this case
if strings.HasPrefix(comp, activeHelpMarker) {
continue
}
}
if noDescriptions {
// Remove any description that may be included following a tab character.
comp = strings.Split(comp, "\t")[0]
@ -311,8 +325,11 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
var completions []string
var directive ShellCompDirective
// Enforce flag groups before doing flag completions
finalCmd.enforceFlagGroupsForCompletion()
// Note that we want to perform flagname completion even if finalCmd.DisableFlagParsing==true;
// doing this allows for completion of persistant flag names even for commands that disable flag parsing.
// doing this allows for completion of persistent flag names even for commands that disable flag parsing.
//
// When doing completion of a flag name, as soon as an argument starts with
// a '-' we know it is a flag. We cannot use isFlagArg() here as it requires
@ -644,7 +661,7 @@ To load completions for every new session, execute once:
#### macOS:
%[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
%[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
You will need to start a new shell for this setup to take effect.
`, c.Root().Name()),
@ -669,6 +686,10 @@ to enable it. You can execute the following once:
echo "autoload -U compinit; compinit" >> ~/.zshrc
To load completions in your current shell session:
source <(%[1]s completion zsh); compdef _%[1]s %[1]s
To load completions for every new session, execute once:
#### Linux:
@ -677,7 +698,7 @@ To load completions for every new session, execute once:
#### macOS:
%[1]s completion zsh > /usr/local/share/zsh/site-functions/_%[1]s
%[1]s completion zsh > $(brew --prefix)/share/zsh/site-functions/_%[1]s
You will need to start a new shell for this setup to take effect.
`, c.Root().Name()),

View File

@ -11,8 +11,8 @@ import (
func genFishComp(buf io.StringWriter, name string, includeDesc bool) {
// Variables should not contain a '-' or ':' character
nameForVar := name
nameForVar = strings.Replace(nameForVar, "-", "_", -1)
nameForVar = strings.Replace(nameForVar, ":", "_", -1)
nameForVar = strings.ReplaceAll(nameForVar, "-", "_")
nameForVar = strings.ReplaceAll(nameForVar, ":", "_")
compCmd := ShellCompRequestCmd
if !includeDesc {
@ -38,7 +38,8 @@ function __%[1]s_perform_completion
__%[1]s_debug "args: $args"
__%[1]s_debug "last arg: $lastArg"
set -l requestComp "$args[1] %[3]s $args[2..-1] $lastArg"
# Disable ActiveHelp which is not supported for fish shell
set -l requestComp "%[9]s=0 $args[1] %[3]s $args[2..-1] $lastArg"
__%[1]s_debug "Calling $requestComp"
set -l results (eval $requestComp 2> /dev/null)
@ -196,7 +197,7 @@ complete -c %[2]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results'
`, nameForVar, name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name)))
}
// GenFishCompletion generates fish completion file and writes to the passed writer.

223
vendor/github.com/spf13/cobra/flag_groups.go generated vendored Normal file
View File

@ -0,0 +1,223 @@
// Copyright © 2022 Steve Francia <spf@spf13.com>.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cobra
import (
"fmt"
"sort"
"strings"
flag "github.com/spf13/pflag"
)
const (
requiredAsGroup = "cobra_annotation_required_if_others_set"
mutuallyExclusive = "cobra_annotation_mutually_exclusive"
)
// MarkFlagsRequiredTogether marks the given flags with annotations so that Cobra errors
// if the command is invoked with a subset (but not all) of the given flags.
func (c *Command) MarkFlagsRequiredTogether(flagNames ...string) {
c.mergePersistentFlags()
for _, v := range flagNames {
f := c.Flags().Lookup(v)
if f == nil {
panic(fmt.Sprintf("Failed to find flag %q and mark it as being required in a flag group", v))
}
if err := c.Flags().SetAnnotation(v, requiredAsGroup, append(f.Annotations[requiredAsGroup], strings.Join(flagNames, " "))); err != nil {
// Only errs if the flag isn't found.
panic(err)
}
}
}
// MarkFlagsMutuallyExclusive marks the given flags with annotations so that Cobra errors
// if the command is invoked with more than one flag from the given set of flags.
func (c *Command) MarkFlagsMutuallyExclusive(flagNames ...string) {
c.mergePersistentFlags()
for _, v := range flagNames {
f := c.Flags().Lookup(v)
if f == nil {
panic(fmt.Sprintf("Failed to find flag %q and mark it as being in a mutually exclusive flag group", v))
}
// Each time this is called is a single new entry; this allows it to be a member of multiple groups if needed.
if err := c.Flags().SetAnnotation(v, mutuallyExclusive, append(f.Annotations[mutuallyExclusive], strings.Join(flagNames, " "))); err != nil {
panic(err)
}
}
}
// validateFlagGroups validates the mutuallyExclusive/requiredAsGroup logic and returns the
// first error encountered.
func (c *Command) validateFlagGroups() error {
if c.DisableFlagParsing {
return nil
}
flags := c.Flags()
// groupStatus format is the list of flags as a unique ID,
// then a map of each flag name and whether it is set or not.
groupStatus := map[string]map[string]bool{}
mutuallyExclusiveGroupStatus := map[string]map[string]bool{}
flags.VisitAll(func(pflag *flag.Flag) {
processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus)
processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus)
})
if err := validateRequiredFlagGroups(groupStatus); err != nil {
return err
}
if err := validateExclusiveFlagGroups(mutuallyExclusiveGroupStatus); err != nil {
return err
}
return nil
}
func hasAllFlags(fs *flag.FlagSet, flagnames ...string) bool {
for _, fname := range flagnames {
f := fs.Lookup(fname)
if f == nil {
return false
}
}
return true
}
func processFlagForGroupAnnotation(flags *flag.FlagSet, pflag *flag.Flag, annotation string, groupStatus map[string]map[string]bool) {
groupInfo, found := pflag.Annotations[annotation]
if found {
for _, group := range groupInfo {
if groupStatus[group] == nil {
flagnames := strings.Split(group, " ")
// Only consider this flag group at all if all the flags are defined.
if !hasAllFlags(flags, flagnames...) {
continue
}
groupStatus[group] = map[string]bool{}
for _, name := range flagnames {
groupStatus[group][name] = false
}
}
groupStatus[group][pflag.Name] = pflag.Changed
}
}
}
func validateRequiredFlagGroups(data map[string]map[string]bool) error {
keys := sortedKeys(data)
for _, flagList := range keys {
flagnameAndStatus := data[flagList]
unset := []string{}
for flagname, isSet := range flagnameAndStatus {
if !isSet {
unset = append(unset, flagname)
}
}
if len(unset) == len(flagnameAndStatus) || len(unset) == 0 {
continue
}
// Sort values, so they can be tested/scripted against consistently.
sort.Strings(unset)
return fmt.Errorf("if any flags in the group [%v] are set they must all be set; missing %v", flagList, unset)
}
return nil
}
func validateExclusiveFlagGroups(data map[string]map[string]bool) error {
keys := sortedKeys(data)
for _, flagList := range keys {
flagnameAndStatus := data[flagList]
var set []string
for flagname, isSet := range flagnameAndStatus {
if isSet {
set = append(set, flagname)
}
}
if len(set) == 0 || len(set) == 1 {
continue
}
// Sort values, so they can be tested/scripted against consistently.
sort.Strings(set)
return fmt.Errorf("if any flags in the group [%v] are set none of the others can be; %v were all set", flagList, set)
}
return nil
}
func sortedKeys(m map[string]map[string]bool) []string {
keys := make([]string, len(m))
i := 0
for k := range m {
keys[i] = k
i++
}
sort.Strings(keys)
return keys
}
// enforceFlagGroupsForCompletion will do the following:
// - when a flag in a group is present, other flags in the group will be marked required
// - when a flag in a mutually exclusive group is present, other flags in the group will be marked as hidden
// This allows the standard completion logic to behave appropriately for flag groups
func (c *Command) enforceFlagGroupsForCompletion() {
if c.DisableFlagParsing {
return
}
flags := c.Flags()
groupStatus := map[string]map[string]bool{}
mutuallyExclusiveGroupStatus := map[string]map[string]bool{}
c.Flags().VisitAll(func(pflag *flag.Flag) {
processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus)
processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus)
})
// If a flag that is part of a group is present, we make all the other flags
// of that group required so that the shell completion suggests them automatically
for flagList, flagnameAndStatus := range groupStatus {
for _, isSet := range flagnameAndStatus {
if isSet {
// One of the flags of the group is set, mark the other ones as required
for _, fName := range strings.Split(flagList, " ") {
_ = c.MarkFlagRequired(fName)
}
}
}
}
// If a flag that is mutually exclusive to others is present, we hide the other
// flags of that group so the shell completion does not suggest them
for flagList, flagnameAndStatus := range mutuallyExclusiveGroupStatus {
for flagName, isSet := range flagnameAndStatus {
if isSet {
// One of the flags of the mutually exclusive group is set, mark the other ones as hidden
// Don't mark the flag that is already set as hidden because it may be an
// array or slice flag and therefore must continue being suggested
for _, fName := range strings.Split(flagList, " ") {
if fName != flagName {
flag := c.Flags().Lookup(fName)
flag.Hidden = true
}
}
}
}
}
}

View File

@ -61,6 +61,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
# Prepare the command to request completions for the program.
# Split the command at the first space to separate the program and arguments.
$Program,$Arguments = $Command.Split(" ",2)
$RequestComp="$Program %[2]s $Arguments"
__%[1]s_debug "RequestComp: $RequestComp"
@ -90,11 +91,13 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
}
__%[1]s_debug "Calling $RequestComp"
# First disable ActiveHelp which is not supported for Powershell
$env:%[8]s=0
#call the command store the output in $out and redirect stderr and stdout to null
# $Out is an array contains each line per element
Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
# get directive from last line
[int]$Directive = $Out[-1].TrimStart(':')
if ($Directive -eq "") {
@ -242,7 +245,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
}
`, name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name)))
}
func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error {

View File

@ -1,8 +1,8 @@
## Projects using Cobra
- [Arduino CLI](https://github.com/arduino/arduino-cli)
- [Bleve](http://www.blevesearch.com/)
- [CockroachDB](http://www.cockroachlabs.com/)
- [Bleve](https://blevesearch.com/)
- [CockroachDB](https://www.cockroachlabs.com/)
- [Cosmos SDK](https://github.com/cosmos/cosmos-sdk)
- [Datree](https://github.com/datreeio/datree)
- [Delve](https://github.com/derekparker/delve)
@ -14,14 +14,15 @@
- [Github CLI](https://github.com/cli/cli)
- [GitHub Labeler](https://github.com/erdaltsksn/gh-label)
- [Golangci-lint](https://golangci-lint.run)
- [GopherJS](http://www.gopherjs.org/)
- [GopherJS](https://github.com/gopherjs/gopherjs)
- [GoReleaser](https://goreleaser.com)
- [Helm](https://helm.sh)
- [Hugo](https://gohugo.io)
- [Infracost](https://github.com/infracost/infracost)
- [Istio](https://istio.io)
- [Kool](https://github.com/kool-dev/kool)
- [Kubernetes](http://kubernetes.io/)
- [Kubernetes](https://kubernetes.io/)
- [Kubescape](https://github.com/armosec/kubescape)
- [Linkerd](https://linkerd.io/)
- [Mattermost-server](https://github.com/mattermost/mattermost-server)
- [Mercure](https://mercure.rocks/)
@ -36,9 +37,11 @@
- [Ory Hydra](https://github.com/ory/hydra)
- [Ory Kratos](https://github.com/ory/kratos)
- [Pixie](https://github.com/pixie-io/pixie)
- [Polygon Edge](https://github.com/0xPolygon/polygon-edge)
- [Pouch](https://github.com/alibaba/pouch)
- [ProjectAtomic (enterprise)](http://www.projectatomic.io/)
- [ProjectAtomic (enterprise)](https://www.projectatomic.io/)
- [Prototool](https://github.com/uber/prototool)
- [Pulumi](https://www.pulumi.com)
- [QRcp](https://github.com/claudiodangelis/qrcp)
- [Random](https://github.com/erdaltsksn/random)
- [Rclone](https://rclone.org/)

View File

@ -40,7 +40,7 @@ Bash:
# Linux:
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
# macOS:
$ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
$ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
Zsh:
@ -122,7 +122,7 @@ For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns
Some simplified code from `kubectl get` looks like:
```go
validArgs []string = { "pod", "node", "service", "replicationcontroller" }
validArgs = []string{ "pod", "node", "service", "replicationcontroller" }
cmd := &cobra.Command{
Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
@ -148,7 +148,7 @@ node pod replicationcontroller service
If your nouns have aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
```go
argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
argAliases = []string { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
cmd := &cobra.Command{
...

View File

@ -32,7 +32,7 @@ func main() {
Cobra-CLI is its own program that will create your application and add any
commands you want. It's the easiest way to incorporate Cobra into your application.
For complete details on using the Cobra generator, please refer to [The Cobra-CLI Generator README](https://github.com/spf13/cobra-cli/blob/master/README.md)
For complete details on using the Cobra generator, please refer to [The Cobra-CLI Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md)
## Using the Cobra Library
@ -51,7 +51,7 @@ var rootCmd = &cobra.Command{
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
Complete documentation is available at http://hugo.spf13.com`,
Complete documentation is available at https://gohugo.io/documentation/`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
@ -300,10 +300,34 @@ rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (re
rootCmd.MarkPersistentFlagRequired("region")
```
### Flag Groups
If you have different flags that must be provided together (e.g. if they provide the `--username` flag they MUST provide the `--password` flag as well) then
Cobra can enforce that requirement:
```go
rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
rootCmd.MarkFlagsRequiredTogether("username", "password")
```
You can also prevent different flags from being provided together if they represent mutually
exclusive options such as specifying an output format as either `--json` or `--yaml` but never both:
```go
rootCmd.Flags().BoolVar(&u, "json", false, "Output in JSON")
rootCmd.Flags().BoolVar(&pw, "yaml", false, "Output in YAML")
rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
```
In both of these cases:
- both local and persistent flags can be used
- **NOTE:** the group is only enforced on commands where every flag is defined
- a flag may appear in multiple groups
- a group may contain any number of flags
## Positional and Custom Arguments
Validation of positional arguments can be specified using the `Args` field
of `Command`.
Validation of positional arguments can be specified using the `Args` field of `Command`.
If `Args` is undefined or `nil`, it defaults to `ArbitraryArgs`.
The following validators are built in:
@ -405,7 +429,7 @@ a count and a string.`,
}
```
For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/).
For a more complete example of a larger application, please checkout [Hugo](https://gohugo.io/).
## Help Command
@ -603,7 +627,7 @@ Did you mean this?
Run 'hugo --help' for usage.
```
Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.
Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.
If you need to disable suggestions or tweak the string distance in your command, use:
@ -636,3 +660,7 @@ Cobra can generate documentation based on subcommands, flags, etc. Read more abo
## Generating shell completions
Cobra can generate a shell-completion file for the following shells: bash, zsh, fish, PowerShell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md).
## Providing Active Help
Cobra makes use of the shell-completion system to define a framework allowing you to provide Active Help to your users. Active Help are messages (hints, warnings, etc) printed as the program is being used. Read more about it in [Active Help](active_help.md).

View File

@ -75,7 +75,7 @@ func genZshComp(buf io.StringWriter, name string, includeDesc bool) {
if !includeDesc {
compCmd = ShellCompNoDescRequestCmd
}
WriteStringAndCheck(buf, fmt.Sprintf(`#compdef _%[1]s %[1]s
WriteStringAndCheck(buf, fmt.Sprintf(`#compdef %[1]s
# zsh completion for %-36[1]s -*- shell-script -*-
@ -163,7 +163,24 @@ _%[1]s()
return
fi
local activeHelpMarker="%[8]s"
local endIndex=${#activeHelpMarker}
local startIndex=$((${#activeHelpMarker}+1))
local hasActiveHelp=0
while IFS='\n' read -r comp; do
# Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
__%[1]s_debug "ActiveHelp found: $comp"
comp="${comp[$startIndex,-1]}"
if [ -n "$comp" ]; then
compadd -x "${comp}"
__%[1]s_debug "ActiveHelp will need delimiter"
hasActiveHelp=1
fi
continue
fi
if [ -n "$comp" ]; then
# If requested, completions are returned with a description.
# The description is preceded by a TAB character.
@ -171,7 +188,7 @@ _%[1]s()
# We first need to escape any : as part of the completion itself.
comp=${comp//:/\\:}
local tab=$(printf '\t')
local tab="$(printf '\t')"
comp=${comp//$tab/:}
__%[1]s_debug "Adding completion: ${comp}"
@ -180,6 +197,17 @@ _%[1]s()
fi
done < <(printf "%%s\n" "${out[@]}")
# Add a delimiter after the activeHelp statements, but only if:
# - there are completions following the activeHelp statements, or
# - file completion will be performed (so there will be choices after the activeHelp)
if [ $hasActiveHelp -eq 1 ]; then
if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
__%[1]s_debug "Adding activeHelp delimiter"
compadd -x "--"
hasActiveHelp=0
fi
fi
if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
__%[1]s_debug "Activating nospace."
noSpace="-S ''"
@ -254,5 +282,6 @@ if [ "$funcstack[1]" = "_%[1]s" ]; then
fi
`, name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs,
activeHelpMarker))
}

View File

@ -1,20 +0,0 @@
language: go
go:
- "1.12.x"
- "1.13.x"
- "1.14.x"
before_script:
# make sure we keep path in tact when we sudo
- sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers
# modprobe ip_gre or else the first gre device can't be deleted
- sudo modprobe ip_gre
# modprobe nf_conntrack for the conntrack testing
- sudo modprobe nf_conntrack
- sudo modprobe nf_conntrack_netlink
- sudo modprobe nf_conntrack_ipv4
- sudo modprobe nf_conntrack_ipv6
- sudo modprobe sch_hfsc
- sudo modprobe sch_sfq
install:
- go get -v -t ./...
go_import_path: github.com/vishvananda/netlink

View File

@ -1,6 +1,6 @@
# netlink - netlink library for go #
[![Build Status](https://travis-ci.org/vishvananda/netlink.png?branch=master)](https://travis-ci.org/vishvananda/netlink) [![GoDoc](https://godoc.org/github.com/vishvananda/netlink?status.svg)](https://godoc.org/github.com/vishvananda/netlink)
![Build Status](https://github.com/vishvananda/netlink/actions/workflows/main.yml/badge.svg) [![GoDoc](https://godoc.org/github.com/vishvananda/netlink?status.svg)](https://godoc.org/github.com/vishvananda/netlink)
The netlink package provides a simple netlink library for go. Netlink
is the interface a user-space program in linux uses to communicate with

View File

@ -176,7 +176,7 @@ func AddrList(link Link, family int) ([]Addr, error) {
// The list can be filtered by link and ip family.
func (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
req := h.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP)
msg := nl.NewIfInfomsg(family)
msg := nl.NewIfAddrmsg(family)
req.AddData(msg)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWADDR)
@ -268,7 +268,7 @@ func parseAddr(m []byte) (addr Addr, family int, err error) {
// But obviously, as there are IPv6 PtP addresses, too,
// IFA_LOCAL should also be handled for IPv6.
if local != nil {
if family == FAMILY_V4 && local.IP.Equal(dst.IP) {
if family == FAMILY_V4 && dst != nil && local.IP.Equal(dst.IP) {
addr.IPNet = dst
} else {
addr.IPNet = local
@ -296,13 +296,13 @@ type AddrUpdate struct {
// AddrSubscribe takes a chan down which notifications will be sent
// when addresses change. Close the 'done' chan to stop subscription.
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0)
return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil)
}
// AddrSubscribeAt works like AddrSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns).
func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0)
return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil)
}
// AddrSubscribeOptions contains a set of options to use with
@ -312,6 +312,7 @@ type AddrSubscribeOptions struct {
ErrorCallback func(error)
ListExisting bool
ReceiveBufferSize int
ReceiveTimeout *unix.Timeval
}
// AddrSubscribeWithOptions work like AddrSubscribe but enable to
@ -322,14 +323,20 @@ func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, option
none := netns.None()
options.Namespace = &none
}
return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize)
return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize, options.ReceiveTimeout)
}
func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int) error {
func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int, rcvTimeout *unix.Timeval) error {
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
if err != nil {
return err
}
if rcvTimeout != nil {
if err := s.SetReceiveTimeout(rcvTimeout); err != nil {
return err
}
}
if done != nil {
go func() {
<-done
@ -357,7 +364,8 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
msgs, from, err := s.Receive()
if err != nil {
if cberr != nil {
cberr(err)
cberr(fmt.Errorf("Receive failed: %v",
err))
}
return
}
@ -372,7 +380,6 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
continue
}
if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
continue

View File

@ -16,6 +16,30 @@ const (
BPF_PROG_TYPE_SCHED_ACT
BPF_PROG_TYPE_TRACEPOINT
BPF_PROG_TYPE_XDP
BPF_PROG_TYPE_PERF_EVENT
BPF_PROG_TYPE_CGROUP_SKB
BPF_PROG_TYPE_CGROUP_SOCK
BPF_PROG_TYPE_LWT_IN
BPF_PROG_TYPE_LWT_OUT
BPF_PROG_TYPE_LWT_XMIT
BPF_PROG_TYPE_SOCK_OPS
BPF_PROG_TYPE_SK_SKB
BPF_PROG_TYPE_CGROUP_DEVICE
BPF_PROG_TYPE_SK_MSG
BPF_PROG_TYPE_RAW_TRACEPOINT
BPF_PROG_TYPE_CGROUP_SOCK_ADDR
BPF_PROG_TYPE_LWT_SEG6LOCAL
BPF_PROG_TYPE_LIRC_MODE2
BPF_PROG_TYPE_SK_REUSEPORT
BPF_PROG_TYPE_FLOW_DISSECTOR
BPF_PROG_TYPE_CGROUP_SYSCTL
BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE
BPF_PROG_TYPE_CGROUP_SOCKOPT
BPF_PROG_TYPE_TRACING
BPF_PROG_TYPE_STRUCT_OPS
BPF_PROG_TYPE_EXT
BPF_PROG_TYPE_LSM
BPF_PROG_TYPE_SK_LOOKUP
)
type BPFAttr struct {

View File

@ -191,9 +191,9 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
opt.Fsc.Set(fm1/8, fd, fm2/8)
um1, ud, um2 := hfsc.Usc.Attrs()
opt.Usc.Set(um1/8, ud, um2/8)
nl.NewRtAttrChild(options, nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
nl.NewRtAttrChild(options, nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
nl.NewRtAttrChild(options, nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
options.AddRtAttr(nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
options.AddRtAttr(nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
options.AddRtAttr(nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
}
req.AddData(options)
return nil
@ -341,7 +341,6 @@ func parseHfscClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, err
func parseTcStats(data []byte) (*ClassStatistics, error) {
buf := &bytes.Buffer{}
buf.Write(data)
native := nl.NativeEndian()
tcStats := &tcStats{}
if err := binary.Read(buf, native, tcStats); err != nil {
return nil, err
@ -363,7 +362,6 @@ func parseTcStats(data []byte) (*ClassStatistics, error) {
func parseGnetStats(data []byte, gnetStats interface{}) error {
buf := &bytes.Buffer{}
buf.Write(data)
native := nl.NativeEndian()
return binary.Read(buf, native, gnetStats)
}

View File

@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"net"
"time"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
@ -145,16 +146,23 @@ type ConntrackFlow struct {
Forward ipTuple
Reverse ipTuple
Mark uint32
TimeStart uint64
TimeStop uint64
TimeOut uint32
}
func (s *ConntrackFlow) String() string {
// conntrack cmd output:
// udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0
return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=%d",
// start=2019-07-26 01:26:21.557800506 +0000 UTC stop=1970-01-01 00:00:00 +0000 UTC timeout=30(sec)
start := time.Unix(0, int64(s.TimeStart))
stop := time.Unix(0, int64(s.TimeStop))
timeout := int32(s.TimeOut)
return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=0x%x start=%v stop=%v timeout=%d(sec)",
nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes,
s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes,
s.Mark)
s.Mark, start, stop, timeout)
}
// This method parse the ip tuple structure
@ -174,25 +182,43 @@ func parseIpTuple(reader *bytes.Reader, tpl *ipTuple) uint8 {
tpl.DstIP = v
}
}
// Skip the next 4 bytes nl.NLA_F_NESTED|nl.CTA_TUPLE_PROTO
reader.Seek(4, seekCurrent)
_, t, _, v := parseNfAttrTLV(reader)
// Get total length of nested protocol-specific info.
_, _, protoInfoTotalLen := parseNfAttrTL(reader)
_, t, l, v := parseNfAttrTLV(reader)
// Track the number of bytes read.
protoInfoBytesRead := uint16(nl.SizeofNfattr) + l
if t == nl.CTA_PROTO_NUM {
tpl.Protocol = uint8(v[0])
}
// Skip some padding 3 bytes
// We only parse TCP & UDP headers. Skip the others.
if tpl.Protocol != 6 && tpl.Protocol != 17 {
// skip the rest
bytesRemaining := protoInfoTotalLen - protoInfoBytesRead
reader.Seek(int64(bytesRemaining), seekCurrent)
return tpl.Protocol
}
// Skip 3 bytes of padding
reader.Seek(3, seekCurrent)
protoInfoBytesRead += 3
for i := 0; i < 2; i++ {
_, t, _ := parseNfAttrTL(reader)
protoInfoBytesRead += uint16(nl.SizeofNfattr)
switch t {
case nl.CTA_PROTO_SRC_PORT:
parseBERaw16(reader, &tpl.SrcPort)
protoInfoBytesRead += 2
case nl.CTA_PROTO_DST_PORT:
parseBERaw16(reader, &tpl.DstPort)
protoInfoBytesRead += 2
}
// Skip some padding 2 byte
// Skip 2 bytes of padding
reader.Seek(2, seekCurrent)
protoInfoBytesRead += 2
}
// Skip any remaining/unknown parts of the message
bytesRemaining := protoInfoTotalLen - protoInfoBytesRead
reader.Seek(int64(bytesRemaining), seekCurrent)
return tpl.Protocol
}
@ -211,10 +237,14 @@ func parseNfAttrTL(r *bytes.Reader) (isNested bool, attrType, len uint16) {
binary.Read(r, nl.NativeEndian(), &attrType)
isNested = (attrType & nl.NLA_F_NESTED) == nl.NLA_F_NESTED
attrType = attrType & (nl.NLA_F_NESTED - 1)
return isNested, attrType, len
}
func skipNfAttrValue(r *bytes.Reader, len uint16) {
len = (len + nl.NLA_ALIGNTO - 1) & ^(nl.NLA_ALIGNTO - 1)
r.Seek(int64(len), seekCurrent)
}
func parseBERaw16(r *bytes.Reader, v *uint16) {
binary.Read(r, binary.BigEndian, v)
}
@ -241,6 +271,36 @@ func parseByteAndPacketCounters(r *bytes.Reader) (bytes, packets uint64) {
return
}
// when the flow is alive, only the timestamp_start is returned in structure
func parseTimeStamp(r *bytes.Reader, readSize uint16) (tstart, tstop uint64) {
var numTimeStamps int
oneItem := nl.SizeofNfattr + 8 // 4 bytes attr header + 8 bytes timestamp
if readSize == uint16(oneItem) {
numTimeStamps = 1
} else if readSize == 2*uint16(oneItem) {
numTimeStamps = 2
} else {
return
}
for i := 0; i < numTimeStamps; i++ {
switch _, t, _ := parseNfAttrTL(r); t {
case nl.CTA_TIMESTAMP_START:
parseBERaw64(r, &tstart)
case nl.CTA_TIMESTAMP_STOP:
parseBERaw64(r, &tstop)
default:
return
}
}
return
}
func parseTimeOut(r *bytes.Reader) (ttimeout uint32) {
parseBERaw32(r, &ttimeout)
return
}
func parseConnectionMark(r *bytes.Reader) (mark uint32) {
parseBERaw32(r, &mark)
return
@ -266,25 +326,37 @@ func parseRawData(data []byte) *ConntrackFlow {
if nested, t, l := parseNfAttrTL(reader); nested {
switch t {
case nl.CTA_TUPLE_ORIG:
if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
if nested, t, l = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
parseIpTuple(reader, &s.Forward)
}
case nl.CTA_TUPLE_REPLY:
if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
if nested, t, l = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
parseIpTuple(reader, &s.Reverse)
} else {
// Header not recognized skip it
reader.Seek(int64(l), seekCurrent)
skipNfAttrValue(reader, l)
}
case nl.CTA_COUNTERS_ORIG:
s.Forward.Bytes, s.Forward.Packets = parseByteAndPacketCounters(reader)
case nl.CTA_COUNTERS_REPLY:
s.Reverse.Bytes, s.Reverse.Packets = parseByteAndPacketCounters(reader)
case nl.CTA_TIMESTAMP:
s.TimeStart, s.TimeStop = parseTimeStamp(reader, l)
case nl.CTA_PROTOINFO:
skipNfAttrValue(reader, l)
default:
skipNfAttrValue(reader, l)
}
} else {
switch t {
case nl.CTA_MARK:
s.Mark = parseConnectionMark(reader)
case nl.CTA_TIMEOUT:
s.TimeOut = parseTimeOut(reader)
case nl.CTA_STATUS, nl.CTA_USE, nl.CTA_ID:
skipNfAttrValue(reader, l)
default:
skipNfAttrValue(reader, l)
}
}
}
@ -346,23 +418,34 @@ type CustomConntrackFilter interface {
}
type ConntrackFilter struct {
ipFilter map[ConntrackFilterType]net.IP
ipNetFilter map[ConntrackFilterType]*net.IPNet
portFilter map[ConntrackFilterType]uint16
protoFilter uint8
}
// AddIP adds an IP to the conntrack filter
func (f *ConntrackFilter) AddIP(tp ConntrackFilterType, ip net.IP) error {
if f.ipFilter == nil {
f.ipFilter = make(map[ConntrackFilterType]net.IP)
// AddIPNet adds a IP subnet to the conntrack filter
func (f *ConntrackFilter) AddIPNet(tp ConntrackFilterType, ipNet *net.IPNet) error {
if ipNet == nil {
return fmt.Errorf("Filter attribute empty")
}
if _, ok := f.ipFilter[tp]; ok {
if f.ipNetFilter == nil {
f.ipNetFilter = make(map[ConntrackFilterType]*net.IPNet)
}
if _, ok := f.ipNetFilter[tp]; ok {
return errors.New("Filter attribute already present")
}
f.ipFilter[tp] = ip
f.ipNetFilter[tp] = ipNet
return nil
}
// AddIP adds an IP to the conntrack filter
func (f *ConntrackFilter) AddIP(tp ConntrackFilterType, ip net.IP) error {
if ip == nil {
return fmt.Errorf("Filter attribute empty")
}
return f.AddIPNet(tp, NewIPNet(ip))
}
// AddPort adds a Port to the conntrack filter if the Layer 4 protocol allows it
func (f *ConntrackFilter) AddPort(tp ConntrackFilterType, port uint16) error {
switch f.protoFilter {
@ -394,7 +477,7 @@ func (f *ConntrackFilter) AddProtocol(proto uint8) error {
// MatchConntrackFlow applies the filter to the flow and returns true if the flow matches the filter
// false otherwise
func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
if len(f.ipFilter) == 0 && len(f.portFilter) == 0 && f.protoFilter == 0 {
if len(f.ipNetFilter) == 0 && len(f.portFilter) == 0 && f.protoFilter == 0 {
// empty filter always not match
return false
}
@ -408,30 +491,30 @@ func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
match := true
// IP conntrack filter
if len(f.ipFilter) > 0 {
if len(f.ipNetFilter) > 0 {
// -orig-src ip Source address from original direction
if elem, found := f.ipFilter[ConntrackOrigSrcIP]; found {
match = match && elem.Equal(flow.Forward.SrcIP)
if elem, found := f.ipNetFilter[ConntrackOrigSrcIP]; found {
match = match && elem.Contains(flow.Forward.SrcIP)
}
// -orig-dst ip Destination address from original direction
if elem, found := f.ipFilter[ConntrackOrigDstIP]; match && found {
match = match && elem.Equal(flow.Forward.DstIP)
if elem, found := f.ipNetFilter[ConntrackOrigDstIP]; match && found {
match = match && elem.Contains(flow.Forward.DstIP)
}
// -src-nat ip Source NAT ip
if elem, found := f.ipFilter[ConntrackReplySrcIP]; match && found {
match = match && elem.Equal(flow.Reverse.SrcIP)
if elem, found := f.ipNetFilter[ConntrackReplySrcIP]; match && found {
match = match && elem.Contains(flow.Reverse.SrcIP)
}
// -dst-nat ip Destination NAT ip
if elem, found := f.ipFilter[ConntrackReplyDstIP]; match && found {
match = match && elem.Equal(flow.Reverse.DstIP)
if elem, found := f.ipNetFilter[ConntrackReplyDstIP]; match && found {
match = match && elem.Contains(flow.Reverse.DstIP)
}
// Match source or destination reply IP
if elem, found := f.ipFilter[ConntrackReplyAnyIP]; match && found {
match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP))
if elem, found := f.ipNetFilter[ConntrackReplyAnyIP]; match && found {
match = match && (elem.Contains(flow.Reverse.SrcIP) || elem.Contains(flow.Reverse.DstIP))
}
}

View File

@ -1,9 +1,11 @@
package netlink
import (
"fmt"
"net"
"strings"
"syscall"
"fmt"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
@ -27,6 +29,20 @@ type DevlinkDevice struct {
Attrs DevlinkDevAttrs
}
// DevlinkPortFn represents port function and its attributes
type DevlinkPortFn struct {
HwAddr net.HardwareAddr
State uint8
OpState uint8
}
// DevlinkPortFnSetAttrs represents attributes to set
type DevlinkPortFnSetAttrs struct {
FnAttrs DevlinkPortFn
HwAddrValid bool
StateValid bool
}
// DevlinkPort represents port and its attributes
type DevlinkPort struct {
BusName string
@ -37,6 +53,35 @@ type DevlinkPort struct {
NetdevIfIndex uint32
RdmaDeviceName string
PortFlavour uint16
Fn *DevlinkPortFn
}
type DevLinkPortAddAttrs struct {
Controller uint32
SfNumber uint32
PortIndex uint32
PfNumber uint16
SfNumberValid bool
PortIndexValid bool
ControllerValid bool
}
// DevlinkDeviceInfo represents devlink info
type DevlinkDeviceInfo struct {
Driver string
SerialNumber string
BoardID string
FwApp string
FwAppBoundleID string
FwAppName string
FwBoundleID string
FwMgmt string
FwMgmtAPI string
FwMgmtBuild string
FwNetlist string
FwNetlistBuild string
FwPsidAPI string
FwUndi string
}
func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
@ -107,9 +152,9 @@ func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error
for _, a := range attrs {
switch a.Attr.Type {
case nl.DEVLINK_ATTR_BUS_NAME:
d.BusName = string(a.Value)
d.BusName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_DEV_NAME:
d.DeviceName = string(a.Value)
d.DeviceName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_ESWITCH_MODE:
d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
@ -138,12 +183,12 @@ func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
req.AddData(msg)
b := make([]byte, len(dev.BusName))
b := make([]byte, len(dev.BusName)+1)
copy(b, dev.BusName)
data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
req.AddData(data)
b = make([]byte, len(dev.DeviceName))
b = make([]byte, len(dev.DeviceName)+1)
copy(b, dev.DeviceName)
data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
req.AddData(data)
@ -287,21 +332,33 @@ func (port *DevlinkPort) parseAttributes(attrs []syscall.NetlinkRouteAttr) error
for _, a := range attrs {
switch a.Attr.Type {
case nl.DEVLINK_ATTR_BUS_NAME:
port.BusName = string(a.Value)
port.BusName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_DEV_NAME:
port.DeviceName = string(a.Value)
port.DeviceName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_PORT_INDEX:
port.PortIndex = native.Uint32(a.Value)
case nl.DEVLINK_ATTR_PORT_TYPE:
port.PortType = native.Uint16(a.Value)
case nl.DEVLINK_ATTR_PORT_NETDEV_NAME:
port.NetdeviceName = string(a.Value)
port.NetdeviceName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_PORT_NETDEV_IFINDEX:
port.NetdevIfIndex = native.Uint32(a.Value)
case nl.DEVLINK_ATTR_PORT_IBDEV_NAME:
port.RdmaDeviceName = string(a.Value)
port.RdmaDeviceName = string(a.Value[:len(a.Value)-1])
case nl.DEVLINK_ATTR_PORT_FLAVOUR:
port.PortFlavour = native.Uint16(a.Value)
case nl.DEVLINK_ATTR_PORT_FUNCTION:
port.Fn = &DevlinkPortFn{}
for nested := range nl.ParseAttributes(a.Value) {
switch nested.Type {
case nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR:
port.Fn.HwAddr = nested.Value[:]
case nl.DEVLINK_PORT_FN_ATTR_STATE:
port.Fn.State = uint8(nested.Value[0])
case nl.DEVLINK_PORT_FN_ATTR_OPSTATE:
port.Fn.OpState = uint8(nested.Value[0])
}
}
}
}
return nil
@ -391,3 +448,281 @@ func (h *Handle) DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint
func DevLinkGetPortByIndex(Bus string, Device string, PortIndex uint32) (*DevlinkPort, error) {
return pkgHandle.DevLinkGetPortByIndex(Bus, Device, PortIndex)
}
// DevLinkPortAdd adds a devlink port and returns a port on success
// otherwise returns nil port and an error code.
func (h *Handle) DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_NEW, Bus, Device)
if err != nil {
return nil, err
}
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FLAVOUR, nl.Uint16Attr(Flavour)))
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_PF_NUMBER, nl.Uint16Attr(Attrs.PfNumber)))
if Flavour == nl.DEVLINK_PORT_FLAVOUR_PCI_SF && Attrs.SfNumberValid {
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_PCI_SF_NUMBER, nl.Uint32Attr(Attrs.SfNumber)))
}
if Attrs.PortIndexValid {
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(Attrs.PortIndex)))
}
if Attrs.ControllerValid {
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_CONTROLLER_NUMBER, nl.Uint32Attr(Attrs.Controller)))
}
respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
port, err := parseDevlinkPortMsg(respmsg)
return port, err
}
// DevLinkPortAdd adds a devlink port and returns a port on success
// otherwise returns nil port and an error code.
func DevLinkPortAdd(Bus string, Device string, Flavour uint16, Attrs DevLinkPortAddAttrs) (*DevlinkPort, error) {
return pkgHandle.DevLinkPortAdd(Bus, Device, Flavour, Attrs)
}
// DevLinkPortDel deletes a devlink port and returns success or error code.
func (h *Handle) DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_DEL, Bus, Device)
if err != nil {
return err
}
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
return err
}
// DevLinkPortDel deletes a devlink port and returns success or error code.
func DevLinkPortDel(Bus string, Device string, PortIndex uint32) error {
return pkgHandle.DevLinkPortDel(Bus, Device, PortIndex)
}
// DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
// It returns 0 on success or error code.
func (h *Handle) DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_PORT_SET, Bus, Device)
if err != nil {
return err
}
req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_INDEX, nl.Uint32Attr(PortIndex)))
fnAttr := nl.NewRtAttr(nl.DEVLINK_ATTR_PORT_FUNCTION|unix.NLA_F_NESTED, nil)
if FnAttrs.HwAddrValid {
fnAttr.AddRtAttr(nl.DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, []byte(FnAttrs.FnAttrs.HwAddr))
}
if FnAttrs.StateValid {
fnAttr.AddRtAttr(nl.DEVLINK_PORT_FN_ATTR_STATE, nl.Uint8Attr(FnAttrs.FnAttrs.State))
}
req.AddData(fnAttr)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
return err
}
// DevlinkPortFnSet sets one or more port function attributes specified by the attribute mask.
// It returns 0 on success or error code.
func DevlinkPortFnSet(Bus string, Device string, PortIndex uint32, FnAttrs DevlinkPortFnSetAttrs) error {
return pkgHandle.DevlinkPortFnSet(Bus, Device, PortIndex, FnAttrs)
}
// devlinkInfoGetter is function that is responsible for getting devlink info message
// this is introduced for test purpose
type devlinkInfoGetter func(bus, device string) ([]byte, error)
// DevlinkGetDeviceInfoByName returns devlink info for selected device,
// otherwise returns an error code.
// Equivalent to: `devlink dev info $dev`
func (h *Handle) DevlinkGetDeviceInfoByName(Bus string, Device string, getInfoMsg devlinkInfoGetter) (*DevlinkDeviceInfo, error) {
info, err := h.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, getInfoMsg)
if err != nil {
return nil, err
}
return parseInfoData(info), nil
}
// DevlinkGetDeviceInfoByName returns devlink info for selected device,
// otherwise returns an error code.
// Equivalent to: `devlink dev info $dev`
func DevlinkGetDeviceInfoByName(Bus string, Device string) (*DevlinkDeviceInfo, error) {
return pkgHandle.DevlinkGetDeviceInfoByName(Bus, Device, pkgHandle.getDevlinkInfoMsg)
}
// DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
// otherwise returns an error code.
// Equivalent to: `devlink dev info $dev`
func (h *Handle) DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string, getInfoMsg devlinkInfoGetter) (map[string]string, error) {
response, err := getInfoMsg(Bus, Device)
if err != nil {
return nil, err
}
info, err := parseInfoMsg(response)
if err != nil {
return nil, err
}
return info, nil
}
// DevlinkGetDeviceInfoByNameAsMap returns devlink info for selected device as a map,
// otherwise returns an error code.
// Equivalent to: `devlink dev info $dev`
func DevlinkGetDeviceInfoByNameAsMap(Bus string, Device string) (map[string]string, error) {
return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(Bus, Device, pkgHandle.getDevlinkInfoMsg)
}
// GetDevlinkInfo returns devlink info for target device,
// otherwise returns an error code.
func (d *DevlinkDevice) GetDevlinkInfo() (*DevlinkDeviceInfo, error) {
return pkgHandle.DevlinkGetDeviceInfoByName(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
}
// GetDevlinkInfoAsMap returns devlink info for target device as a map,
// otherwise returns an error code.
func (d *DevlinkDevice) GetDevlinkInfoAsMap() (map[string]string, error) {
return pkgHandle.DevlinkGetDeviceInfoByNameAsMap(d.BusName, d.DeviceName, pkgHandle.getDevlinkInfoMsg)
}
func (h *Handle) getDevlinkInfoMsg(bus, device string) ([]byte, error) {
_, req, err := h.createCmdReq(nl.DEVLINK_CMD_INFO_GET, bus, device)
if err != nil {
return nil, err
}
response, err := req.Execute(unix.NETLINK_GENERIC, 0)
if err != nil {
return nil, err
}
if len(response) < 1 {
return nil, fmt.Errorf("getDevlinkInfoMsg: message too short")
}
return response[0], nil
}
func parseInfoMsg(msg []byte) (map[string]string, error) {
if len(msg) < nl.SizeofGenlmsg {
return nil, fmt.Errorf("parseInfoMsg: message too short")
}
info := make(map[string]string)
err := collectInfoData(msg[nl.SizeofGenlmsg:], info)
if err != nil {
return nil, err
}
return info, nil
}
func collectInfoData(msg []byte, data map[string]string) error {
attrs, err := nl.ParseRouteAttr(msg)
if err != nil {
return err
}
for _, attr := range attrs {
switch attr.Attr.Type {
case nl.DEVLINK_ATTR_INFO_DRIVER_NAME:
data["driver"] = parseInfoValue(attr.Value)
case nl.DEVLINK_ATTR_INFO_SERIAL_NUMBER:
data["serialNumber"] = parseInfoValue(attr.Value)
case nl.DEVLINK_ATTR_INFO_VERSION_RUNNING, nl.DEVLINK_ATTR_INFO_VERSION_FIXED,
nl.DEVLINK_ATTR_INFO_VERSION_STORED:
key, value, err := getNestedInfoData(attr.Value)
if err != nil {
return err
}
data[key] = value
}
}
if len(data) == 0 {
return fmt.Errorf("collectInfoData: could not read attributes")
}
return nil
}
func getNestedInfoData(msg []byte) (string, string, error) {
nestedAttrs, err := nl.ParseRouteAttr(msg)
var key, value string
if err != nil {
return "", "", err
}
if len(nestedAttrs) != 2 {
return "", "", fmt.Errorf("getNestedInfoData: too few attributes in nested structure")
}
for _, nestedAttr := range nestedAttrs {
switch nestedAttr.Attr.Type {
case nl.DEVLINK_ATTR_INFO_VERSION_NAME:
key = parseInfoValue(nestedAttr.Value)
case nl.DEVLINK_ATTR_INFO_VERSION_VALUE:
value = parseInfoValue(nestedAttr.Value)
}
}
if key == "" {
return "", "", fmt.Errorf("getNestedInfoData: key not found")
}
if value == "" {
return "", "", fmt.Errorf("getNestedInfoData: value not found")
}
return key, value, nil
}
func parseInfoData(data map[string]string) *DevlinkDeviceInfo {
info := new(DevlinkDeviceInfo)
for key, value := range data {
switch key {
case "driver":
info.Driver = value
case "serialNumber":
info.SerialNumber = value
case "board.id":
info.BoardID = value
case "fw.app":
info.FwApp = value
case "fw.app.bundle_id":
info.FwAppBoundleID = value
case "fw.app.name":
info.FwAppName = value
case "fw.bundle_id":
info.FwBoundleID = value
case "fw.mgmt":
info.FwMgmt = value
case "fw.mgmt.api":
info.FwMgmtAPI = value
case "fw.mgmt.build":
info.FwMgmtBuild = value
case "fw.netlist":
info.FwNetlist = value
case "fw.netlist.build":
info.FwNetlistBuild = value
case "fw.psid.api":
info.FwPsidAPI = value
case "fw.undi":
info.FwUndi = value
}
}
return info
}
func parseInfoValue(value []byte) string {
v := strings.ReplaceAll(string(value), "\x00", "")
return strings.TrimSpace(v)
}

View File

@ -157,6 +157,39 @@ func NewConnmarkAction() *ConnmarkAction {
}
}
type CsumUpdateFlags uint32
const (
TCA_CSUM_UPDATE_FLAG_IPV4HDR CsumUpdateFlags = 1
TCA_CSUM_UPDATE_FLAG_ICMP CsumUpdateFlags = 2
TCA_CSUM_UPDATE_FLAG_IGMP CsumUpdateFlags = 4
TCA_CSUM_UPDATE_FLAG_TCP CsumUpdateFlags = 8
TCA_CSUM_UPDATE_FLAG_UDP CsumUpdateFlags = 16
TCA_CSUM_UPDATE_FLAG_UDPLITE CsumUpdateFlags = 32
TCA_CSUM_UPDATE_FLAG_SCTP CsumUpdateFlags = 64
)
type CsumAction struct {
ActionAttrs
UpdateFlags CsumUpdateFlags
}
func (action *CsumAction) Type() string {
return "csum"
}
func (action *CsumAction) Attrs() *ActionAttrs {
return &action.ActionAttrs
}
func NewCsumAction() *CsumAction {
return &CsumAction{
ActionAttrs: ActionAttrs{
Action: TC_ACT_PIPE,
},
}
}
type MirredAct uint8
func (a MirredAct) String() string {
@ -260,6 +293,40 @@ func NewSkbEditAction() *SkbEditAction {
}
}
type PoliceAction struct {
ActionAttrs
Rate uint32 // in byte per second
Burst uint32 // in byte
RCellLog int
Mtu uint32
Mpu uint16 // in byte
PeakRate uint32 // in byte per second
PCellLog int
AvRate uint32 // in byte per second
Overhead uint16
LinkLayer int
ExceedAction TcPolAct
NotExceedAction TcPolAct
}
func (action *PoliceAction) Type() string {
return "police"
}
func (action *PoliceAction) Attrs() *ActionAttrs {
return &action.ActionAttrs
}
func NewPoliceAction() *PoliceAction {
return &PoliceAction{
RCellLog: -1,
PCellLog: -1,
LinkLayer: 1, // ETHERNET
ExceedAction: TC_POLICE_RECLASSIFY,
NotExceedAction: TC_POLICE_OK,
}
}
// MatchAll filters match all packets
type MatchAll struct {
FilterAttrs
@ -275,20 +342,20 @@ func (filter *MatchAll) Type() string {
return "matchall"
}
type FilterFwAttrs struct {
ClassId uint32
InDev string
Mask uint32
Index uint32
Buffer uint32
Mtu uint32
Mpu uint16
Rate uint32
AvRate uint32
PeakRate uint32
Action TcPolAct
Overhead uint16
LinkLayer int
type FwFilter struct {
FilterAttrs
ClassId uint32
InDev string
Mask uint32
Police *PoliceAction
}
func (filter *FwFilter) Attrs() *FilterAttrs {
return &filter.FilterAttrs
}
func (filter *FwFilter) Type() string {
return "fw"
}
type BpfFilter struct {

View File

@ -6,6 +6,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"net"
"syscall"
"github.com/vishvananda/netlink/nl"
@ -50,74 +51,129 @@ func (filter *U32) Type() string {
return "u32"
}
// Fw filter filters on firewall marks
// NOTE: this is in filter_linux because it refers to nl.TcPolice which
// is defined in nl/tc_linux.go
type Fw struct {
type Flower struct {
FilterAttrs
ClassId uint32
// TODO remove nl type from interface
Police nl.TcPolice
InDev string
// TODO Action
Mask uint32
AvRate uint32
Rtab [256]uint32
Ptab [256]uint32
DestIP net.IP
DestIPMask net.IPMask
SrcIP net.IP
SrcIPMask net.IPMask
EthType uint16
EncDestIP net.IP
EncDestIPMask net.IPMask
EncSrcIP net.IP
EncSrcIPMask net.IPMask
EncDestPort uint16
EncKeyId uint32
Actions []Action
}
func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
var rtab [256]uint32
var ptab [256]uint32
rcellLog := -1
pcellLog := -1
avrate := fattrs.AvRate / 8
police := nl.TcPolice{}
police.Rate.Rate = fattrs.Rate / 8
police.PeakRate.Rate = fattrs.PeakRate / 8
buffer := fattrs.Buffer
linklayer := nl.LINKLAYER_ETHERNET
if fattrs.LinkLayer != nl.LINKLAYER_UNSPEC {
linklayer = fattrs.LinkLayer
}
police.Action = int32(fattrs.Action)
if police.Rate.Rate != 0 {
police.Rate.Mpu = fattrs.Mpu
police.Rate.Overhead = fattrs.Overhead
if CalcRtable(&police.Rate, rtab[:], rcellLog, fattrs.Mtu, linklayer) < 0 {
return nil, errors.New("TBF: failed to calculate rate table")
}
police.Burst = Xmittime(uint64(police.Rate.Rate), uint32(buffer))
}
police.Mtu = fattrs.Mtu
if police.PeakRate.Rate != 0 {
police.PeakRate.Mpu = fattrs.Mpu
police.PeakRate.Overhead = fattrs.Overhead
if CalcRtable(&police.PeakRate, ptab[:], pcellLog, fattrs.Mtu, linklayer) < 0 {
return nil, errors.New("POLICE: failed to calculate peak rate table")
}
}
return &Fw{
FilterAttrs: attrs,
ClassId: fattrs.ClassId,
InDev: fattrs.InDev,
Mask: fattrs.Mask,
Police: police,
AvRate: avrate,
Rtab: rtab,
Ptab: ptab,
}, nil
}
func (filter *Fw) Attrs() *FilterAttrs {
func (filter *Flower) Attrs() *FilterAttrs {
return &filter.FilterAttrs
}
func (filter *Fw) Type() string {
return "fw"
func (filter *Flower) Type() string {
return "flower"
}
func (filter *Flower) encodeIP(parent *nl.RtAttr, ip net.IP, mask net.IPMask, v4Type, v6Type int, v4MaskType, v6MaskType int) {
ipType := v4Type
maskType := v4MaskType
encodeMask := mask
if mask == nil {
encodeMask = net.CIDRMask(32, 32)
}
v4IP := ip.To4()
if v4IP == nil {
ipType = v6Type
maskType = v6MaskType
if mask == nil {
encodeMask = net.CIDRMask(128, 128)
}
} else {
ip = v4IP
}
parent.AddRtAttr(ipType, ip)
parent.AddRtAttr(maskType, encodeMask)
}
func (filter *Flower) encode(parent *nl.RtAttr) error {
if filter.EthType != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_ETH_TYPE, htons(filter.EthType))
}
if filter.SrcIP != nil {
filter.encodeIP(parent, filter.SrcIP, filter.SrcIPMask,
nl.TCA_FLOWER_KEY_IPV4_SRC, nl.TCA_FLOWER_KEY_IPV6_SRC,
nl.TCA_FLOWER_KEY_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_IPV6_SRC_MASK)
}
if filter.DestIP != nil {
filter.encodeIP(parent, filter.DestIP, filter.DestIPMask,
nl.TCA_FLOWER_KEY_IPV4_DST, nl.TCA_FLOWER_KEY_IPV6_DST,
nl.TCA_FLOWER_KEY_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_IPV6_DST_MASK)
}
if filter.EncSrcIP != nil {
filter.encodeIP(parent, filter.EncSrcIP, filter.EncSrcIPMask,
nl.TCA_FLOWER_KEY_ENC_IPV4_SRC, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC,
nl.TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK)
}
if filter.EncDestIP != nil {
filter.encodeIP(parent, filter.EncDestIP, filter.EncSrcIPMask,
nl.TCA_FLOWER_KEY_ENC_IPV4_DST, nl.TCA_FLOWER_KEY_ENC_IPV6_DST,
nl.TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_DST_MASK)
}
if filter.EncDestPort != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_ENC_UDP_DST_PORT, htons(filter.EncDestPort))
}
if filter.EncKeyId != 0 {
parent.AddRtAttr(nl.TCA_FLOWER_KEY_ENC_KEY_ID, htonl(filter.EncKeyId))
}
actionsAttr := parent.AddRtAttr(nl.TCA_FLOWER_ACT, nil)
if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
return err
}
return nil
}
func (filter *Flower) decode(data []syscall.NetlinkRouteAttr) error {
for _, datum := range data {
switch datum.Attr.Type {
case nl.TCA_FLOWER_KEY_ETH_TYPE:
filter.EthType = ntohs(datum.Value)
case nl.TCA_FLOWER_KEY_IPV4_SRC, nl.TCA_FLOWER_KEY_IPV6_SRC:
filter.SrcIP = datum.Value
case nl.TCA_FLOWER_KEY_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_IPV6_SRC_MASK:
filter.SrcIPMask = datum.Value
case nl.TCA_FLOWER_KEY_IPV4_DST, nl.TCA_FLOWER_KEY_IPV6_DST:
filter.DestIP = datum.Value
case nl.TCA_FLOWER_KEY_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_IPV6_DST_MASK:
filter.DestIPMask = datum.Value
case nl.TCA_FLOWER_KEY_ENC_IPV4_SRC, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC:
filter.EncSrcIP = datum.Value
case nl.TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK:
filter.EncSrcIPMask = datum.Value
case nl.TCA_FLOWER_KEY_ENC_IPV4_DST, nl.TCA_FLOWER_KEY_ENC_IPV6_DST:
filter.EncDestIP = datum.Value
case nl.TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_DST_MASK:
filter.EncDestIPMask = datum.Value
case nl.TCA_FLOWER_KEY_ENC_UDP_DST_PORT:
filter.EncDestPort = ntohs(datum.Value)
case nl.TCA_FLOWER_KEY_ENC_KEY_ID:
filter.EncKeyId = ntohl(datum.Value)
case nl.TCA_FLOWER_ACT:
tables, err := nl.ParseRouteAttr(datum.Value)
if err != nil {
return err
}
filter.Actions, err = parseActions(tables)
if err != nil {
return err
}
}
}
return nil
}
// FilterDel will delete a filter from the system.
@ -169,7 +225,6 @@ func (h *Handle) FilterReplace(filter Filter) error {
}
func (h *Handle) filterModify(filter Filter, flags int) error {
native = nl.NativeEndian()
req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, flags|unix.NLM_F_ACK)
base := filter.Attrs()
msg := &nl.TcMsg{
@ -237,7 +292,7 @@ func (h *Handle) filterModify(filter Filter, flags int) error {
if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
return err
}
case *Fw:
case *FwFilter:
if filter.Mask != 0 {
b := make([]byte, 4)
native.PutUint32(b, filter.Mask)
@ -246,17 +301,10 @@ func (h *Handle) filterModify(filter Filter, flags int) error {
if filter.InDev != "" {
options.AddRtAttr(nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev))
}
if (filter.Police != nl.TcPolice{}) {
if filter.Police != nil {
police := options.AddRtAttr(nl.TCA_FW_POLICE, nil)
police.AddRtAttr(nl.TCA_POLICE_TBF, filter.Police.Serialize())
if (filter.Police.Rate != nl.TcRateSpec{}) {
payload := SerializeRtab(filter.Rtab)
police.AddRtAttr(nl.TCA_POLICE_RATE, payload)
}
if (filter.Police.PeakRate != nl.TcRateSpec{}) {
payload := SerializeRtab(filter.Ptab)
police.AddRtAttr(nl.TCA_POLICE_PEAKRATE, payload)
if err := encodePolice(police, filter.Police); err != nil {
return err
}
}
if filter.ClassId != 0 {
@ -287,6 +335,10 @@ func (h *Handle) filterModify(filter Filter, flags int) error {
if filter.ClassId != 0 {
options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
}
case *Flower:
if err := filter.encode(options); err != nil {
return err
}
}
req.AddData(options)
@ -350,11 +402,13 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
case "u32":
filter = &U32{}
case "fw":
filter = &Fw{}
filter = &FwFilter{}
case "bpf":
filter = &BpfFilter{}
case "matchall":
filter = &MatchAll{}
case "flower":
filter = &Flower{}
default:
filter = &GenericFilter{FilterType: filterType}
}
@ -384,6 +438,11 @@ func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
if err != nil {
return nil, err
}
case "flower":
detailed, err = parseFlowerData(filter, data)
if err != nil {
return nil, err
}
default:
detailed = true
}
@ -415,6 +474,53 @@ func toAttrs(tcgen *nl.TcGen, attrs *ActionAttrs) {
attrs.Bindcnt = int(tcgen.Bindcnt)
}
func encodePolice(attr *nl.RtAttr, action *PoliceAction) error {
var rtab [256]uint32
var ptab [256]uint32
police := nl.TcPolice{}
police.Index = uint32(action.Attrs().Index)
police.Bindcnt = int32(action.Attrs().Bindcnt)
police.Capab = uint32(action.Attrs().Capab)
police.Refcnt = int32(action.Attrs().Refcnt)
police.Rate.Rate = action.Rate
police.PeakRate.Rate = action.PeakRate
police.Action = int32(action.ExceedAction)
if police.Rate.Rate != 0 {
police.Rate.Mpu = action.Mpu
police.Rate.Overhead = action.Overhead
if CalcRtable(&police.Rate, rtab[:], action.RCellLog, action.Mtu, action.LinkLayer) < 0 {
return errors.New("TBF: failed to calculate rate table")
}
police.Burst = Xmittime(uint64(police.Rate.Rate), action.Burst)
}
police.Mtu = action.Mtu
if police.PeakRate.Rate != 0 {
police.PeakRate.Mpu = action.Mpu
police.PeakRate.Overhead = action.Overhead
if CalcRtable(&police.PeakRate, ptab[:], action.PCellLog, action.Mtu, action.LinkLayer) < 0 {
return errors.New("POLICE: failed to calculate peak rate table")
}
}
attr.AddRtAttr(nl.TCA_POLICE_TBF, police.Serialize())
if police.Rate.Rate != 0 {
attr.AddRtAttr(nl.TCA_POLICE_RATE, SerializeRtab(rtab))
}
if police.PeakRate.Rate != 0 {
attr.AddRtAttr(nl.TCA_POLICE_PEAKRATE, SerializeRtab(ptab))
}
if action.AvRate != 0 {
attr.AddRtAttr(nl.TCA_POLICE_AVRATE, nl.Uint32Attr(action.AvRate))
}
if action.NotExceedAction != 0 {
attr.AddRtAttr(nl.TCA_POLICE_RESULT, nl.Uint32Attr(uint32(action.NotExceedAction)))
}
return nil
}
func EncodeActions(attr *nl.RtAttr, actions []Action) error {
tabIndex := int(nl.TCA_ACT_TAB)
@ -422,6 +528,14 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
switch action := action.(type) {
default:
return fmt.Errorf("unknown action type %s", action.Type())
case *PoliceAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("police"))
aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
if err := encodePolice(aopts, action); err != nil {
return err
}
case *MirredAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
@ -493,6 +607,16 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
}
toTcGen(action.Attrs(), &connmark.TcGen)
aopts.AddRtAttr(nl.TCA_CONNMARK_PARMS, connmark.Serialize())
case *CsumAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("csum"))
aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
csum := nl.TcCsum{
UpdateFlags: uint32(action.UpdateFlags),
}
toTcGen(action.Attrs(), &csum.TcGen)
aopts.AddRtAttr(nl.TCA_CSUM_PARMS, csum.Serialize())
case *BpfAction:
table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
@ -516,6 +640,29 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
return nil
}
func parsePolice(data syscall.NetlinkRouteAttr, police *PoliceAction) {
switch data.Attr.Type {
case nl.TCA_POLICE_RESULT:
police.NotExceedAction = TcPolAct(native.Uint32(data.Value[0:4]))
case nl.TCA_POLICE_AVRATE:
police.AvRate = native.Uint32(data.Value[0:4])
case nl.TCA_POLICE_TBF:
p := *nl.DeserializeTcPolice(data.Value)
police.ActionAttrs = ActionAttrs{}
police.Attrs().Index = int(p.Index)
police.Attrs().Bindcnt = int(p.Bindcnt)
police.Attrs().Capab = int(p.Capab)
police.Attrs().Refcnt = int(p.Refcnt)
police.ExceedAction = TcPolAct(p.Action)
police.Rate = p.Rate.Rate
police.PeakRate = p.PeakRate.Rate
police.Burst = Xmitsize(uint64(p.Rate.Rate), p.Burst)
police.Mtu = p.Mtu
police.LinkLayer = int(p.Rate.Linklayer) & nl.TC_LINKLAYER_MASK
police.Overhead = p.Rate.Overhead
}
}
func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
var actions []Action
for _, table := range tables {
@ -538,12 +685,16 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
action = &BpfAction{}
case "connmark":
action = &ConnmarkAction{}
case "csum":
action = &CsumAction{}
case "gact":
action = &GenericAction{}
case "tunnel_key":
action = &TunnelKeyAction{}
case "skbedit":
action = &SkbEditAction{}
case "police":
action = &PoliceAction{}
default:
break nextattr
}
@ -616,12 +767,22 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
toAttrs(&connmark.TcGen, action.Attrs())
action.(*ConnmarkAction).Zone = connmark.Zone
}
case "csum":
switch adatum.Attr.Type {
case nl.TCA_CSUM_PARMS:
csum := *nl.DeserializeTcCsum(adatum.Value)
action.(*CsumAction).ActionAttrs = ActionAttrs{}
toAttrs(&csum.TcGen, action.Attrs())
action.(*CsumAction).UpdateFlags = CsumUpdateFlags(csum.UpdateFlags)
}
case "gact":
switch adatum.Attr.Type {
case nl.TCA_GACT_PARMS:
gen := *nl.DeserializeTcGen(adatum.Value)
toAttrs(&gen, action.Attrs())
}
case "police":
parsePolice(adatum, action.(*PoliceAction))
}
}
}
@ -632,7 +793,6 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
}
func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
u32 := filter.(*U32)
detailed := false
for _, datum := range data {
@ -678,8 +838,7 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
}
func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
fw := filter.(*Fw)
fw := filter.(*FwFilter)
detailed := true
for _, datum := range data {
switch datum.Attr.Type {
@ -690,24 +849,18 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
case nl.TCA_FW_INDEV:
fw.InDev = string(datum.Value[:len(datum.Value)-1])
case nl.TCA_FW_POLICE:
var police PoliceAction
adata, _ := nl.ParseRouteAttr(datum.Value)
for _, aattr := range adata {
switch aattr.Attr.Type {
case nl.TCA_POLICE_TBF:
fw.Police = *nl.DeserializeTcPolice(aattr.Value)
case nl.TCA_POLICE_RATE:
fw.Rtab = DeserializeRtab(aattr.Value)
case nl.TCA_POLICE_PEAKRATE:
fw.Ptab = DeserializeRtab(aattr.Value)
}
parsePolice(aattr, &police)
}
fw.Police = &police
}
}
return detailed, nil
}
func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
bpf := filter.(*BpfFilter)
detailed := true
for _, datum := range data {
@ -726,14 +879,13 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
case nl.TCA_BPF_ID:
bpf.Id = int(native.Uint32(datum.Value[0:4]))
case nl.TCA_BPF_TAG:
bpf.Tag = hex.EncodeToString(datum.Value[:len(datum.Value)-1])
bpf.Tag = hex.EncodeToString(datum.Value)
}
}
return detailed, nil
}
func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
native = nl.NativeEndian()
matchall := filter.(*MatchAll)
detailed := true
for _, datum := range data {
@ -754,6 +906,10 @@ func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, er
return detailed, nil
}
func parseFlowerData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
return true, filter.(*Flower).decode(data)
}
func AlignToAtm(size uint) uint {
var linksize, cells int
cells = int(size / nl.ATM_CELL_PAYLOAD)
@ -801,14 +957,12 @@ func CalcRtable(rate *nl.TcRateSpec, rtab []uint32, cellLog int, mtu uint32, lin
func DeserializeRtab(b []byte) [256]uint32 {
var rtab [256]uint32
native := nl.NativeEndian()
r := bytes.NewReader(b)
_ = binary.Read(r, native, &rtab)
return rtab
}
func SerializeRtab(rtab [256]uint32) []byte {
native := nl.NativeEndian()
var w bytes.Buffer
_ = binary.Write(&w, native, rtab)
return w.Bytes()

View File

@ -15,7 +15,7 @@ var pkgHandle = &Handle{}
// Handle is an handle for the netlink requests on a
// specific network namespace. All the requests on the
// same netlink family share the same netlink socket,
// which gets released when the handle is deleted.
// which gets released when the handle is Close'd.
type Handle struct {
sockets map[int]*nl.SocketHandle
lookupByDump bool
@ -107,6 +107,21 @@ func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) {
return results, nil
}
// SetStrictCheck sets the strict check socket option for each socket in the netlink handle. Returns early if any set operation fails
func (h *Handle) SetStrictCheck(state bool) error {
for _, sh := range h.sockets {
var stateInt int = 0
if state {
stateInt = 1
}
err := unix.SetsockoptInt(sh.Socket.GetFd(), unix.SOL_NETLINK, unix.NETLINK_GET_STRICT_CHK, stateInt)
if err != nil {
return err
}
}
return nil
}
// NewHandleAt returns a netlink handle on the network namespace
// specified by ns. If ns=netns.None(), current network namespace
// will be assumed
@ -136,14 +151,22 @@ func newHandle(newNs, curNs netns.NsHandle, nlFamilies ...int) (*Handle, error)
return h, nil
}
// Delete releases the resources allocated to this handle
func (h *Handle) Delete() {
// Close releases the resources allocated to this handle
func (h *Handle) Close() {
for _, sh := range h.sockets {
sh.Close()
}
h.sockets = nil
}
// Delete releases the resources allocated to this handle
//
// Deprecated: use Close instead which is in line with typical resource release
// patterns for files and other resources.
func (h *Handle) Delete() {
h.Close()
}
func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest {
// Do this so that package API still use nl package variable nextSeqNr
if h.sockets == nil {

View File

@ -23,6 +23,8 @@ func NewHandleAtFrom(newNs, curNs netns.NsHandle) (*Handle, error) {
return nil, ErrNotImplemented
}
func (h *Handle) Close() {}
func (h *Handle) Delete() {}
func (h *Handle) SupportsNetlinkFamily(nlFamily int) bool {

View File

@ -1,6 +1,7 @@
package netlink
import (
"encoding/binary"
"log"
"net"
"syscall"
@ -11,12 +12,19 @@ import (
// IPSetEntry is used for adding, updating, retreiving and deleting entries
type IPSetEntry struct {
Comment string
MAC net.HardwareAddr
IP net.IP
Timeout *uint32
Packets *uint64
Bytes *uint64
Comment string
MAC net.HardwareAddr
IP net.IP
CIDR uint8
Timeout *uint32
Packets *uint64
Bytes *uint64
Protocol *uint8
Port *uint16
IP2 net.IP
CIDR2 uint8
IFace string
Mark *uint32
Replace bool // replace existing entry
}
@ -32,6 +40,12 @@ type IPSetResult struct {
SetName string
TypeName string
Comment string
MarkMask uint32
IPFrom net.IP
IPTo net.IP
PortFrom uint16
PortTo uint16
HashSize uint32
NumEntries uint32
@ -52,6 +66,12 @@ type IpsetCreateOptions struct {
Counters bool
Comments bool
Skbinfo bool
Revision uint8
IPFrom net.IP
IPTo net.IP
PortFrom uint16
PortTo uint16
}
// IpsetProtocol returns the ipset protocol version from the kernel
@ -86,12 +106,12 @@ func IpsetListAll() ([]IPSetResult, error) {
// IpsetAdd adds an entry to an existing ipset.
func IpsetAdd(setname string, entry *IPSetEntry) error {
return pkgHandle.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
return pkgHandle.IpsetAdd(setname, entry)
}
// IpsetDel deletes an entry from an existing ipset.
func IpsetDel(setname string, entry *IPSetEntry) error {
return pkgHandle.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
return pkgHandle.IpsetDel(setname, entry)
}
func (h *Handle) IpsetProtocol() (protocol uint8, minVersion uint8, err error) {
@ -114,11 +134,30 @@ func (h *Handle) IpsetCreate(setname, typename string, options IpsetCreateOption
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_TYPENAME, nl.ZeroTerminated(typename)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(0)))
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(2))) // 2 == inet
revision := options.Revision
if revision == 0 {
revision = getIpsetDefaultWithTypeName(typename)
}
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_REVISION, nl.Uint8Attr(revision)))
data := nl.NewRtAttr(nl.IPSET_ATTR_DATA|int(nl.NLA_F_NESTED), nil)
var family uint8
switch typename {
case "hash:mac":
case "bitmap:port":
buf := make([]byte, 4)
binary.BigEndian.PutUint16(buf, options.PortFrom)
binary.BigEndian.PutUint16(buf[2:], options.PortTo)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PORT_FROM|int(nl.NLA_F_NET_BYTEORDER), buf[:2]))
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PORT_TO|int(nl.NLA_F_NET_BYTEORDER), buf[2:]))
default:
family = unix.AF_INET
}
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_FAMILY, nl.Uint8Attr(family)))
if timeout := options.Timeout; timeout != nil {
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *timeout})
}
@ -187,6 +226,16 @@ func (h *Handle) IpsetListAll() ([]IPSetResult, error) {
return result, nil
}
// IpsetAdd adds an entry to an existing ipset.
func (h *Handle) IpsetAdd(setname string, entry *IPSetEntry) error {
return h.ipsetAddDel(nl.IPSET_CMD_ADD, setname, entry)
}
// IpsetDel deletes an entry from an existing ipset.
func (h *Handle) IpsetDel(setname string, entry *IPSetEntry) error {
return h.ipsetAddDel(nl.IPSET_CMD_DEL, setname, entry)
}
func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error {
req := h.newIpsetRequest(nlCmd)
req.AddData(nl.NewRtAttr(nl.IPSET_ATTR_SETNAME, nl.ZeroTerminated(setname)))
@ -204,15 +253,49 @@ func (h *Handle) ipsetAddDel(nlCmd int, setname string, entry *IPSetEntry) error
if entry.Timeout != nil {
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_TIMEOUT | nl.NLA_F_NET_BYTEORDER, Value: *entry.Timeout})
}
if entry.MAC != nil {
nestedData := nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NET_BYTEORDER), entry.MAC)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER|int(nl.NLA_F_NESTED), nestedData.Serialize()))
}
if entry.IP != nil {
nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NESTED), nestedData.Serialize()))
}
if entry.MAC != nil {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_ETHER, entry.MAC))
}
if entry.CIDR != 0 {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_CIDR, nl.Uint8Attr(entry.CIDR)))
}
if entry.IP2 != nil {
nestedData := nl.NewRtAttr(nl.IPSET_ATTR_IP|int(nl.NLA_F_NET_BYTEORDER), entry.IP2)
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IP2|int(nl.NLA_F_NESTED), nestedData.Serialize()))
}
if entry.CIDR2 != 0 {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_CIDR2, nl.Uint8Attr(entry.CIDR2)))
}
if entry.Port != nil {
if entry.Protocol == nil {
// use tcp protocol as default
val := uint8(unix.IPPROTO_TCP)
entry.Protocol = &val
}
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_PROTO, nl.Uint8Attr(*entry.Protocol)))
buf := make([]byte, 2)
binary.BigEndian.PutUint16(buf, *entry.Port)
data.AddChild(nl.NewRtAttr(int(nl.IPSET_ATTR_PORT|nl.NLA_F_NET_BYTEORDER), buf))
}
if entry.IFace != "" {
data.AddChild(nl.NewRtAttr(nl.IPSET_ATTR_IFACE, nl.ZeroTerminated(entry.IFace)))
}
if entry.Mark != nil {
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_MARK | nl.NLA_F_NET_BYTEORDER, Value: *entry.Mark})
}
data.AddChild(&nl.Uint32Attribute{Type: nl.IPSET_ATTR_LINENO | nl.NLA_F_NET_BYTEORDER, Value: 0})
req.AddData(data)
@ -235,6 +318,17 @@ func (h *Handle) newIpsetRequest(cmd int) *nl.NetlinkRequest {
return req
}
func getIpsetDefaultWithTypeName(typename string) uint8 {
switch typename {
case "hash:ip,port",
"hash:ip,port,ip",
"hash:ip,port,net",
"hash:net,port":
return 1
}
return 0
}
func ipsetExecute(req *nl.NetlinkRequest) (msgs [][]byte, err error) {
msgs, err = req.Execute(unix.NETLINK_NETFILTER, 0)
@ -278,6 +372,8 @@ func (result *IPSetResult) unserialize(msg []byte) {
result.parseAttrADT(attr.Value)
case nl.IPSET_ATTR_PROTOCOL_MIN:
result.ProtocolMinVersion = attr.Value[0]
case nl.IPSET_ATTR_MARKMASK:
result.MarkMask = attr.Uint32()
default:
log.Printf("unknown ipset attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
}
@ -307,12 +403,31 @@ func (result *IPSetResult) parseAttrData(data []byte) {
switch nested.Type {
case nl.IPSET_ATTR_IP | nl.NLA_F_NET_BYTEORDER:
result.Entries = append(result.Entries, IPSetEntry{IP: nested.Value})
case nl.IPSET_ATTR_IP:
result.IPFrom = nested.Value
default:
log.Printf("unknown nested ipset data attribute from kernel: %+v %v", nested, nested.Type&nl.NLA_TYPE_MASK)
}
}
case nl.IPSET_ATTR_IP_TO | nl.NLA_F_NESTED:
for nested := range nl.ParseAttributes(attr.Value) {
switch nested.Type {
case nl.IPSET_ATTR_IP:
result.IPTo = nested.Value
default:
log.Printf("unknown nested ipset data attribute from kernel: %+v %v", nested, nested.Type&nl.NLA_TYPE_MASK)
}
}
case nl.IPSET_ATTR_PORT_FROM | nl.NLA_F_NET_BYTEORDER:
result.PortFrom = networkOrder.Uint16(attr.Value)
case nl.IPSET_ATTR_PORT_TO | nl.NLA_F_NET_BYTEORDER:
result.PortTo = networkOrder.Uint16(attr.Value)
case nl.IPSET_ATTR_CADT_LINENO | nl.NLA_F_NET_BYTEORDER:
result.LineNo = attr.Uint32()
case nl.IPSET_ATTR_COMMENT:
result.Comment = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_MARKMASK:
result.MarkMask = attr.Uint32()
default:
log.Printf("unknown ipset data attribute from kernel: %+v %v", attr, attr.Type&nl.NLA_TYPE_MASK)
}
@ -357,6 +472,30 @@ func parseIPSetEntry(data []byte) (entry IPSetEntry) {
log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
}
}
case nl.IPSET_ATTR_IP2 | nl.NLA_F_NESTED:
for attr := range nl.ParseAttributes(attr.Value) {
switch attr.Type {
case nl.IPSET_ATTR_IP:
entry.IP2 = net.IP(attr.Value)
default:
log.Printf("unknown nested ADT attribute from kernel: %+v", attr)
}
}
case nl.IPSET_ATTR_CIDR:
entry.CIDR = attr.Value[0]
case nl.IPSET_ATTR_CIDR2:
entry.CIDR2 = attr.Value[0]
case nl.IPSET_ATTR_PORT | nl.NLA_F_NET_BYTEORDER:
val := networkOrder.Uint16(attr.Value)
entry.Port = &val
case nl.IPSET_ATTR_PROTO:
val := attr.Value[0]
entry.Protocol = &val
case nl.IPSET_ATTR_IFACE:
entry.IFace = nl.BytesToString(attr.Value)
case nl.IPSET_ATTR_MARK | nl.NLA_F_NET_BYTEORDER:
val := attr.Uint32()
entry.Mark = &val
default:
log.Printf("unknown ADT attribute from kernel: %+v", attr)
}

View File

@ -35,10 +35,13 @@ type LinkAttrs struct {
Alias string
Statistics *LinkStatistics
Promisc int
Allmulti int
Multi int
Xdp *LinkXdp
EncapType string
Protinfo *Protinfo
OperState LinkOperState
PhysSwitchID int
NetNsID int
NumTxQueues int
NumRxQueues int
@ -456,6 +459,19 @@ func (ipvlan *IPVlan) Type() string {
return "ipvlan"
}
// IPVtap - IPVtap is a virtual interfaces based on ipvlan
type IPVtap struct {
IPVlan
}
func (ipvtap *IPVtap) Attrs() *LinkAttrs {
return &ipvtap.LinkAttrs
}
func (ipvtap IPVtap) Type() string {
return "ipvtap"
}
// VlanProtocol type
type VlanProtocol int
@ -946,6 +962,14 @@ func (b *BondSlave) SlaveType() string {
return "bond"
}
type VrfSlave struct {
Table uint32
}
func (v *VrfSlave) SlaveType() string {
return "vrf"
}
// Geneve devices must specify RemoteIP and ID (VNI) on create
// https://github.com/torvalds/linux/blob/47ec5303d73ea344e84f46660fff693c57641386/drivers/net/geneve.c#L1209-L1223
type Geneve struct {
@ -1014,6 +1038,7 @@ type Iptun struct {
EncapType uint16
EncapFlags uint16
FlowBased bool
Proto uint8
}
func (iptun *Iptun) Attrs() *LinkAttrs {
@ -1049,6 +1074,37 @@ func (ip6tnl *Ip6tnl) Type() string {
return "ip6tnl"
}
// from https://elixir.bootlin.com/linux/v5.15.4/source/include/uapi/linux/if_tunnel.h#L84
type TunnelEncapType uint16
const (
None TunnelEncapType = iota
FOU
GUE
)
// from https://elixir.bootlin.com/linux/v5.15.4/source/include/uapi/linux/if_tunnel.h#L91
type TunnelEncapFlag uint16
const (
CSum TunnelEncapFlag = 1 << 0
CSum6 = 1 << 1
RemCSum = 1 << 2
)
// from https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/ip6_tunnel.h#L12
type IP6TunnelFlag uint16
const (
IP6_TNL_F_IGN_ENCAP_LIMIT IP6TunnelFlag = 1 // don't add encapsulation limit if one isn't present in inner packet
IP6_TNL_F_USE_ORIG_TCLASS = 2 // copy the traffic class field from the inner packet
IP6_TNL_F_USE_ORIG_FLOWLABEL = 4 // copy the flowlabel from the inner packet
IP6_TNL_F_MIP6_DEV = 8 // being used for Mobile IPv6
IP6_TNL_F_RCV_DSCP_COPY = 10 // copy DSCP from the outer packet
IP6_TNL_F_USE_ORIG_FWMARK = 20 // copy fwmark from inner packet
IP6_TNL_F_ALLOW_LOCAL_REMOTE = 40 // allow remote endpoint on the local node
)
type Sittun struct {
LinkAttrs
Link uint32
@ -1260,11 +1316,27 @@ func (ipoib *IPoIB) Type() string {
return "ipoib"
}
type BareUDP struct {
LinkAttrs
Port uint16
EtherType uint16
SrcPortMin uint16
MultiProto bool
}
func (bareudp *BareUDP) Attrs() *LinkAttrs {
return &bareudp.LinkAttrs
}
func (bareudp *BareUDP) Type() string {
return "bareudp"
}
// iproute2 supported devices;
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
// gre | gretap | ip6gre | ip6gretap | vti | vti6 | nlmon |
// bond_slave | ipvlan | xfrm
// bond_slave | ipvlan | xfrm | bareudp
// LinkNotFoundError wraps the various not found errors when
// getting/reading links. This is intended for better error

View File

@ -55,8 +55,6 @@ const (
VF_LINK_STATE_DISABLE uint32 = 2
)
var lookupByDump = false
var macvlanModes = [...]uint32{
0,
nl.MACVLAN_MODE_PRIVATE,
@ -153,7 +151,6 @@ func (h *Handle) LinkSetAllmulticastOn(link Link) error {
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Change = unix.IFF_ALLMULTI
msg.Flags = unix.IFF_ALLMULTI
msg.Index = int32(base.Index)
req.AddData(msg)
@ -183,6 +180,51 @@ func (h *Handle) LinkSetAllmulticastOff(link Link) error {
return err
}
// LinkSetMulticastOn enables the reception of multicast packets for the link device.
// Equivalent to: `ip link set $link multicast on`
func LinkSetMulticastOn(link Link) error {
return pkgHandle.LinkSetMulticastOn(link)
}
// LinkSetMulticastOn enables the reception of multicast packets for the link device.
// Equivalent to: `ip link set $link multicast on`
func (h *Handle) LinkSetMulticastOn(link Link) error {
base := link.Attrs()
h.ensureIndex(base)
req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Change = unix.IFF_MULTICAST
msg.Flags = unix.IFF_MULTICAST
msg.Index = int32(base.Index)
req.AddData(msg)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
// LinkSetAllmulticastOff disables the reception of multicast packets for the link device.
// Equivalent to: `ip link set $link multicast off`
func LinkSetMulticastOff(link Link) error {
return pkgHandle.LinkSetMulticastOff(link)
}
// LinkSetAllmulticastOff disables the reception of multicast packets for the link device.
// Equivalent to: `ip link set $link multicast off`
func (h *Handle) LinkSetMulticastOff(link Link) error {
base := link.Attrs()
h.ensureIndex(base)
req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Change = unix.IFF_MULTICAST
msg.Index = int32(base.Index)
req.AddData(msg)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
func MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error {
return pkgHandle.MacvlanMACAddrAdd(link, addr)
}
@ -547,13 +589,13 @@ func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
req.AddData(msg)
data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfVlan{
Vf: uint32(vf),
Vlan: uint32(vlan),
Qos: uint32(qos),
}
nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize())
info.AddRtAttr(nl.IFLA_VF_VLAN, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
@ -1104,6 +1146,10 @@ func (h *Handle) LinkAdd(link Link) error {
return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
}
func LinkModify(link Link) error {
return pkgHandle.LinkModify(link)
}
func (h *Handle) LinkModify(link Link) error {
return h.linkModify(link, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
}
@ -1218,9 +1264,26 @@ func (h *Handle) linkModify(link Link, flags int) error {
}
control := func(file *os.File, f func(fd uintptr)) error {
name := file.Name()
conn, err := file.SyscallConn()
if err != nil {
return fmt.Errorf("SyscallConn() failed on %s: %v", name, err)
}
if err := conn.Control(f); err != nil {
return fmt.Errorf("Failed to get file descriptor for %s: %v", name, err)
}
return nil
}
// only persist interface if NonPersist is NOT set
if !tuntap.NonPersist {
_, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1)
var errno syscall.Errno
if err := control(fds[0], func(fd uintptr) {
_, _, errno = unix.Syscall(unix.SYS_IOCTL, fd, uintptr(unix.TUNSETPERSIST), 1)
}); err != nil {
return err
}
if errno != 0 {
cleanupFds(fds)
return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
@ -1237,7 +1300,10 @@ func (h *Handle) linkModify(link Link, flags int) error {
// un-persist (e.g. allow the interface to be removed) the tuntap
// should not hurt if not set prior, condition might be not needed
if !tuntap.NonPersist {
_, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0)
// ignore error
_ = control(fds[0], func(fd uintptr) {
_, _, _ = unix.Syscall(unix.SYS_IOCTL, fd, uintptr(unix.TUNSETPERSIST), 0)
})
}
cleanupFds(fds)
return err
@ -1409,6 +1475,10 @@ func (h *Handle) linkModify(link Link, flags int) error {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode)))
data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag)))
case *IPVtap:
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode)))
data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag)))
case *Macvlan:
if link.Mode != MACVLAN_MODE_DEFAULT {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
@ -1443,6 +1513,8 @@ func (h *Handle) linkModify(link Link, flags int) error {
addXfrmiAttrs(link, linkInfo)
case *IPoIB:
addIPoIBAttrs(link, linkInfo)
case *BareUDP:
addBareUDPAttrs(link, linkInfo)
}
req.AddData(linkInfo)
@ -1624,7 +1696,7 @@ func execGetLink(req *nl.NetlinkRequest) (Link, error) {
}
}
// linkDeserialize deserializes a raw message received from netlink into
// LinkDeserialize deserializes a raw message received from netlink into
// a link object.
func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
msg := nl.DeserializeIfInfomsg(m)
@ -1639,9 +1711,17 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
base.RawFlags = msg.Flags
base.Flags = linkFlags(msg.Flags)
base.EncapType = msg.EncapType()
base.NetNsID = -1
if msg.Flags&unix.IFF_PROMISC != 0 {
base.Promisc = 1
}
if msg.Flags&unix.IFF_ALLMULTI != 0 {
base.Allmulti = 1
}
if msg.Flags&unix.IFF_MULTICAST != 0 {
base.Multi = 1
}
var (
link Link
stats32 *LinkStatistics32
@ -1680,6 +1760,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Bond{}
case "ipvlan":
link = &IPVlan{}
case "ipvtap":
link = &IPVtap{}
case "macvlan":
link = &Macvlan{}
case "macvtap":
@ -1714,6 +1796,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &IPoIB{}
case "can":
link = &Can{}
case "bareudp":
link = &BareUDP{}
default:
link = &GenericLink{LinkType: linkType}
}
@ -1731,6 +1815,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
parseBondData(link, data)
case "ipvlan":
parseIPVlanData(link, data)
case "ipvtap":
parseIPVtapData(link, data)
case "macvlan":
parseMacvlanData(link, data)
case "macvtap":
@ -1767,13 +1853,19 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
parseIPoIBData(link, data)
case "can":
parseCanData(link, data)
case "bareudp":
parseBareUDPData(link, data)
}
case nl.IFLA_INFO_SLAVE_KIND:
slaveType = string(info.Value[:len(info.Value)-1])
switch slaveType {
case "bond":
linkSlave = &BondSlave{}
case "vrf":
linkSlave = &VrfSlave{}
}
case nl.IFLA_INFO_SLAVE_DATA:
switch slaveType {
case "bond":
@ -1782,6 +1874,12 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
return nil, err
}
parseBondSlaveData(linkSlave, data)
case "vrf":
data, err := nl.ParseRouteAttr(info.Value)
if err != nil {
return nil, err
}
parseVrfSlaveData(linkSlave, data)
}
}
}
@ -1835,6 +1933,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
}
case unix.IFLA_OPERSTATE:
base.OperState = LinkOperState(uint8(attr.Value[0]))
case unix.IFLA_PHYS_SWITCH_ID:
base.PhysSwitchID = int(native.Uint32(attr.Value[0:4]))
case unix.IFLA_LINK_NETNSID:
base.NetNsID = int(native.Uint32(attr.Value[0:4]))
case unix.IFLA_GSO_MAX_SIZE:
@ -2023,7 +2123,8 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
msgs, from, err := s.Receive()
if err != nil {
if cberr != nil {
cberr(err)
cberr(fmt.Errorf("Receive failed: %v",
err))
}
return
}
@ -2038,15 +2139,15 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
continue
}
if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
continue
}
if cberr != nil {
cberr(syscall.Errno(-error))
cberr(fmt.Errorf("error message: %v",
syscall.Errno(-error)))
}
return
continue
}
ifmsg := nl.DeserializeIfInfomsg(m.Data)
header := unix.NlMsghdr(m.Header)
@ -2055,7 +2156,7 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
if cberr != nil {
cberr(err)
}
return
continue
}
ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: header, Link: link}
}
@ -2404,6 +2505,16 @@ func parseBondSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) {
}
}
func parseVrfSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) {
vrfSlave := slave.(*VrfSlave)
for i := range data {
switch data[i].Attr.Type {
case nl.IFLA_BOND_SLAVE_STATE:
vrfSlave.Table = native.Uint32(data[i].Value[0:4])
}
}
}
func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
ipv := link.(*IPVlan)
for _, datum := range data {
@ -2416,6 +2527,18 @@ func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
}
}
func parseIPVtapData(link Link, data []syscall.NetlinkRouteAttr) {
ipv := link.(*IPVtap)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_IPVLAN_MODE:
ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4]))
case nl.IFLA_IPVLAN_FLAG:
ipv.Flag = IPVlanFlag(native.Uint32(datum.Value[0:4]))
}
}
}
func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) {
macv := link.(*Macvtap)
parseMacvlanData(&macv.Macvlan, data)
@ -2751,11 +2874,16 @@ func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) {
data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags))
data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport))
data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport))
data.AddRtAttr(nl.IFLA_IPTUN_PROTO, nl.Uint8Attr(iptun.Proto))
}
func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
iptun := link.(*Iptun)
for _, datum := range data {
// NOTE: same with vxlan, ip tunnel may also has null datum.Value
if len(datum.Value) == 0 {
continue
}
switch datum.Attr.Type {
case nl.IFLA_IPTUN_LOCAL:
iptun.Local = net.IP(datum.Value[0:4])
@ -2777,6 +2905,8 @@ func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
iptun.EncapFlags = native.Uint16(datum.Value[0:2])
case nl.IFLA_IPTUN_COLLECT_METADATA:
iptun.FlowBased = true
case nl.IFLA_IPTUN_PROTO:
iptun.Proto = datum.Value[0]
}
}
}
@ -3099,8 +3229,9 @@ func parseVfInfo(data []syscall.NetlinkRouteAttr, id int) VfInfo {
func addXfrmiAttrs(xfrmi *Xfrmi, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_XFRM_LINK, nl.Uint32Attr(uint32(xfrmi.ParentIndex)))
data.AddRtAttr(nl.IFLA_XFRM_IF_ID, nl.Uint32Attr(xfrmi.Ifid))
if xfrmi.Ifid != 0 {
data.AddRtAttr(nl.IFLA_XFRM_IF_ID, nl.Uint32Attr(xfrmi.Ifid))
}
}
func parseXfrmiData(link Link, data []syscall.NetlinkRouteAttr) {
@ -3303,3 +3434,32 @@ func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) {
data.AddRtAttr(nl.IFLA_IPOIB_MODE, nl.Uint16Attr(uint16(ipoib.Mode)))
data.AddRtAttr(nl.IFLA_IPOIB_UMCAST, nl.Uint16Attr(uint16(ipoib.Umcast)))
}
func addBareUDPAttrs(bareudp *BareUDP, linkInfo *nl.RtAttr) {
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
data.AddRtAttr(nl.IFLA_BAREUDP_PORT, nl.Uint16Attr(nl.Swap16(bareudp.Port)))
data.AddRtAttr(nl.IFLA_BAREUDP_ETHERTYPE, nl.Uint16Attr(nl.Swap16(bareudp.EtherType)))
if bareudp.SrcPortMin != 0 {
data.AddRtAttr(nl.IFLA_BAREUDP_SRCPORT_MIN, nl.Uint16Attr(bareudp.SrcPortMin))
}
if bareudp.MultiProto {
data.AddRtAttr(nl.IFLA_BAREUDP_MULTIPROTO_MODE, []byte{})
}
}
func parseBareUDPData(link Link, data []syscall.NetlinkRouteAttr) {
bareudp := link.(*BareUDP)
for _, attr := range data {
switch attr.Attr.Type {
case nl.IFLA_BAREUDP_PORT:
bareudp.Port = binary.BigEndian.Uint16(attr.Value)
case nl.IFLA_BAREUDP_ETHERTYPE:
bareudp.EtherType = binary.BigEndian.Uint16(attr.Value)
case nl.IFLA_BAREUDP_SRCPORT_MIN:
bareudp.SrcPortMin = native.Uint16(attr.Value)
case nl.IFLA_BAREUDP_MULTIPROTO_MODE:
bareudp.MultiProto = true
}
}
}

View File

@ -12,6 +12,7 @@ type Neigh struct {
State int
Type int
Flags int
FlagsExt int
IP net.IP
HardwareAddr net.HardwareAddr
LLIPAddr net.IP //Used in the case of NHRP

View File

@ -24,7 +24,11 @@ const (
NDA_MASTER
NDA_LINK_NETNSID
NDA_SRC_VNI
NDA_MAX = NDA_SRC_VNI
NDA_PROTOCOL
NDA_NH_ID
NDA_FDB_EXT_ATTRS
NDA_FLAGS_EXT
NDA_MAX = NDA_FLAGS_EXT
)
// Neighbor Cache Entry States.
@ -42,11 +46,19 @@ const (
// Neighbor Flags
const (
NTF_USE = 0x01
NTF_SELF = 0x02
NTF_MASTER = 0x04
NTF_PROXY = 0x08
NTF_ROUTER = 0x80
NTF_USE = 0x01
NTF_SELF = 0x02
NTF_MASTER = 0x04
NTF_PROXY = 0x08
NTF_EXT_LEARNED = 0x10
NTF_OFFLOADED = 0x20
NTF_STICKY = 0x40
NTF_ROUTER = 0x80
)
// Extended Neighbor Flags
const (
NTF_EXT_MANAGED = 0x00000001
)
// Ndmsg is for adding, removing or receiving information about a neighbor table entry
@ -162,11 +174,16 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
if neigh.LLIPAddr != nil {
llIPData := nl.NewRtAttr(NDA_LLADDR, neigh.LLIPAddr.To4())
req.AddData(llIPData)
} else if neigh.Flags != NTF_PROXY || neigh.HardwareAddr != nil {
} else if neigh.HardwareAddr != nil {
hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
req.AddData(hwData)
}
if neigh.FlagsExt != 0 {
flagsExtData := nl.NewRtAttr(NDA_FLAGS_EXT, nl.Uint32Attr(uint32(neigh.FlagsExt)))
req.AddData(flagsExtData)
}
if neigh.Vlan != 0 {
vlanData := nl.NewRtAttr(NDA_VLAN, nl.Uint16Attr(uint16(neigh.Vlan)))
req.AddData(vlanData)
@ -305,6 +322,8 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
} else {
neigh.HardwareAddr = net.HardwareAddr(attr.Value)
}
case NDA_FLAGS_EXT:
neigh.FlagsExt = int(native.Uint32(attr.Value[0:4]))
case NDA_VLAN:
neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
case NDA_VNI:
@ -408,7 +427,6 @@ func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <
continue
}
if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
continue

View File

@ -180,14 +180,30 @@ func RouteAdd(route *Route) error {
return ErrNotImplemented
}
func RouteAppend(route *Route) error {
return ErrNotImplemented
}
func RouteDel(route *Route) error {
return ErrNotImplemented
}
func RouteGet(destination net.IP) ([]Route, error) {
return nil, ErrNotImplemented
}
func RouteList(link Link, family int) ([]Route, error) {
return nil, ErrNotImplemented
}
func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
return nil, ErrNotImplemented
}
func RouteReplace(route *Route) error {
return ErrNotImplemented
}
func XfrmPolicyAdd(policy *XfrmPolicy) error {
return ErrNotImplemented
}

View File

@ -87,7 +87,7 @@ func (h *Handle) getNetNsId(attrType int, val uint32) (int, error) {
rtgen := nl.NewRtGenMsg()
req.AddData(rtgen)
b := make([]byte, 4, 4)
b := make([]byte, 4)
native.PutUint32(b, val)
attr := nl.NewRtAttr(attrType, b)
req.AddData(attr)
@ -126,12 +126,12 @@ func (h *Handle) setNetNsId(attrType int, val uint32, newnsid uint32) error {
rtgen := nl.NewRtGenMsg()
req.AddData(rtgen)
b := make([]byte, 4, 4)
b := make([]byte, 4)
native.PutUint32(b, val)
attr := nl.NewRtAttr(attrType, b)
req.AddData(attr)
b1 := make([]byte, 4, 4)
b1 := make([]byte, 4)
native.PutUint32(b1, newnsid)
attr1 := nl.NewRtAttr(NETNSA_NSID, b1)
req.AddData(attr1)

View File

@ -44,6 +44,7 @@ const (
NLA_F_NESTED uint16 = (1 << 15) // #define NLA_F_NESTED (1 << 15)
NLA_F_NET_BYTEORDER uint16 = (1 << 14) // #define NLA_F_NESTED (1 << 14)
NLA_TYPE_MASK = ^(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
NLA_ALIGNTO uint16 = 4 // #define NLA_ALIGNTO 4
)
// enum ctattr_type {

View File

@ -11,22 +11,37 @@ const (
const (
DEVLINK_CMD_GET = 1
DEVLINK_CMD_PORT_GET = 5
DEVLINK_CMD_PORT_SET = 6
DEVLINK_CMD_PORT_NEW = 7
DEVLINK_CMD_PORT_DEL = 8
DEVLINK_CMD_ESWITCH_GET = 29
DEVLINK_CMD_ESWITCH_SET = 30
DEVLINK_CMD_INFO_GET = 51
)
const (
DEVLINK_ATTR_BUS_NAME = 1
DEVLINK_ATTR_DEV_NAME = 2
DEVLINK_ATTR_PORT_INDEX = 3
DEVLINK_ATTR_PORT_TYPE = 4
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
DEVLINK_ATTR_ESWITCH_MODE = 25
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
DEVLINK_ATTR_PORT_FLAVOUR = 77
DEVLINK_ATTR_BUS_NAME = 1
DEVLINK_ATTR_DEV_NAME = 2
DEVLINK_ATTR_PORT_INDEX = 3
DEVLINK_ATTR_PORT_TYPE = 4
DEVLINK_ATTR_PORT_NETDEV_IFINDEX = 6
DEVLINK_ATTR_PORT_NETDEV_NAME = 7
DEVLINK_ATTR_PORT_IBDEV_NAME = 8
DEVLINK_ATTR_ESWITCH_MODE = 25
DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
DEVLINK_ATTR_PORT_FLAVOUR = 77
DEVLINK_ATTR_INFO_DRIVER_NAME = 98
DEVLINK_ATTR_INFO_SERIAL_NUMBER = 99
DEVLINK_ATTR_INFO_VERSION_FIXED = 100
DEVLINK_ATTR_INFO_VERSION_RUNNING = 101
DEVLINK_ATTR_INFO_VERSION_STORED = 102
DEVLINK_ATTR_INFO_VERSION_NAME = 103
DEVLINK_ATTR_INFO_VERSION_VALUE = 104
DEVLINK_ATTR_PORT_PCI_PF_NUMBER = 127
DEVLINK_ATTR_PORT_FUNCTION = 145
DEVLINK_ATTR_PORT_CONTROLLER_NUMBER = 150
DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 164
)
const (
@ -53,6 +68,8 @@ const (
DEVLINK_PORT_FLAVOUR_PCI_PF = 3
DEVLINK_PORT_FLAVOUR_PCI_VF = 4
DEVLINK_PORT_FLAVOUR_VIRTUAL = 5
DEVLINK_PORT_FLAVOUR_UNUSED = 6
DEVLINK_PORT_FLAVOUR_PCI_SF = 7
)
const (
@ -61,3 +78,19 @@ const (
DEVLINK_PORT_TYPE_ETH = 2
DEVLINK_PORT_TYPE_IB = 3
)
const (
DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR = 1
DEVLINK_PORT_FN_ATTR_STATE = 2
DEVLINK_PORT_FN_ATTR_OPSTATE = 3
)
const (
DEVLINK_PORT_FN_STATE_INACTIVE = 0
DEVLINK_PORT_FN_STATE_ACTIVE = 1
)
const (
DEVLINK_PORT_FN_OPSTATE_DETACHED = 0
DEVLINK_PORT_FN_OPSTATE_ATTACHED = 1
)

View File

@ -709,3 +709,12 @@ const (
IFLA_CAN_BITRATE_MAX
IFLA_CAN_MAX = IFLA_CAN_BITRATE_MAX
)
const (
IFLA_BAREUDP_UNSPEC = iota
IFLA_BAREUDP_PORT
IFLA_BAREUDP_ETHERTYPE
IFLA_BAREUDP_SRCPORT_MIN
IFLA_BAREUDP_MULTIPROTO_MODE
IFLA_BAREUDP_MAX = IFLA_BAREUDP_MULTIPROTO_MODE
)

29
vendor/github.com/vishvananda/netlink/nl/lwt_linux.go generated vendored Normal file
View File

@ -0,0 +1,29 @@
package nl
const (
LWT_BPF_PROG_UNSPEC = iota
LWT_BPF_PROG_FD
LWT_BPF_PROG_NAME
__LWT_BPF_PROG_MAX
)
const (
LWT_BPF_PROG_MAX = __LWT_BPF_PROG_MAX - 1
)
const (
LWT_BPF_UNSPEC = iota
LWT_BPF_IN
LWT_BPF_OUT
LWT_BPF_XMIT
LWT_BPF_XMIT_HEADROOM
__LWT_BPF_MAX
)
const (
LWT_BPF_MAX = __LWT_BPF_MAX - 1
)
const (
LWT_BPF_MAX_HEADROOM = 256
)

View File

@ -27,7 +27,8 @@ const (
// tc rules or filters, or other more memory requiring data.
RECEIVE_BUFFER_SIZE = 65536
// Kernel netlink pid
PidKernel uint32 = 0
PidKernel uint32 = 0
SizeofCnMsgOp = 0x18
)
// SupportedNlFamilies contains the list of netlink families this netlink package supports
@ -38,6 +39,9 @@ var nextSeqNr uint32
// Default netlink socket timeout, 60s
var SocketTimeoutTv = unix.Timeval{Sec: 60, Usec: 0}
// ErrorMessageReporting is the default error message reporting configuration for the new netlink sockets
var EnableErrorMessageReporting bool = false
// GetIPFamily returns the family type of a net.IP.
func GetIPFamily(ip net.IP) int {
if len(ip) <= net.IPv4len {
@ -80,11 +84,69 @@ func Swap32(i uint32) uint32 {
return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24
}
const (
NLMSGERR_ATTR_UNUSED = 0
NLMSGERR_ATTR_MSG = 1
NLMSGERR_ATTR_OFFS = 2
NLMSGERR_ATTR_COOKIE = 3
NLMSGERR_ATTR_POLICY = 4
)
type NetlinkRequestData interface {
Len() int
Serialize() []byte
}
const (
PROC_CN_MCAST_LISTEN = 1
PROC_CN_MCAST_IGNORE
)
type CbID struct {
Idx uint32
Val uint32
}
type CnMsg struct {
ID CbID
Seq uint32
Ack uint32
Length uint16
Flags uint16
}
type CnMsgOp struct {
CnMsg
// here we differ from the C header
Op uint32
}
func NewCnMsg(idx, val, op uint32) *CnMsgOp {
var cm CnMsgOp
cm.ID.Idx = idx
cm.ID.Val = val
cm.Ack = 0
cm.Seq = 1
cm.Length = uint16(binary.Size(op))
cm.Op = op
return &cm
}
func (msg *CnMsgOp) Serialize() []byte {
return (*(*[SizeofCnMsgOp]byte)(unsafe.Pointer(msg)))[:]
}
func DeserializeCnMsgOp(b []byte) *CnMsgOp {
return (*CnMsgOp)(unsafe.Pointer(&b[0:SizeofCnMsgOp][0]))
}
func (msg *CnMsgOp) Len() int {
return SizeofCnMsgOp
}
// IfInfomsg is related to links, but it is used for list requests as well
type IfInfomsg struct {
unix.IfInfomsg
@ -252,6 +314,12 @@ func (msg *IfInfomsg) EncapType() string {
return fmt.Sprintf("unknown%d", msg.Type)
}
// Round the length of a netlink message up to align it properly.
// Taken from syscall/netlink_linux.go by The Go Authors under BSD-style license.
func nlmAlignOf(msglen int) int {
return (msglen + syscall.NLMSG_ALIGNTO - 1) & ^(syscall.NLMSG_ALIGNTO - 1)
}
func rtaAlignOf(attrlen int) int {
return (attrlen + unix.RTA_ALIGNTO - 1) & ^(unix.RTA_ALIGNTO - 1)
}
@ -436,6 +504,11 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
if err := s.SetReceiveTimeout(&SocketTimeoutTv); err != nil {
return nil, err
}
if EnableErrorMessageReporting {
if err := s.SetExtAck(true); err != nil {
return nil, err
}
}
defer s.Close()
} else {
@ -475,11 +548,37 @@ done:
}
if m.Header.Type == unix.NLMSG_DONE || m.Header.Type == unix.NLMSG_ERROR {
native := NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
errno := int32(native.Uint32(m.Data[0:4]))
if errno == 0 {
break done
}
return nil, syscall.Errno(-error)
var err error
err = syscall.Errno(-errno)
unreadData := m.Data[4:]
if m.Header.Flags|unix.NLM_F_ACK_TLVS != 0 && len(unreadData) > syscall.SizeofNlMsghdr {
// Skip the echoed request message.
echoReqH := (*syscall.NlMsghdr)(unsafe.Pointer(&unreadData[0]))
unreadData = unreadData[nlmAlignOf(int(echoReqH.Len)):]
// Annotate `err` using nlmsgerr attributes.
for len(unreadData) >= syscall.SizeofRtAttr {
attr := (*syscall.RtAttr)(unsafe.Pointer(&unreadData[0]))
attrData := unreadData[syscall.SizeofRtAttr:attr.Len]
switch attr.Type {
case NLMSGERR_ATTR_MSG:
err = fmt.Errorf("%w: %s", err, string(attrData))
default:
// TODO: handle other NLMSGERR_ATTR types
}
unreadData = unreadData[rtaAlignOf(int(attr.Len)):]
}
}
return nil, err
}
if resType != 0 && m.Header.Type != resType {
continue
@ -694,6 +793,16 @@ func (s *NetlinkSocket) SetReceiveTimeout(timeout *unix.Timeval) error {
return unix.SetsockoptTimeval(int(s.fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, timeout)
}
// SetExtAck requests error messages to be reported on the socket
func (s *NetlinkSocket) SetExtAck(enable bool) error {
var enableN int
if enable {
enableN = 1
}
return unix.SetsockoptInt(int(s.fd), unix.SOL_NETLINK, unix.NETLINK_EXT_ACK, enableN)
}
func (s *NetlinkSocket) GetPid() (uint32, error) {
fd := int(atomic.LoadInt32(&s.fd))
lsa, err := unix.Getsockname(fd)

View File

@ -11,6 +11,8 @@ const (
const (
RDMA_NLDEV_CMD_GET = 1
RDMA_NLDEV_CMD_SET = 2
RDMA_NLDEV_CMD_NEWLINK = 3
RDMA_NLDEV_CMD_DELLINK = 4
RDMA_NLDEV_CMD_SYS_GET = 6
RDMA_NLDEV_CMD_SYS_SET = 7
)
@ -30,6 +32,8 @@ const (
RDMA_NLDEV_ATTR_PORT_STATE = 12
RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13
RDMA_NLDEV_ATTR_DEV_NODE_TYPE = 14
RDMA_NLDEV_ATTR_NDEV_NAME = 51
RDMA_NLDEV_ATTR_LINK_TYPE = 65
RDMA_NLDEV_SYS_ATTR_NETNS_MODE = 66
RDMA_NLDEV_NET_NS_FD = 68
)

View File

@ -23,7 +23,7 @@ func (s1 *IPv6SrHdr) Equal(s2 IPv6SrHdr) bool {
return false
}
for i := range s1.Segments {
if s1.Segments[i].Equal(s2.Segments[i]) != true {
if !s1.Segments[i].Equal(s2.Segments[i]) {
return false
}
}
@ -89,7 +89,7 @@ func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) {
}
buf = buf[12:]
if len(buf)%16 != 0 {
err := fmt.Errorf("DecodeSEG6Encap: error parsing Segment List (buf len: %d)\n", len(buf))
err := fmt.Errorf("DecodeSEG6Encap: error parsing Segment List (buf len: %d)", len(buf))
return mode, nil, err
}
for len(buf) > 0 {

View File

@ -1,6 +1,6 @@
package nl
// syscall package lack of rule atributes type.
// syscall package lack of rule attributes type.
// Thus there are defined below
const (
FRA_UNSPEC = iota

View File

@ -90,6 +90,7 @@ const (
SizeofTcU32Sel = 0x10 // without keys
SizeofTcGen = 0x14
SizeofTcConnmark = SizeofTcGen + 0x04
SizeofTcCsum = SizeofTcGen + 0x04
SizeofTcMirred = SizeofTcGen + 0x08
SizeofTcTunnelKey = SizeofTcGen + 0x04
SizeofTcSkbEdit = SizeofTcGen
@ -694,6 +695,36 @@ func (x *TcConnmark) Serialize() []byte {
return (*(*[SizeofTcConnmark]byte)(unsafe.Pointer(x)))[:]
}
const (
TCA_CSUM_UNSPEC = iota
TCA_CSUM_PARMS
TCA_CSUM_TM
TCA_CSUM_PAD
TCA_CSUM_MAX = TCA_CSUM_PAD
)
// struct tc_csum {
// tc_gen;
// __u32 update_flags;
// }
type TcCsum struct {
TcGen
UpdateFlags uint32
}
func (msg *TcCsum) Len() int {
return SizeofTcCsum
}
func DeserializeTcCsum(b []byte) *TcCsum {
return (*TcCsum)(unsafe.Pointer(&b[0:SizeofTcCsum][0]))
}
func (x *TcCsum) Serialize() []byte {
return (*(*[SizeofTcCsum]byte)(unsafe.Pointer(x)))[:]
}
const (
TCA_ACT_MIRRED = 8
)
@ -882,6 +913,111 @@ const (
TCA_HFSC_USC
)
const (
TCA_FLOWER_UNSPEC = iota
TCA_FLOWER_CLASSID
TCA_FLOWER_INDEV
TCA_FLOWER_ACT
TCA_FLOWER_KEY_ETH_DST /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_DST_MASK /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_SRC /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_SRC_MASK /* ETH_ALEN */
TCA_FLOWER_KEY_ETH_TYPE /* be16 */
TCA_FLOWER_KEY_IP_PROTO /* u8 */
TCA_FLOWER_KEY_IPV4_SRC /* be32 */
TCA_FLOWER_KEY_IPV4_SRC_MASK /* be32 */
TCA_FLOWER_KEY_IPV4_DST /* be32 */
TCA_FLOWER_KEY_IPV4_DST_MASK /* be32 */
TCA_FLOWER_KEY_IPV6_SRC /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_SRC_MASK /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_DST /* struct in6_addr */
TCA_FLOWER_KEY_IPV6_DST_MASK /* struct in6_addr */
TCA_FLOWER_KEY_TCP_SRC /* be16 */
TCA_FLOWER_KEY_TCP_DST /* be16 */
TCA_FLOWER_KEY_UDP_SRC /* be16 */
TCA_FLOWER_KEY_UDP_DST /* be16 */
TCA_FLOWER_FLAGS
TCA_FLOWER_KEY_VLAN_ID /* be16 */
TCA_FLOWER_KEY_VLAN_PRIO /* u8 */
TCA_FLOWER_KEY_VLAN_ETH_TYPE /* be16 */
TCA_FLOWER_KEY_ENC_KEY_ID /* be32 */
TCA_FLOWER_KEY_ENC_IPV4_SRC /* be32 */
TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK /* be32 */
TCA_FLOWER_KEY_ENC_IPV4_DST /* be32 */
TCA_FLOWER_KEY_ENC_IPV4_DST_MASK /* be32 */
TCA_FLOWER_KEY_ENC_IPV6_SRC /* struct in6_addr */
TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK /* struct in6_addr */
TCA_FLOWER_KEY_ENC_IPV6_DST /* struct in6_addr */
TCA_FLOWER_KEY_ENC_IPV6_DST_MASK /* struct in6_addr */
TCA_FLOWER_KEY_TCP_SRC_MASK /* be16 */
TCA_FLOWER_KEY_TCP_DST_MASK /* be16 */
TCA_FLOWER_KEY_UDP_SRC_MASK /* be16 */
TCA_FLOWER_KEY_UDP_DST_MASK /* be16 */
TCA_FLOWER_KEY_SCTP_SRC_MASK /* be16 */
TCA_FLOWER_KEY_SCTP_DST_MASK /* be16 */
TCA_FLOWER_KEY_SCTP_SRC /* be16 */
TCA_FLOWER_KEY_SCTP_DST /* be16 */
TCA_FLOWER_KEY_ENC_UDP_SRC_PORT /* be16 */
TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK /* be16 */
TCA_FLOWER_KEY_ENC_UDP_DST_PORT /* be16 */
TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK /* be16 */
TCA_FLOWER_KEY_FLAGS /* be32 */
TCA_FLOWER_KEY_FLAGS_MASK /* be32 */
TCA_FLOWER_KEY_ICMPV4_CODE /* u8 */
TCA_FLOWER_KEY_ICMPV4_CODE_MASK /* u8 */
TCA_FLOWER_KEY_ICMPV4_TYPE /* u8 */
TCA_FLOWER_KEY_ICMPV4_TYPE_MASK /* u8 */
TCA_FLOWER_KEY_ICMPV6_CODE /* u8 */
TCA_FLOWER_KEY_ICMPV6_CODE_MASK /* u8 */
TCA_FLOWER_KEY_ICMPV6_TYPE /* u8 */
TCA_FLOWER_KEY_ICMPV6_TYPE_MASK /* u8 */
TCA_FLOWER_KEY_ARP_SIP /* be32 */
TCA_FLOWER_KEY_ARP_SIP_MASK /* be32 */
TCA_FLOWER_KEY_ARP_TIP /* be32 */
TCA_FLOWER_KEY_ARP_TIP_MASK /* be32 */
TCA_FLOWER_KEY_ARP_OP /* u8 */
TCA_FLOWER_KEY_ARP_OP_MASK /* u8 */
TCA_FLOWER_KEY_ARP_SHA /* ETH_ALEN */
TCA_FLOWER_KEY_ARP_SHA_MASK /* ETH_ALEN */
TCA_FLOWER_KEY_ARP_THA /* ETH_ALEN */
TCA_FLOWER_KEY_ARP_THA_MASK /* ETH_ALEN */
TCA_FLOWER_KEY_MPLS_TTL /* u8 - 8 bits */
TCA_FLOWER_KEY_MPLS_BOS /* u8 - 1 bit */
TCA_FLOWER_KEY_MPLS_TC /* u8 - 3 bits */
TCA_FLOWER_KEY_MPLS_LABEL /* be32 - 20 bits */
TCA_FLOWER_KEY_TCP_FLAGS /* be16 */
TCA_FLOWER_KEY_TCP_FLAGS_MASK /* be16 */
TCA_FLOWER_KEY_IP_TOS /* u8 */
TCA_FLOWER_KEY_IP_TOS_MASK /* u8 */
TCA_FLOWER_KEY_IP_TTL /* u8 */
TCA_FLOWER_KEY_IP_TTL_MASK /* u8 */
TCA_FLOWER_KEY_CVLAN_ID /* be16 */
TCA_FLOWER_KEY_CVLAN_PRIO /* u8 */
TCA_FLOWER_KEY_CVLAN_ETH_TYPE /* be16 */
TCA_FLOWER_KEY_ENC_IP_TOS /* u8 */
TCA_FLOWER_KEY_ENC_IP_TOS_MASK /* u8 */
TCA_FLOWER_KEY_ENC_IP_TTL /* u8 */
TCA_FLOWER_KEY_ENC_IP_TTL_MASK /* u8 */
TCA_FLOWER_KEY_ENC_OPTS
TCA_FLOWER_KEY_ENC_OPTS_MASK
__TCA_FLOWER_MAX
)
// struct tc_sfq_qopt {
// unsigned quantum; /* Bytes per round allocated to flow */
// int perturb_period; /* Period of hash perturbation */

View File

@ -0,0 +1,217 @@
package netlink
import (
"bytes"
"encoding/binary"
"fmt"
"os"
"syscall"
"github.com/vishvananda/netlink/nl"
"github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
const CN_IDX_PROC = 0x1
const (
PROC_EVENT_NONE = 0x00000000
PROC_EVENT_FORK = 0x00000001
PROC_EVENT_EXEC = 0x00000002
PROC_EVENT_UID = 0x00000004
PROC_EVENT_GID = 0x00000040
PROC_EVENT_SID = 0x00000080
PROC_EVENT_PTRACE = 0x00000100
PROC_EVENT_COMM = 0x00000200
PROC_EVENT_COREDUMP = 0x40000000
PROC_EVENT_EXIT = 0x80000000
)
const (
CN_VAL_PROC = 0x1
PROC_CN_MCAST_LISTEN = 0x1
)
type ProcEventMsg interface {
Pid() uint32
Tgid() uint32
}
type ProcEventHeader struct {
What uint32
CPU uint32
Timestamp uint64
}
type ProcEvent struct {
ProcEventHeader
Msg ProcEventMsg
}
func (pe *ProcEvent) setHeader(h ProcEventHeader) {
pe.What = h.What
pe.CPU = h.CPU
pe.Timestamp = h.Timestamp
}
type ExitProcEvent struct {
ProcessPid uint32
ProcessTgid uint32
ExitCode uint32
ExitSignal uint32
ParentPid uint32
ParentTgid uint32
}
type ExitProcEvent2 struct {
ProcessPid uint32
ProcessTgid uint32
ExitCode uint32
ExitSignal uint32
ParentPid uint32
ParentTgid uint32
}
func (e *ExitProcEvent) Pid() uint32 {
return e.ProcessPid
}
func (e *ExitProcEvent) Tgid() uint32 {
return e.ProcessTgid
}
type ExecProcEvent struct {
ProcessPid uint32
ProcessTgid uint32
}
func (e *ExecProcEvent) Pid() uint32 {
return e.ProcessPid
}
func (e *ExecProcEvent) Tgid() uint32 {
return e.ProcessTgid
}
type ForkProcEvent struct {
ParentPid uint32
ParentTgid uint32
ChildPid uint32
ChildTgid uint32
}
func (e *ForkProcEvent) Pid() uint32 {
return e.ParentPid
}
func (e *ForkProcEvent) Tgid() uint32 {
return e.ParentTgid
}
type CommProcEvent struct {
ProcessPid uint32
ProcessTgid uint32
Comm [16]byte
}
func (e *CommProcEvent) Pid() uint32 {
return e.ProcessPid
}
func (e *CommProcEvent) Tgid() uint32 {
return e.ProcessTgid
}
func ProcEventMonitor(ch chan<- ProcEvent, done <-chan struct{}, errorChan chan<- error) error {
h, err := NewHandle()
if err != nil {
return err
}
defer h.Delete()
s, err := nl.SubscribeAt(netns.None(), netns.None(), unix.NETLINK_CONNECTOR, CN_IDX_PROC)
if err != nil {
return err
}
var nlmsg nl.NetlinkRequest
nlmsg.Pid = uint32(os.Getpid())
nlmsg.Type = unix.NLMSG_DONE
nlmsg.Len = uint32(unix.SizeofNlMsghdr)
cm := nl.NewCnMsg(CN_IDX_PROC, CN_VAL_PROC, PROC_CN_MCAST_LISTEN)
nlmsg.AddData(cm)
s.Send(&nlmsg)
if done != nil {
go func() {
<-done
s.Close()
}()
}
go func() {
defer close(ch)
for {
msgs, from, err := s.Receive()
if err != nil {
errorChan <- err
return
}
if from.Pid != nl.PidKernel {
errorChan <- fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
return
}
for _, m := range msgs {
e := parseNetlinkMessage(m)
if e != nil {
ch <- *e
}
}
}
}()
return nil
}
func parseNetlinkMessage(m syscall.NetlinkMessage) *ProcEvent {
if m.Header.Type == unix.NLMSG_DONE {
buf := bytes.NewBuffer(m.Data)
msg := &nl.CnMsg{}
hdr := &ProcEventHeader{}
binary.Read(buf, nl.NativeEndian(), msg)
binary.Read(buf, nl.NativeEndian(), hdr)
pe := &ProcEvent{}
pe.setHeader(*hdr)
switch hdr.What {
case PROC_EVENT_EXIT:
event := &ExitProcEvent{}
binary.Read(buf, nl.NativeEndian(), event)
pe.Msg = event
return pe
case PROC_EVENT_FORK:
event := &ForkProcEvent{}
binary.Read(buf, nl.NativeEndian(), event)
pe.Msg = event
return pe
case PROC_EVENT_EXEC:
event := &ExecProcEvent{}
binary.Read(buf, nl.NativeEndian(), event)
pe.Msg = event
return pe
case PROC_EVENT_COMM:
event := &CommProcEvent{}
binary.Read(buf, nl.NativeEndian(), event)
pe.Msg = event
return pe
}
return nil
}
return nil
}

View File

@ -468,7 +468,6 @@ func parsePrioData(qdisc Qdisc, value []byte) error {
}
func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
htb := qdisc.(*Htb)
for _, datum := range data {
switch datum.Attr.Type {
@ -488,7 +487,6 @@ func parseHtbData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
}
func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fqCodel := qdisc.(*FqCodel)
for _, datum := range data {
@ -518,13 +516,11 @@ func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
func parseHfscData(qdisc Qdisc, data []byte) error {
Hfsc := qdisc.(*Hfsc)
native = nl.NativeEndian()
Hfsc.Defcls = native.Uint16(data)
return nil
}
func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fq := qdisc.(*Fq)
for _, datum := range data {
switch datum.Attr.Type {
@ -589,7 +585,6 @@ func parseNetemData(qdisc Qdisc, value []byte) error {
}
func parseTbfData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
tbf := qdisc.(*Tbf)
for _, datum := range data {
switch datum.Attr.Type {
@ -711,3 +706,7 @@ func Xmittime(rate uint64, size uint32) uint32 {
// https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/tree/tc/tc_core.c#n62
return time2Tick(uint32(TIME_UNITS_PER_SEC * (float64(size) / float64(rate))))
}
func Xmitsize(rate uint64, ticks uint32) uint32 {
return uint32((float64(rate) * float64(tick2Time(ticks))) / TIME_UNITS_PER_SEC)
}

View File

@ -278,3 +278,54 @@ func (h *Handle) RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
return execRdmaSetLink(req)
}
// RdmaLinkDel deletes an rdma link
//
// Similar to: rdma link delete NAME
// REF: https://man7.org/linux/man-pages/man8/rdma-link.8.html
func RdmaLinkDel(name string) error {
return pkgHandle.RdmaLinkDel(name)
}
// RdmaLinkDel deletes an rdma link.
func (h *Handle) RdmaLinkDel(name string) error {
link, err := h.RdmaLinkByName(name)
if err != nil {
return err
}
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_DELLINK)
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
b := make([]byte, 4)
native.PutUint32(b, link.Attrs.Index)
req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b))
_, err = req.Execute(unix.NETLINK_RDMA, 0)
return err
}
// RdmaLinkAdd adds an rdma link for the specified type to the network device.
// Similar to: rdma link add NAME type TYPE netdev NETDEV
// NAME - specifies the new name of the rdma link to add
// TYPE - specifies which rdma type to use. Link types:
// rxe - Soft RoCE driver
// siw - Soft iWARP driver
// NETDEV - specifies the network device to which the link is bound
//
// REF: https://man7.org/linux/man-pages/man8/rdma-link.8.html
func RdmaLinkAdd(linkName, linkType, netdev string) error {
return pkgHandle.RdmaLinkAdd(linkName, linkType, netdev)
}
// RdmaLinkAdd adds an rdma link for the specified type to the network device.
func (h *Handle) RdmaLinkAdd(linkName string, linkType string, netdev string) error {
proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_NEWLINK)
req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, nl.ZeroTerminated(linkName)))
req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_LINK_TYPE, nl.ZeroTerminated(linkType)))
req.AddData(nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_NDEV_NAME, nl.ZeroTerminated(netdev)))
_, err := req.Execute(unix.NETLINK_RDMA, 0)
return err
}

View File

@ -11,6 +11,24 @@ type Scope uint8
type NextHopFlag int
const (
RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota)
RT_FILTER_SCOPE
RT_FILTER_TYPE
RT_FILTER_TOS
RT_FILTER_IIF
RT_FILTER_OIF
RT_FILTER_DST
RT_FILTER_SRC
RT_FILTER_GW
RT_FILTER_TABLE
RT_FILTER_HOPLIMIT
RT_FILTER_PRIORITY
RT_FILTER_MARK
RT_FILTER_MASK
RT_FILTER_REALM
)
type Destination interface {
Family() int
Decode([]byte) error
@ -41,6 +59,7 @@ type Route struct {
MultiPath []*NexthopInfo
Protocol RouteProtocol
Priority int
Family int
Table int
Type int
Tos int
@ -49,6 +68,7 @@ type Route struct {
NewDst Destination
Encap Encap
Via Destination
Realm int
MTU int
Window int
Rtt int
@ -94,6 +114,7 @@ func (r Route) String() string {
}
elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags()))
elems = append(elems, fmt.Sprintf("Table: %d", r.Table))
elems = append(elems, fmt.Sprintf("Realm: %d", r.Realm))
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
}
@ -107,6 +128,7 @@ func (r Route) Equal(x Route) bool {
nexthopInfoSlice(r.MultiPath).Equal(x.MultiPath) &&
r.Protocol == x.Protocol &&
r.Priority == x.Priority &&
r.Realm == x.Realm &&
r.Table == x.Table &&
r.Type == x.Type &&
r.Tos == x.Tos &&

View File

@ -41,22 +41,6 @@ func (s Scope) String() string {
}
}
const (
RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota)
RT_FILTER_SCOPE
RT_FILTER_TYPE
RT_FILTER_TOS
RT_FILTER_IIF
RT_FILTER_OIF
RT_FILTER_DST
RT_FILTER_SRC
RT_FILTER_GW
RT_FILTER_TABLE
RT_FILTER_HOPLIMIT
RT_FILTER_PRIORITY
RT_FILTER_MARK
RT_FILTER_MASK
)
const (
FLAG_ONLINK NextHopFlag = unix.RTNH_F_ONLINK
@ -151,7 +135,6 @@ func (e *MPLSEncap) Decode(buf []byte) error {
if len(buf) < 4 {
return fmt.Errorf("lack of bytes")
}
native := nl.NativeEndian()
l := native.Uint16(buf)
if len(buf) < int(l) {
return fmt.Errorf("lack of bytes")
@ -167,7 +150,6 @@ func (e *MPLSEncap) Decode(buf []byte) error {
func (e *MPLSEncap) Encode() ([]byte, error) {
s := nl.EncodeMPLSStack(e.Labels...)
native := nl.NativeEndian()
hdr := make([]byte, 4)
native.PutUint16(hdr, uint16(len(s)+4))
native.PutUint16(hdr[2:], nl.MPLS_IPTUNNEL_DST)
@ -223,7 +205,6 @@ func (e *SEG6Encap) Decode(buf []byte) error {
if len(buf) < 4 {
return fmt.Errorf("lack of bytes")
}
native := nl.NativeEndian()
// Get Length(l) & Type(typ) : 2 + 2 bytes
l := native.Uint16(buf)
if len(buf) < int(l) {
@ -243,7 +224,6 @@ func (e *SEG6Encap) Decode(buf []byte) error {
}
func (e *SEG6Encap) Encode() ([]byte, error) {
s, err := nl.EncodeSEG6Encap(e.Mode, e.Segments)
native := nl.NativeEndian()
hdr := make([]byte, 4)
native.PutUint16(hdr, uint16(len(s)+4))
native.PutUint16(hdr[2:], nl.SEG6_IPTUNNEL_SRH)
@ -253,7 +233,7 @@ func (e *SEG6Encap) String() string {
segs := make([]string, 0, len(e.Segments))
// append segment backwards (from n to 0) since seg#0 is the last segment.
for i := len(e.Segments); i > 0; i-- {
segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1]))
segs = append(segs, e.Segments[i-1].String())
}
str := fmt.Sprintf("mode %s segs %d [ %s ]", nl.SEG6EncapModeString(e.Mode),
len(e.Segments), strings.Join(segs, " "))
@ -304,7 +284,6 @@ func (e *SEG6LocalEncap) Decode(buf []byte) error {
if err != nil {
return err
}
native := nl.NativeEndian()
for _, attr := range attrs {
switch attr.Attr.Type {
case nl.SEG6_LOCAL_ACTION:
@ -334,7 +313,6 @@ func (e *SEG6LocalEncap) Decode(buf []byte) error {
}
func (e *SEG6LocalEncap) Encode() ([]byte, error) {
var err error
native := nl.NativeEndian()
res := make([]byte, 8)
native.PutUint16(res, 8) // length
native.PutUint16(res[2:], nl.SEG6_LOCAL_ACTION)
@ -425,7 +403,7 @@ func (e *SEG6LocalEncap) String() string {
segs := make([]string, 0, len(e.Segments))
//append segment backwards (from n to 0) since seg#0 is the last segment.
for i := len(e.Segments); i > 0; i-- {
segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1]))
segs = append(segs, e.Segments[i-1].String())
}
strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " ")))
}
@ -466,6 +444,152 @@ func (e *SEG6LocalEncap) Equal(x Encap) bool {
return true
}
// Encap BPF definitions
type bpfObj struct {
progFd int
progName string
}
type BpfEncap struct {
progs [nl.LWT_BPF_MAX]bpfObj
headroom int
}
// SetProg adds a bpf function to the route via netlink RTA_ENCAP. The fd must be a bpf
// program loaded with bpf(type=BPF_PROG_TYPE_LWT_*) matching the direction the program should
// be applied to (LWT_BPF_IN, LWT_BPF_OUT, LWT_BPF_XMIT).
func (e *BpfEncap) SetProg(mode, progFd int, progName string) error {
if progFd <= 0 {
return fmt.Errorf("lwt bpf SetProg: invalid fd")
}
if mode <= nl.LWT_BPF_UNSPEC || mode >= nl.LWT_BPF_XMIT_HEADROOM {
return fmt.Errorf("lwt bpf SetProg:invalid mode")
}
e.progs[mode].progFd = progFd
e.progs[mode].progName = fmt.Sprintf("%s[fd:%d]", progName, progFd)
return nil
}
// SetXmitHeadroom sets the xmit headroom (LWT_BPF_MAX_HEADROOM) via netlink RTA_ENCAP.
// maximum headroom is LWT_BPF_MAX_HEADROOM
func (e *BpfEncap) SetXmitHeadroom(headroom int) error {
if headroom > nl.LWT_BPF_MAX_HEADROOM || headroom < 0 {
return fmt.Errorf("invalid headroom size. range is 0 - %d", nl.LWT_BPF_MAX_HEADROOM)
}
e.headroom = headroom
return nil
}
func (e *BpfEncap) Type() int {
return nl.LWTUNNEL_ENCAP_BPF
}
func (e *BpfEncap) Decode(buf []byte) error {
if len(buf) < 4 {
return fmt.Errorf("lwt bpf decode: lack of bytes")
}
native := nl.NativeEndian()
attrs, err := nl.ParseRouteAttr(buf)
if err != nil {
return fmt.Errorf("lwt bpf decode: failed parsing attribute. err: %v", err)
}
for _, attr := range attrs {
if int(attr.Attr.Type) < 1 {
// nl.LWT_BPF_UNSPEC
continue
}
if int(attr.Attr.Type) > nl.LWT_BPF_MAX {
return fmt.Errorf("lwt bpf decode: received unknown attribute type: %d", attr.Attr.Type)
}
switch int(attr.Attr.Type) {
case nl.LWT_BPF_MAX_HEADROOM:
e.headroom = int(native.Uint32(attr.Value))
default:
bpfO := bpfObj{}
parsedAttrs, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
return fmt.Errorf("lwt bpf decode: failed parsing route attribute")
}
for _, parsedAttr := range parsedAttrs {
switch int(parsedAttr.Attr.Type) {
case nl.LWT_BPF_PROG_FD:
bpfO.progFd = int(native.Uint32(parsedAttr.Value))
case nl.LWT_BPF_PROG_NAME:
bpfO.progName = string(parsedAttr.Value)
default:
return fmt.Errorf("lwt bpf decode: received unknown attribute: type: %d, len: %d", parsedAttr.Attr.Type, parsedAttr.Attr.Len)
}
}
e.progs[attr.Attr.Type] = bpfO
}
}
return nil
}
func (e *BpfEncap) Encode() ([]byte, error) {
buf := make([]byte, 0)
native = nl.NativeEndian()
for index, attr := range e.progs {
nlMsg := nl.NewRtAttr(index, []byte{})
if attr.progFd != 0 {
nlMsg.AddRtAttr(nl.LWT_BPF_PROG_FD, nl.Uint32Attr(uint32(attr.progFd)))
}
if attr.progName != "" {
nlMsg.AddRtAttr(nl.LWT_BPF_PROG_NAME, nl.ZeroTerminated(attr.progName))
}
if nlMsg.Len() > 4 {
buf = append(buf, nlMsg.Serialize()...)
}
}
if len(buf) <= 4 {
return nil, fmt.Errorf("lwt bpf encode: bpf obj definitions returned empty buffer")
}
if e.headroom > 0 {
hRoom := nl.NewRtAttr(nl.LWT_BPF_XMIT_HEADROOM, nl.Uint32Attr(uint32(e.headroom)))
buf = append(buf, hRoom.Serialize()...)
}
return buf, nil
}
func (e *BpfEncap) String() string {
progs := make([]string, 0)
for index, obj := range e.progs {
empty := bpfObj{}
switch index {
case nl.LWT_BPF_IN:
if obj != empty {
progs = append(progs, fmt.Sprintf("in: %s", obj.progName))
}
case nl.LWT_BPF_OUT:
if obj != empty {
progs = append(progs, fmt.Sprintf("out: %s", obj.progName))
}
case nl.LWT_BPF_XMIT:
if obj != empty {
progs = append(progs, fmt.Sprintf("xmit: %s", obj.progName))
}
}
}
if e.headroom > 0 {
progs = append(progs, fmt.Sprintf("xmit headroom: %d", e.headroom))
}
return strings.Join(progs, " ")
}
func (e *BpfEncap) Equal(x Encap) bool {
o, ok := x.(*BpfEncap)
if !ok {
return false
}
if e.headroom != o.headroom {
return false
}
for i := range o.progs {
if o.progs[i] != e.progs[i] {
return false
}
}
return true
}
type Via struct {
AddrFamily int
Addr net.IP
@ -504,7 +628,6 @@ func (v *Via) Encode() ([]byte, error) {
}
func (v *Via) Decode(b []byte) error {
native := nl.NativeEndian()
if len(b) < 6 {
return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b))
}
@ -552,14 +675,14 @@ func (h *Handle) RouteAppend(route *Route) error {
// RouteAddEcmp will add a route to the system.
func RouteAddEcmp(route *Route) error {
return pkgHandle.RouteAddEcmp(route)
return pkgHandle.RouteAddEcmp(route)
}
// RouteAddEcmp will add a route to the system.
func (h *Handle) RouteAddEcmp(route *Route) error {
flags := unix.NLM_F_CREATE | unix.NLM_F_ACK
req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
flags := unix.NLM_F_CREATE | unix.NLM_F_ACK
req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags)
return h.routeHandle(route, req, nl.NewRtMsg())
}
// RouteReplace will add a route to the system.
@ -635,7 +758,13 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
if err != nil {
return err
}
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP, buf))
switch route.Encap.Type() {
case nl.LWTUNNEL_ENCAP_BPF:
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP|unix.NLA_F_NESTED, buf))
default:
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP, buf))
}
}
if route.Src != nil {
@ -748,6 +877,11 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
native.PutUint32(b, uint32(route.Priority))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PRIORITY, b))
}
if route.Realm > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(route.Realm))
rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_FLOW, b))
}
if route.Tos > 0 {
msg.Tos = uint8(route.Tos)
}
@ -840,10 +974,7 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
req.AddData(attr)
}
var (
b = make([]byte, 4)
native = nl.NativeEndian()
)
b := make([]byte, 4)
native.PutUint32(b, uint32(route.LinkIndex))
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
@ -882,8 +1013,9 @@ func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, e
// All rules must be defined in RouteFilter struct
func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP)
infmsg := nl.NewIfInfomsg(family)
req.AddData(infmsg)
rtmsg := nl.NewRtMsg()
rtmsg.Family = uint8(family)
req.AddData(rtmsg)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE)
if err != nil {
@ -919,6 +1051,8 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
continue
case filterMask&RT_FILTER_TOS != 0 && route.Tos != filter.Tos:
continue
case filterMask&RT_FILTER_REALM != 0 && route.Realm != filter.Realm:
continue
case filterMask&RT_FILTER_OIF != 0 && route.LinkIndex != filter.LinkIndex:
continue
case filterMask&RT_FILTER_IIF != 0 && route.ILinkIndex != filter.ILinkIndex:
@ -956,9 +1090,9 @@ func deserializeRoute(m []byte) (Route, error) {
Type: int(msg.Type),
Tos: int(msg.Tos),
Flags: int(msg.Flags),
Family: int(msg.Family),
}
native := nl.NativeEndian()
var encap, encapType syscall.NetlinkRouteAttr
for _, attr := range attrs {
switch attr.Attr.Type {
@ -985,6 +1119,8 @@ func deserializeRoute(m []byte) (Route, error) {
route.ILinkIndex = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_PRIORITY:
route.Priority = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_FLOW:
route.Realm = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_TABLE:
route.Table = int(native.Uint32(attr.Value[0:4]))
case unix.RTA_MULTIPATH:
@ -1140,6 +1276,11 @@ func deserializeRoute(m []byte) (Route, error) {
if err := e.Decode(encap.Value); err != nil {
return route, err
}
case nl.LWTUNNEL_ENCAP_BPF:
e = &BpfEncap{}
if err := e.Decode(encap.Value); err != nil {
return route, err
}
}
route.Encap = e
}
@ -1150,6 +1291,8 @@ func deserializeRoute(m []byte) (Route, error) {
// RouteGetOptions contains a set of options to use with
// RouteGetWithOptions
type RouteGetOptions struct {
Iif string
Oif string
VrfName string
SrcAddr net.IP
}
@ -1198,10 +1341,31 @@ func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOption
if err != nil {
return nil, err
}
var (
b = make([]byte, 4)
native = nl.NativeEndian()
)
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs().Index))
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
}
if len(options.Iif) > 0 {
link, err := LinkByName(options.Iif)
if err != nil {
return nil, err
}
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs().Index))
req.AddData(nl.NewRtAttr(unix.RTA_IIF, b))
}
if len(options.Oif) > 0 {
link, err := LinkByName(options.Oif)
if err != nil {
return nil, err
}
b := make([]byte, 4)
native.PutUint32(b, uint32(link.Attrs().Index))
req.AddData(nl.NewRtAttr(unix.RTA_OIF, b))
@ -1298,7 +1462,8 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
msgs, from, err := s.Receive()
if err != nil {
if cberr != nil {
cberr(err)
cberr(fmt.Errorf("Receive failed: %v",
err))
}
return
}
@ -1313,22 +1478,22 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
continue
}
if m.Header.Type == unix.NLMSG_ERROR {
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
if error == 0 {
continue
}
if cberr != nil {
cberr(syscall.Errno(-error))
cberr(fmt.Errorf("error message: %v",
syscall.Errno(-error)))
}
return
continue
}
route, err := deserializeRoute(m.Data)
if err != nil {
if cberr != nil {
cberr(err)
}
return
continue
}
ch <- RouteUpdate{Type: m.Header.Type, Route: route}
}

View File

@ -25,10 +25,22 @@ type Rule struct {
Invert bool
Dport *RulePortRange
Sport *RulePortRange
IPProto int
}
func (r Rule) String() string {
return fmt.Sprintf("ip rule %d: from %s table %d", r.Priority, r.Src, r.Table)
from := "all"
if r.Src != nil && r.Src.String() != "<nil>" {
from = r.Src.String()
}
to := "all"
if r.Dst != nil && r.Dst.String() != "<nil>" {
to = r.Dst.String()
}
return fmt.Sprintf("ip rule %d: from %s to %s table %d",
r.Priority, from, to, r.Table)
}
// NewRule return empty rules.

View File

@ -97,8 +97,6 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
req.AddData(rtAttrs[i])
}
native := nl.NativeEndian()
if rule.Priority >= 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(rule.Priority))
@ -154,6 +152,12 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))
}
if rule.IPProto > 0 {
b := make([]byte, 4)
native.PutUint32(b, uint32(rule.IPProto))
req.AddData(nl.NewRtAttr(nl.FRA_IP_PROTO, b))
}
if rule.Dport != nil {
b := rule.Dport.toRtAttrData()
req.AddData(nl.NewRtAttr(nl.FRA_DPORT_RANGE, b))
@ -199,7 +203,6 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
return nil, err
}
native := nl.NativeEndian()
var res = make([]Rule, 0)
for i := range msgs {
msg := nl.DeserializeRtMsg(msgs[i])
@ -232,7 +235,7 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
case nl.FRA_FWMASK:
rule.Mask = int(native.Uint32(attrs[j].Value[0:4]))
case nl.FRA_TUN_ID:
rule.TunID = uint(native.Uint64(attrs[j].Value[0:4]))
rule.TunID = uint(native.Uint64(attrs[j].Value[0:8]))
case nl.FRA_IIFNAME:
rule.IifName = string(attrs[j].Value[:len(attrs[j].Value)-1])
case nl.FRA_OIFNAME:
@ -253,6 +256,8 @@ func (h *Handle) RuleListFiltered(family int, filter *Rule, filterMask uint64) (
rule.Goto = int(native.Uint32(attrs[j].Value[0:4]))
case nl.FRA_PRIORITY:
rule.Priority = int(native.Uint32(attrs[j].Value[0:4]))
case nl.FRA_IP_PROTO:
rule.IPProto = int(native.Uint32(attrs[j].Value[0:4]))
case nl.FRA_DPORT_RANGE:
rule.Dport = NewRulePortRange(native.Uint16(attrs[j].Value[0:2]), native.Uint16(attrs[j].Value[2:4]))
case nl.FRA_SPORT_RANGE:

View File

@ -172,12 +172,56 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
return sock, nil
}
// SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type.
// SocketDiagTCPInfo requests INET_DIAG_INFO for TCP protocol for specified family type and return with extension TCP info.
func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
var result []*InetDiagTCPInfoResp
err := socketDiagTCPExecutor(family, func(m syscall.NetlinkMessage) error {
sockInfo := &Socket{}
if err := sockInfo.deserialize(m.Data); err != nil {
return err
}
attrs, err := nl.ParseRouteAttr(m.Data[sizeofSocket:])
if err != nil {
return err
}
res, err := attrsToInetDiagTCPInfoResp(attrs, sockInfo)
if err != nil {
return err
}
result = append(result, res)
return nil
})
if err != nil {
return nil, err
}
return result, nil
}
// SocketDiagTCP requests INET_DIAG_INFO for TCP protocol for specified family type and return related socket.
func SocketDiagTCP(family uint8) ([]*Socket, error) {
var result []*Socket
err := socketDiagTCPExecutor(family, func(m syscall.NetlinkMessage) error {
sockInfo := &Socket{}
if err := sockInfo.deserialize(m.Data); err != nil {
return err
}
result = append(result, sockInfo)
return nil
})
if err != nil {
return nil, err
}
return result, nil
}
// socketDiagTCPExecutor requests INET_DIAG_INFO for TCP protocol for specified family type.
func socketDiagTCPExecutor(family uint8, receiver func(syscall.NetlinkMessage) error) error {
s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
if err != nil {
return err
}
defer s.Close()
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
@ -189,18 +233,17 @@ func SocketDiagTCPInfo(family uint8) ([]*InetDiagTCPInfoResp, error) {
})
s.Send(req)
var result []*InetDiagTCPInfoResp
loop:
for {
msgs, from, err := s.Receive()
if err != nil {
return nil, err
return err
}
if from.Pid != nl.PidKernel {
return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
return fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
}
if len(msgs) == 0 {
return nil, errors.New("no message nor error from netlink")
return errors.New("no message nor error from netlink")
}
for _, m := range msgs {
@ -208,28 +251,15 @@ loop:
case unix.NLMSG_DONE:
break loop
case unix.NLMSG_ERROR:
native := nl.NativeEndian()
error := int32(native.Uint32(m.Data[0:4]))
return nil, syscall.Errno(-error)
return syscall.Errno(-error)
}
sockInfo := &Socket{}
if err := sockInfo.deserialize(m.Data); err != nil {
return nil, err
if err := receiver(m); err != nil {
return err
}
attrs, err := nl.ParseRouteAttr(m.Data[sizeofSocket:])
if err != nil {
return nil, err
}
res, err := attrsToInetDiagTCPInfoResp(attrs, sockInfo)
if err != nil {
return nil, err
}
result = append(result, res)
}
}
return result, nil
return nil
}
func attrsToInetDiagTCPInfoResp(attrs []syscall.NetlinkRouteAttr, sockInfo *Socket) (*InetDiagTCPInfoResp, error) {

View File

@ -93,8 +93,10 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
req.AddData(out)
}
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
req.AddData(ifId)
if policy.Ifid != 0 {
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
req.AddData(ifId)
}
_, err := req.Execute(unix.NETLINK_XFRM, 0)
return err
@ -189,8 +191,10 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
req.AddData(out)
}
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
req.AddData(ifId)
if policy.Ifid != 0 {
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
req.AddData(ifId)
}
resType := nl.XFRM_MSG_NEWPOLICY
if nlProto == nl.XFRM_MSG_DELPOLICY {

View File

@ -111,7 +111,7 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
// A state with spi 0 can't be deleted so don't allow it to be set
if state.Spi == 0 {
return fmt.Errorf("Spi must be set when adding xfrm state.")
return fmt.Errorf("Spi must be set when adding xfrm state")
}
req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
@ -167,8 +167,10 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
}
}
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
req.AddData(ifId)
if state.Ifid != 0 {
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
req.AddData(ifId)
}
_, err := req.Execute(unix.NETLINK_XFRM, 0)
return err
@ -281,8 +283,10 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
req.AddData(out)
}
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
req.AddData(ifId)
if state.Ifid != 0 {
ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
req.AddData(ifId)
}
resType := nl.XFRM_MSG_NEWSA
if nlProto == nl.XFRM_MSG_DELSA {

View File

@ -1,3 +1,4 @@
//go:build linux && go1.10
// +build linux,go1.10
package netns
@ -133,32 +134,37 @@ func GetFromDocker(id string) (NsHandle, error) {
}
// borrowed from docker/utils/utils.go
func findCgroupMountpoint(cgroupType string) (string, error) {
func findCgroupMountpoint(cgroupType string) (int, string, error) {
output, err := ioutil.ReadFile("/proc/mounts")
if err != nil {
return "", err
return -1, "", err
}
// /proc/mounts has 6 fields per line, one mount per line, e.g.
// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
for _, line := range strings.Split(string(output), "\n") {
parts := strings.Split(line, " ")
if len(parts) == 6 && parts[2] == "cgroup" {
for _, opt := range strings.Split(parts[3], ",") {
if opt == cgroupType {
return parts[1], nil
if len(parts) == 6 {
switch parts[2] {
case "cgroup2":
return 2, parts[1], nil
case "cgroup":
for _, opt := range strings.Split(parts[3], ",") {
if opt == cgroupType {
return 1, parts[1], nil
}
}
}
}
}
return "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
return -1, "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
}
// Returns the relative path to the cgroup docker is running in.
// borrowed from docker/utils/utils.go
// modified to get the docker pid instead of using /proc/self
func getThisCgroup(cgroupType string) (string, error) {
func getDockerCgroup(cgroupVer int, cgroupType string) (string, error) {
dockerpid, err := ioutil.ReadFile("/var/run/docker.pid")
if err != nil {
return "", err
@ -178,7 +184,8 @@ func getThisCgroup(cgroupType string) (string, error) {
for _, line := range strings.Split(string(output), "\n") {
parts := strings.Split(line, ":")
// any type used by docker should work
if parts[1] == cgroupType {
if (cgroupVer == 1 && parts[1] == cgroupType) ||
(cgroupVer == 2 && parts[1] == "") {
return parts[2], nil
}
}
@ -190,46 +197,56 @@ func getThisCgroup(cgroupType string) (string, error) {
// modified to only return the first pid
// modified to glob with id
// modified to search for newer docker containers
// modified to look for cgroups v2
func getPidForContainer(id string) (int, error) {
pid := 0
// memory is chosen randomly, any cgroup used by docker works
cgroupType := "memory"
cgroupRoot, err := findCgroupMountpoint(cgroupType)
cgroupVer, cgroupRoot, err := findCgroupMountpoint(cgroupType)
if err != nil {
return pid, err
}
cgroupThis, err := getThisCgroup(cgroupType)
cgroupDocker, err := getDockerCgroup(cgroupVer, cgroupType)
if err != nil {
return pid, err
}
id += "*"
var pidFile string
if cgroupVer == 1 {
pidFile = "tasks"
} else if cgroupVer == 2 {
pidFile = "cgroup.procs"
} else {
return -1, fmt.Errorf("Invalid cgroup version '%d'", cgroupVer)
}
attempts := []string{
filepath.Join(cgroupRoot, cgroupThis, id, "tasks"),
filepath.Join(cgroupRoot, cgroupDocker, id, pidFile),
// With more recent lxc versions use, cgroup will be in lxc/
filepath.Join(cgroupRoot, cgroupThis, "lxc", id, "tasks"),
filepath.Join(cgroupRoot, cgroupDocker, "lxc", id, pidFile),
// With more recent docker, cgroup will be in docker/
filepath.Join(cgroupRoot, cgroupThis, "docker", id, "tasks"),
filepath.Join(cgroupRoot, cgroupDocker, "docker", id, pidFile),
// Even more recent docker versions under systemd use docker-<id>.scope/
filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", "tasks"),
filepath.Join(cgroupRoot, "system.slice", "docker-"+id+".scope", pidFile),
// Even more recent docker versions under cgroup/systemd/docker/<id>/
filepath.Join(cgroupRoot, "..", "systemd", "docker", id, "tasks"),
filepath.Join(cgroupRoot, "..", "systemd", "docker", id, pidFile),
// Kubernetes with docker and CNI is even more different. Works for BestEffort and Burstable QoS
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, "tasks"),
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "*", "pod*", id, pidFile),
// Same as above but for Guaranteed QoS
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, "tasks"),
filepath.Join(cgroupRoot, "..", "systemd", "kubepods", "pod*", id, pidFile),
// Another flavor of containers location in recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", "tasks"),
filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
// Same as above but for Guaranteed QoS
filepath.Join(cgroupRoot, cgroupThis, "kubepods.slice", "*", "docker-"+id+".scope", "tasks"),
filepath.Join(cgroupRoot, cgroupDocker, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
// When runs inside of a container with recent kubernetes 1.11+. Works for BestEffort and Burstable QoS
filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", "tasks"),
filepath.Join(cgroupRoot, "kubepods.slice", "*.slice", "*", "docker-"+id+".scope", pidFile),
// Same as above but for Guaranteed QoS
filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", "tasks"),
filepath.Join(cgroupRoot, "kubepods.slice", "*", "docker-"+id+".scope", pidFile),
}
var filename string

View File

@ -8,22 +8,35 @@ package errgroup
import (
"context"
"fmt"
"sync"
)
type token struct{}
// A Group is a collection of goroutines working on subtasks that are part of
// the same overall task.
//
// A zero Group is valid and does not cancel on error.
// A zero Group is valid, has no limit on the number of active goroutines,
// and does not cancel on error.
type Group struct {
cancel func()
wg sync.WaitGroup
sem chan token
errOnce sync.Once
err error
}
func (g *Group) done() {
if g.sem != nil {
<-g.sem
}
g.wg.Done()
}
// WithContext returns a new Group and an associated Context derived from ctx.
//
// The derived Context is canceled the first time a function passed to Go
@ -45,14 +58,19 @@ func (g *Group) Wait() error {
}
// Go calls the given function in a new goroutine.
// It blocks until the new goroutine can be added without the number of
// active goroutines in the group exceeding the configured limit.
//
// The first call to return a non-nil error cancels the group; its error will be
// returned by Wait.
func (g *Group) Go(f func() error) {
g.wg.Add(1)
if g.sem != nil {
g.sem <- token{}
}
g.wg.Add(1)
go func() {
defer g.wg.Done()
defer g.done()
if err := f(); err != nil {
g.errOnce.Do(func() {
@ -64,3 +82,51 @@ func (g *Group) Go(f func() error) {
}
}()
}
// TryGo calls the given function in a new goroutine only if the number of
// active goroutines in the group is currently below the configured limit.
//
// The return value reports whether the goroutine was started.
func (g *Group) TryGo(f func() error) bool {
if g.sem != nil {
select {
case g.sem <- token{}:
// Note: this allows barging iff channels in general allow barging.
default:
return false
}
}
g.wg.Add(1)
go func() {
defer g.done()
if err := f(); err != nil {
g.errOnce.Do(func() {
g.err = err
if g.cancel != nil {
g.cancel()
}
})
}
}()
return true
}
// SetLimit limits the number of active goroutines in this group to at most n.
// A negative value indicates no limit.
//
// Any subsequent call to the Go method will block until it can add an active
// goroutine without exceeding the configured limit.
//
// The limit must not be modified while any goroutines in the group are active.
func (g *Group) SetLimit(n int) {
if n < 0 {
g.sem = nil
return
}
if len(g.sem) != 0 {
panic(fmt.Errorf("errgroup: modify limit while %v goroutines in the group are still active", len(g.sem)))
}
g.sem = make(chan token, n)
}

3
vendor/golang.org/x/sys/AUTHORS generated vendored
View File

@ -1,3 +0,0 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

View File

@ -1,3 +0,0 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

29
vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s generated vendored Normal file
View File

@ -0,0 +1,29 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h"
// System call support for RISCV64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

View File

@ -1,233 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
// them here for backwards compatibility.
package unix
const (
DLT_HHDLC = 0x79
IFF_SMART = 0x20
IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82
IFT_AAL2 = 0xbb
IFT_AAL5 = 0x31
IFT_ADSL = 0x5e
IFT_AFLANE8023 = 0x3b
IFT_AFLANE8025 = 0x3c
IFT_ARAP = 0x58
IFT_ARCNET = 0x23
IFT_ARCNETPLUS = 0x24
IFT_ASYNC = 0x54
IFT_ATM = 0x25
IFT_ATMDXI = 0x69
IFT_ATMFUNI = 0x6a
IFT_ATMIMA = 0x6b
IFT_ATMLOGICAL = 0x50
IFT_ATMRADIO = 0xbd
IFT_ATMSUBINTERFACE = 0x86
IFT_ATMVCIENDPT = 0xc2
IFT_ATMVIRTUAL = 0x95
IFT_BGPPOLICYACCOUNTING = 0xa2
IFT_BSC = 0x53
IFT_CCTEMUL = 0x3d
IFT_CEPT = 0x13
IFT_CES = 0x85
IFT_CHANNEL = 0x46
IFT_CNR = 0x55
IFT_COFFEE = 0x84
IFT_COMPOSITELINK = 0x9b
IFT_DCN = 0x8d
IFT_DIGITALPOWERLINE = 0x8a
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
IFT_DLSW = 0x4a
IFT_DOCSCABLEDOWNSTREAM = 0x80
IFT_DOCSCABLEMACLAYER = 0x7f
IFT_DOCSCABLEUPSTREAM = 0x81
IFT_DS0 = 0x51
IFT_DS0BUNDLE = 0x52
IFT_DS1FDL = 0xaa
IFT_DS3 = 0x1e
IFT_DTM = 0x8c
IFT_DVBASILN = 0xac
IFT_DVBASIOUT = 0xad
IFT_DVBRCCDOWNSTREAM = 0x93
IFT_DVBRCCMACLAYER = 0x92
IFT_DVBRCCUPSTREAM = 0x94
IFT_ENC = 0xf4
IFT_EON = 0x19
IFT_EPLRS = 0x57
IFT_ESCON = 0x49
IFT_ETHER = 0x6
IFT_FAITH = 0xf2
IFT_FAST = 0x7d
IFT_FASTETHER = 0x3e
IFT_FASTETHERFX = 0x45
IFT_FDDI = 0xf
IFT_FIBRECHANNEL = 0x38
IFT_FRAMERELAYINTERCONNECT = 0x3a
IFT_FRAMERELAYMPI = 0x5c
IFT_FRDLCIENDPT = 0xc1
IFT_FRELAY = 0x20
IFT_FRELAYDCE = 0x2c
IFT_FRF16MFRBUNDLE = 0xa3
IFT_FRFORWARD = 0x9e
IFT_G703AT2MB = 0x43
IFT_G703AT64K = 0x42
IFT_GIF = 0xf0
IFT_GIGABITETHERNET = 0x75
IFT_GR303IDT = 0xb2
IFT_GR303RDT = 0xb1
IFT_H323GATEKEEPER = 0xa4
IFT_H323PROXY = 0xa5
IFT_HDH1822 = 0x3
IFT_HDLC = 0x76
IFT_HDSL2 = 0xa8
IFT_HIPERLAN2 = 0xb7
IFT_HIPPI = 0x2f
IFT_HIPPIINTERFACE = 0x39
IFT_HOSTPAD = 0x5a
IFT_HSSI = 0x2e
IFT_HY = 0xe
IFT_IBM370PARCHAN = 0x48
IFT_IDSL = 0x9a
IFT_IEEE80211 = 0x47
IFT_IEEE80212 = 0x37
IFT_IEEE8023ADLAG = 0xa1
IFT_IFGSN = 0x91
IFT_IMT = 0xbe
IFT_INTERLEAVE = 0x7c
IFT_IP = 0x7e
IFT_IPFORWARD = 0x8e
IFT_IPOVERATM = 0x72
IFT_IPOVERCDLC = 0x6d
IFT_IPOVERCLAW = 0x6e
IFT_IPSWITCH = 0x4e
IFT_IPXIP = 0xf9
IFT_ISDN = 0x3f
IFT_ISDNBASIC = 0x14
IFT_ISDNPRIMARY = 0x15
IFT_ISDNS = 0x4b
IFT_ISDNU = 0x4c
IFT_ISO88022LLC = 0x29
IFT_ISO88023 = 0x7
IFT_ISO88024 = 0x8
IFT_ISO88025 = 0x9
IFT_ISO88025CRFPINT = 0x62
IFT_ISO88025DTR = 0x56
IFT_ISO88025FIBER = 0x73
IFT_ISO88026 = 0xa
IFT_ISUP = 0xb3
IFT_L3IPXVLAN = 0x89
IFT_LAPB = 0x10
IFT_LAPD = 0x4d
IFT_LAPF = 0x77
IFT_LOCALTALK = 0x2a
IFT_LOOP = 0x18
IFT_MEDIAMAILOVERIP = 0x8b
IFT_MFSIGLINK = 0xa7
IFT_MIOX25 = 0x26
IFT_MODEM = 0x30
IFT_MPC = 0x71
IFT_MPLS = 0xa6
IFT_MPLSTUNNEL = 0x96
IFT_MSDSL = 0x8f
IFT_MVL = 0xbf
IFT_MYRINET = 0x63
IFT_NFAS = 0xaf
IFT_NSIP = 0x1b
IFT_OPTICALCHANNEL = 0xc3
IFT_OPTICALTRANSPORT = 0xc4
IFT_OTHER = 0x1
IFT_P10 = 0xc
IFT_P80 = 0xd
IFT_PARA = 0x22
IFT_PFLOG = 0xf6
IFT_PFSYNC = 0xf7
IFT_PLC = 0xae
IFT_POS = 0xab
IFT_PPPMULTILINKBUNDLE = 0x6c
IFT_PROPBWAP2MP = 0xb8
IFT_PROPCNLS = 0x59
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
IFT_PROPMUX = 0x36
IFT_PROPWIRELESSP2P = 0x9d
IFT_PTPSERIAL = 0x16
IFT_PVC = 0xf1
IFT_QLLC = 0x44
IFT_RADIOMAC = 0xbc
IFT_RADSL = 0x5f
IFT_REACHDSL = 0xc0
IFT_RFC1483 = 0x9f
IFT_RS232 = 0x21
IFT_RSRB = 0x4f
IFT_SDLC = 0x11
IFT_SDSL = 0x60
IFT_SHDSL = 0xa9
IFT_SIP = 0x1f
IFT_SLIP = 0x1c
IFT_SMDSDXI = 0x2b
IFT_SMDSICIP = 0x34
IFT_SONET = 0x27
IFT_SONETOVERHEADCHANNEL = 0xb9
IFT_SONETPATH = 0x32
IFT_SONETVT = 0x33
IFT_SRP = 0x97
IFT_SS7SIGLINK = 0x9c
IFT_STACKTOSTACK = 0x6f
IFT_STARLAN = 0xb
IFT_STF = 0xd7
IFT_T1 = 0x12
IFT_TDLC = 0x74
IFT_TERMPAD = 0x5b
IFT_TR008 = 0xb0
IFT_TRANSPHDLC = 0x7b
IFT_TUNNEL = 0x83
IFT_ULTRA = 0x1d
IFT_USB = 0xa0
IFT_V11 = 0x40
IFT_V35 = 0x2d
IFT_V36 = 0x41
IFT_V37 = 0x78
IFT_VDSL = 0x61
IFT_VIRTUALIPADDRESS = 0x70
IFT_VOICEEM = 0x64
IFT_VOICEENCAP = 0x67
IFT_VOICEFXO = 0x65
IFT_VOICEFXS = 0x66
IFT_VOICEOVERATM = 0x98
IFT_VOICEOVERFRAMERELAY = 0x99
IFT_VOICEOVERIP = 0x68
IFT_X213 = 0x5d
IFT_X25 = 0x5
IFT_X25DDN = 0x4
IFT_X25HUNTGROUP = 0x7a
IFT_X25MLP = 0x79
IFT_X25PLE = 0x28
IFT_XETHER = 0x1a
IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_FAITH = 0x16
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
MAP_NORESERVE = 0x40
MAP_RENAME = 0x20
NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
SIOCADDRT = 0x8030720a
SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8030720b
SIOCDLIFADDR = 0x8118691d
SIOCGLIFADDR = 0xc118691c
SIOCGLIFPHYADDR = 0xc118694b
SIOCSLIFPHYADDR = 0x8118694a
)

View File

@ -1,233 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
// them here for backwards compatibility.
package unix
const (
DLT_HHDLC = 0x79
IFF_SMART = 0x20
IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82
IFT_AAL2 = 0xbb
IFT_AAL5 = 0x31
IFT_ADSL = 0x5e
IFT_AFLANE8023 = 0x3b
IFT_AFLANE8025 = 0x3c
IFT_ARAP = 0x58
IFT_ARCNET = 0x23
IFT_ARCNETPLUS = 0x24
IFT_ASYNC = 0x54
IFT_ATM = 0x25
IFT_ATMDXI = 0x69
IFT_ATMFUNI = 0x6a
IFT_ATMIMA = 0x6b
IFT_ATMLOGICAL = 0x50
IFT_ATMRADIO = 0xbd
IFT_ATMSUBINTERFACE = 0x86
IFT_ATMVCIENDPT = 0xc2
IFT_ATMVIRTUAL = 0x95
IFT_BGPPOLICYACCOUNTING = 0xa2
IFT_BSC = 0x53
IFT_CCTEMUL = 0x3d
IFT_CEPT = 0x13
IFT_CES = 0x85
IFT_CHANNEL = 0x46
IFT_CNR = 0x55
IFT_COFFEE = 0x84
IFT_COMPOSITELINK = 0x9b
IFT_DCN = 0x8d
IFT_DIGITALPOWERLINE = 0x8a
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
IFT_DLSW = 0x4a
IFT_DOCSCABLEDOWNSTREAM = 0x80
IFT_DOCSCABLEMACLAYER = 0x7f
IFT_DOCSCABLEUPSTREAM = 0x81
IFT_DS0 = 0x51
IFT_DS0BUNDLE = 0x52
IFT_DS1FDL = 0xaa
IFT_DS3 = 0x1e
IFT_DTM = 0x8c
IFT_DVBASILN = 0xac
IFT_DVBASIOUT = 0xad
IFT_DVBRCCDOWNSTREAM = 0x93
IFT_DVBRCCMACLAYER = 0x92
IFT_DVBRCCUPSTREAM = 0x94
IFT_ENC = 0xf4
IFT_EON = 0x19
IFT_EPLRS = 0x57
IFT_ESCON = 0x49
IFT_ETHER = 0x6
IFT_FAITH = 0xf2
IFT_FAST = 0x7d
IFT_FASTETHER = 0x3e
IFT_FASTETHERFX = 0x45
IFT_FDDI = 0xf
IFT_FIBRECHANNEL = 0x38
IFT_FRAMERELAYINTERCONNECT = 0x3a
IFT_FRAMERELAYMPI = 0x5c
IFT_FRDLCIENDPT = 0xc1
IFT_FRELAY = 0x20
IFT_FRELAYDCE = 0x2c
IFT_FRF16MFRBUNDLE = 0xa3
IFT_FRFORWARD = 0x9e
IFT_G703AT2MB = 0x43
IFT_G703AT64K = 0x42
IFT_GIF = 0xf0
IFT_GIGABITETHERNET = 0x75
IFT_GR303IDT = 0xb2
IFT_GR303RDT = 0xb1
IFT_H323GATEKEEPER = 0xa4
IFT_H323PROXY = 0xa5
IFT_HDH1822 = 0x3
IFT_HDLC = 0x76
IFT_HDSL2 = 0xa8
IFT_HIPERLAN2 = 0xb7
IFT_HIPPI = 0x2f
IFT_HIPPIINTERFACE = 0x39
IFT_HOSTPAD = 0x5a
IFT_HSSI = 0x2e
IFT_HY = 0xe
IFT_IBM370PARCHAN = 0x48
IFT_IDSL = 0x9a
IFT_IEEE80211 = 0x47
IFT_IEEE80212 = 0x37
IFT_IEEE8023ADLAG = 0xa1
IFT_IFGSN = 0x91
IFT_IMT = 0xbe
IFT_INTERLEAVE = 0x7c
IFT_IP = 0x7e
IFT_IPFORWARD = 0x8e
IFT_IPOVERATM = 0x72
IFT_IPOVERCDLC = 0x6d
IFT_IPOVERCLAW = 0x6e
IFT_IPSWITCH = 0x4e
IFT_IPXIP = 0xf9
IFT_ISDN = 0x3f
IFT_ISDNBASIC = 0x14
IFT_ISDNPRIMARY = 0x15
IFT_ISDNS = 0x4b
IFT_ISDNU = 0x4c
IFT_ISO88022LLC = 0x29
IFT_ISO88023 = 0x7
IFT_ISO88024 = 0x8
IFT_ISO88025 = 0x9
IFT_ISO88025CRFPINT = 0x62
IFT_ISO88025DTR = 0x56
IFT_ISO88025FIBER = 0x73
IFT_ISO88026 = 0xa
IFT_ISUP = 0xb3
IFT_L3IPXVLAN = 0x89
IFT_LAPB = 0x10
IFT_LAPD = 0x4d
IFT_LAPF = 0x77
IFT_LOCALTALK = 0x2a
IFT_LOOP = 0x18
IFT_MEDIAMAILOVERIP = 0x8b
IFT_MFSIGLINK = 0xa7
IFT_MIOX25 = 0x26
IFT_MODEM = 0x30
IFT_MPC = 0x71
IFT_MPLS = 0xa6
IFT_MPLSTUNNEL = 0x96
IFT_MSDSL = 0x8f
IFT_MVL = 0xbf
IFT_MYRINET = 0x63
IFT_NFAS = 0xaf
IFT_NSIP = 0x1b
IFT_OPTICALCHANNEL = 0xc3
IFT_OPTICALTRANSPORT = 0xc4
IFT_OTHER = 0x1
IFT_P10 = 0xc
IFT_P80 = 0xd
IFT_PARA = 0x22
IFT_PFLOG = 0xf6
IFT_PFSYNC = 0xf7
IFT_PLC = 0xae
IFT_POS = 0xab
IFT_PPPMULTILINKBUNDLE = 0x6c
IFT_PROPBWAP2MP = 0xb8
IFT_PROPCNLS = 0x59
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
IFT_PROPMUX = 0x36
IFT_PROPWIRELESSP2P = 0x9d
IFT_PTPSERIAL = 0x16
IFT_PVC = 0xf1
IFT_QLLC = 0x44
IFT_RADIOMAC = 0xbc
IFT_RADSL = 0x5f
IFT_REACHDSL = 0xc0
IFT_RFC1483 = 0x9f
IFT_RS232 = 0x21
IFT_RSRB = 0x4f
IFT_SDLC = 0x11
IFT_SDSL = 0x60
IFT_SHDSL = 0xa9
IFT_SIP = 0x1f
IFT_SLIP = 0x1c
IFT_SMDSDXI = 0x2b
IFT_SMDSICIP = 0x34
IFT_SONET = 0x27
IFT_SONETOVERHEADCHANNEL = 0xb9
IFT_SONETPATH = 0x32
IFT_SONETVT = 0x33
IFT_SRP = 0x97
IFT_SS7SIGLINK = 0x9c
IFT_STACKTOSTACK = 0x6f
IFT_STARLAN = 0xb
IFT_STF = 0xd7
IFT_T1 = 0x12
IFT_TDLC = 0x74
IFT_TERMPAD = 0x5b
IFT_TR008 = 0xb0
IFT_TRANSPHDLC = 0x7b
IFT_TUNNEL = 0x83
IFT_ULTRA = 0x1d
IFT_USB = 0xa0
IFT_V11 = 0x40
IFT_V35 = 0x2d
IFT_V36 = 0x41
IFT_V37 = 0x78
IFT_VDSL = 0x61
IFT_VIRTUALIPADDRESS = 0x70
IFT_VOICEEM = 0x64
IFT_VOICEENCAP = 0x67
IFT_VOICEFXO = 0x65
IFT_VOICEFXS = 0x66
IFT_VOICEOVERATM = 0x98
IFT_VOICEOVERFRAMERELAY = 0x99
IFT_VOICEOVERIP = 0x68
IFT_X213 = 0x5d
IFT_X25 = 0x5
IFT_X25DDN = 0x4
IFT_X25HUNTGROUP = 0x7a
IFT_X25MLP = 0x79
IFT_X25PLE = 0x28
IFT_XETHER = 0x1a
IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_FAITH = 0x16
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
MAP_NORESERVE = 0x40
MAP_RENAME = 0x20
NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
SIOCADDRT = 0x8040720a
SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8040720b
SIOCDLIFADDR = 0x8118691d
SIOCGLIFADDR = 0xc118691c
SIOCGLIFPHYADDR = 0xc118694b
SIOCSLIFPHYADDR = 0x8118694a
)

View File

@ -1,226 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package unix
const (
IFT_1822 = 0x2
IFT_A12MPPSWITCH = 0x82
IFT_AAL2 = 0xbb
IFT_AAL5 = 0x31
IFT_ADSL = 0x5e
IFT_AFLANE8023 = 0x3b
IFT_AFLANE8025 = 0x3c
IFT_ARAP = 0x58
IFT_ARCNET = 0x23
IFT_ARCNETPLUS = 0x24
IFT_ASYNC = 0x54
IFT_ATM = 0x25
IFT_ATMDXI = 0x69
IFT_ATMFUNI = 0x6a
IFT_ATMIMA = 0x6b
IFT_ATMLOGICAL = 0x50
IFT_ATMRADIO = 0xbd
IFT_ATMSUBINTERFACE = 0x86
IFT_ATMVCIENDPT = 0xc2
IFT_ATMVIRTUAL = 0x95
IFT_BGPPOLICYACCOUNTING = 0xa2
IFT_BSC = 0x53
IFT_CCTEMUL = 0x3d
IFT_CEPT = 0x13
IFT_CES = 0x85
IFT_CHANNEL = 0x46
IFT_CNR = 0x55
IFT_COFFEE = 0x84
IFT_COMPOSITELINK = 0x9b
IFT_DCN = 0x8d
IFT_DIGITALPOWERLINE = 0x8a
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
IFT_DLSW = 0x4a
IFT_DOCSCABLEDOWNSTREAM = 0x80
IFT_DOCSCABLEMACLAYER = 0x7f
IFT_DOCSCABLEUPSTREAM = 0x81
IFT_DS0 = 0x51
IFT_DS0BUNDLE = 0x52
IFT_DS1FDL = 0xaa
IFT_DS3 = 0x1e
IFT_DTM = 0x8c
IFT_DVBASILN = 0xac
IFT_DVBASIOUT = 0xad
IFT_DVBRCCDOWNSTREAM = 0x93
IFT_DVBRCCMACLAYER = 0x92
IFT_DVBRCCUPSTREAM = 0x94
IFT_ENC = 0xf4
IFT_EON = 0x19
IFT_EPLRS = 0x57
IFT_ESCON = 0x49
IFT_ETHER = 0x6
IFT_FAST = 0x7d
IFT_FASTETHER = 0x3e
IFT_FASTETHERFX = 0x45
IFT_FDDI = 0xf
IFT_FIBRECHANNEL = 0x38
IFT_FRAMERELAYINTERCONNECT = 0x3a
IFT_FRAMERELAYMPI = 0x5c
IFT_FRDLCIENDPT = 0xc1
IFT_FRELAY = 0x20
IFT_FRELAYDCE = 0x2c
IFT_FRF16MFRBUNDLE = 0xa3
IFT_FRFORWARD = 0x9e
IFT_G703AT2MB = 0x43
IFT_G703AT64K = 0x42
IFT_GIF = 0xf0
IFT_GIGABITETHERNET = 0x75
IFT_GR303IDT = 0xb2
IFT_GR303RDT = 0xb1
IFT_H323GATEKEEPER = 0xa4
IFT_H323PROXY = 0xa5
IFT_HDH1822 = 0x3
IFT_HDLC = 0x76
IFT_HDSL2 = 0xa8
IFT_HIPERLAN2 = 0xb7
IFT_HIPPI = 0x2f
IFT_HIPPIINTERFACE = 0x39
IFT_HOSTPAD = 0x5a
IFT_HSSI = 0x2e
IFT_HY = 0xe
IFT_IBM370PARCHAN = 0x48
IFT_IDSL = 0x9a
IFT_IEEE80211 = 0x47
IFT_IEEE80212 = 0x37
IFT_IEEE8023ADLAG = 0xa1
IFT_IFGSN = 0x91
IFT_IMT = 0xbe
IFT_INTERLEAVE = 0x7c
IFT_IP = 0x7e
IFT_IPFORWARD = 0x8e
IFT_IPOVERATM = 0x72
IFT_IPOVERCDLC = 0x6d
IFT_IPOVERCLAW = 0x6e
IFT_IPSWITCH = 0x4e
IFT_ISDN = 0x3f
IFT_ISDNBASIC = 0x14
IFT_ISDNPRIMARY = 0x15
IFT_ISDNS = 0x4b
IFT_ISDNU = 0x4c
IFT_ISO88022LLC = 0x29
IFT_ISO88023 = 0x7
IFT_ISO88024 = 0x8
IFT_ISO88025 = 0x9
IFT_ISO88025CRFPINT = 0x62
IFT_ISO88025DTR = 0x56
IFT_ISO88025FIBER = 0x73
IFT_ISO88026 = 0xa
IFT_ISUP = 0xb3
IFT_L3IPXVLAN = 0x89
IFT_LAPB = 0x10
IFT_LAPD = 0x4d
IFT_LAPF = 0x77
IFT_LOCALTALK = 0x2a
IFT_LOOP = 0x18
IFT_MEDIAMAILOVERIP = 0x8b
IFT_MFSIGLINK = 0xa7
IFT_MIOX25 = 0x26
IFT_MODEM = 0x30
IFT_MPC = 0x71
IFT_MPLS = 0xa6
IFT_MPLSTUNNEL = 0x96
IFT_MSDSL = 0x8f
IFT_MVL = 0xbf
IFT_MYRINET = 0x63
IFT_NFAS = 0xaf
IFT_NSIP = 0x1b
IFT_OPTICALCHANNEL = 0xc3
IFT_OPTICALTRANSPORT = 0xc4
IFT_OTHER = 0x1
IFT_P10 = 0xc
IFT_P80 = 0xd
IFT_PARA = 0x22
IFT_PFLOG = 0xf6
IFT_PFSYNC = 0xf7
IFT_PLC = 0xae
IFT_POS = 0xab
IFT_PPPMULTILINKBUNDLE = 0x6c
IFT_PROPBWAP2MP = 0xb8
IFT_PROPCNLS = 0x59
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
IFT_PROPMUX = 0x36
IFT_PROPWIRELESSP2P = 0x9d
IFT_PTPSERIAL = 0x16
IFT_PVC = 0xf1
IFT_QLLC = 0x44
IFT_RADIOMAC = 0xbc
IFT_RADSL = 0x5f
IFT_REACHDSL = 0xc0
IFT_RFC1483 = 0x9f
IFT_RS232 = 0x21
IFT_RSRB = 0x4f
IFT_SDLC = 0x11
IFT_SDSL = 0x60
IFT_SHDSL = 0xa9
IFT_SIP = 0x1f
IFT_SLIP = 0x1c
IFT_SMDSDXI = 0x2b
IFT_SMDSICIP = 0x34
IFT_SONET = 0x27
IFT_SONETOVERHEADCHANNEL = 0xb9
IFT_SONETPATH = 0x32
IFT_SONETVT = 0x33
IFT_SRP = 0x97
IFT_SS7SIGLINK = 0x9c
IFT_STACKTOSTACK = 0x6f
IFT_STARLAN = 0xb
IFT_STF = 0xd7
IFT_T1 = 0x12
IFT_TDLC = 0x74
IFT_TERMPAD = 0x5b
IFT_TR008 = 0xb0
IFT_TRANSPHDLC = 0x7b
IFT_TUNNEL = 0x83
IFT_ULTRA = 0x1d
IFT_USB = 0xa0
IFT_V11 = 0x40
IFT_V35 = 0x2d
IFT_V36 = 0x41
IFT_V37 = 0x78
IFT_VDSL = 0x61
IFT_VIRTUALIPADDRESS = 0x70
IFT_VOICEEM = 0x64
IFT_VOICEENCAP = 0x67
IFT_VOICEFXO = 0x65
IFT_VOICEFXS = 0x66
IFT_VOICEOVERATM = 0x98
IFT_VOICEOVERFRAMERELAY = 0x99
IFT_VOICEOVERIP = 0x68
IFT_X213 = 0x5d
IFT_X25 = 0x5
IFT_X25DDN = 0x4
IFT_X25HUNTGROUP = 0x7a
IFT_X25MLP = 0x79
IFT_X25PLE = 0x28
IFT_XETHER = 0x1a
// missing constants on FreeBSD-11.1-RELEASE, copied from old values in ztypes_freebsd_arm.go
IFF_SMART = 0x20
IFT_FAITH = 0xf2
IFT_IPXIP = 0xf9
IPPROTO_MAXID = 0x34
IPV6_FAITH = 0x1d
IP_FAITH = 0x16
MAP_NORESERVE = 0x40
MAP_RENAME = 0x20
NET_RT_MAXID = 0x6
RTF_PRCLONING = 0x10000
RTM_OLDADD = 0x9
RTM_OLDDEL = 0xa
SIOCADDRT = 0x8030720a
SIOCALIFADDR = 0x8118691b
SIOCDELRT = 0x8030720b
SIOCDLIFADDR = 0x8118691d
SIOCGLIFADDR = 0xc118691c
SIOCGLIFPHYADDR = 0xc118694b
SIOCSLIFPHYADDR = 0x8118694a
)

View File

@ -1,17 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
// them here for backwards compatibility.
package unix
const (
DLT_HHDLC = 0x79
IPV6_MIN_MEMBERSHIPS = 0x1f
IP_MAX_SOURCE_FILTER = 0x400
IP_MIN_MEMBERSHIPS = 0x1f
RT_CACHING_CONTEXT = 0x1
RT_NORTREF = 0x2
)

View File

@ -73,12 +73,12 @@ aix_ppc64)
darwin_amd64)
mkerrors="$mkerrors -m64"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm_darwin.go"
mkasm="go run mkasm.go"
;;
darwin_arm64)
mkerrors="$mkerrors -m64"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm_darwin.go"
mkasm="go run mkasm.go"
;;
dragonfly_amd64)
mkerrors="$mkerrors -m64"
@ -89,25 +89,30 @@ dragonfly_amd64)
freebsd_386)
mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32"
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_amd64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_arm)
mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32 -arm"
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
freebsd_arm64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
freebsd_riscv64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
netbsd_386)
@ -137,17 +142,17 @@ netbsd_arm64)
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_386)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32 -openbsd"
mksyscall="go run mksyscall.go -l32 -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_amd64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_arm)
@ -160,10 +165,10 @@ openbsd_arm)
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_arm64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
@ -227,5 +232,5 @@ esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi
if [ -n "$mkasm" ]; then echo "$mkasm $GOOS $GOARCH"; fi
) | $run

View File

@ -128,6 +128,7 @@ includes_FreeBSD='
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/ptrace.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
@ -202,6 +203,7 @@ struct ltchars {
#include <sys/timerfd.h>
#include <sys/uio.h>
#include <sys/xattr.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/can.h>
#include <linux/can/error.h>
@ -295,6 +297,10 @@ struct ltchars {
#define SOL_NETLINK 270
#endif
#ifndef SOL_SMC
#define SOL_SMC 286
#endif
#ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go
@ -529,7 +535,7 @@ ccflags="$@"
$2 ~ /^(MS|MNT|MOUNT|UMOUNT)_/ ||
$2 ~ /^NS_GET_/ ||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|TFD)_/ ||
$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|PIOD|TFD)_/ ||
$2 ~ /^KEXEC_/ ||
$2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
@ -553,6 +559,7 @@ ccflags="$@"
$2 ~ /^CLONE_[A-Z_]+/ ||
$2 !~ /^(BPF_TIMEVAL|BPF_FIB_LOOKUP_[A-Z]+)$/ &&
$2 ~ /^(BPF|DLT)_/ ||
$2 ~ /^AUDIT_/ ||
$2 ~ /^(CLOCK|TIMER)_/ ||
$2 ~ /^CAN_/ ||
$2 ~ /^CAP_/ ||
@ -575,7 +582,6 @@ ccflags="$@"
$2 ~ /^SEEK_/ ||
$2 ~ /^SPLICE_/ ||
$2 ~ /^SYNC_FILE_RANGE_/ ||
$2 !~ /^AUDIT_RECORD_MAGIC/ &&
$2 !~ /IOC_MAGIC/ &&
$2 ~ /^[A-Z][A-Z0-9_]+_MAGIC2?$/ ||
$2 ~ /^(VM|VMADDR)_/ ||

View File

@ -218,13 +218,62 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
}
func recvmsgRaw(fd int, iov []Iovec, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
// Recvmsg not implemented on AIX
return -1, -1, -1, ENOSYS
var msg Msghdr
msg.Name = (*byte)(unsafe.Pointer(rsa))
msg.Namelen = uint32(SizeofSockaddrAny)
var dummy byte
if len(oob) > 0 {
// receive at least one normal byte
if emptyIovecs(iov) {
var iova [1]Iovec
iova[0].Base = &dummy
iova[0].SetLen(1)
iov = iova[:]
}
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
msg.SetControllen(len(oob))
}
if len(iov) > 0 {
msg.Iov = &iov[0]
msg.SetIovlen(len(iov))
}
if n, err = recvmsg(fd, &msg, flags); n == -1 {
return
}
oobn = int(msg.Controllen)
recvflags = int(msg.Flags)
return
}
func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
// SendmsgN not implemented on AIX
return -1, ENOSYS
var msg Msghdr
msg.Name = (*byte)(unsafe.Pointer(ptr))
msg.Namelen = uint32(salen)
var dummy byte
var empty bool
if len(oob) > 0 {
// send at least one normal byte
empty = emptyIovecs(iov)
if empty {
var iova [1]Iovec
iova[0].Base = &dummy
iova[0].SetLen(1)
iov = iova[:]
}
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
msg.SetControllen(len(oob))
}
if len(iov) > 0 {
msg.Iov = &iov[0]
msg.SetIovlen(len(iov))
}
if n, err = sendmsg(fd, &msg, flags); err != nil {
return 0, err
}
if len(oob) > 0 && empty {
n = 0
}
return n, nil
}
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {

View File

@ -363,7 +363,7 @@ func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Sockle
var empty bool
if len(oob) > 0 {
// send at least one normal byte
empty := emptyIovecs(iov)
empty = emptyIovecs(iov)
if empty {
var iova [1]Iovec
iova[0].Base = &dummy

View File

@ -17,25 +17,12 @@ import (
"unsafe"
)
const (
SYS_FSTAT_FREEBSD12 = 551 // { int fstat(int fd, _Out_ struct stat *sb); }
SYS_FSTATAT_FREEBSD12 = 552 // { int fstatat(int fd, _In_z_ char *path, \
SYS_GETDIRENTRIES_FREEBSD12 = 554 // { ssize_t getdirentries(int fd, \
SYS_STATFS_FREEBSD12 = 555 // { int statfs(_In_z_ char *path, \
SYS_FSTATFS_FREEBSD12 = 556 // { int fstatfs(int fd, \
SYS_GETFSSTAT_FREEBSD12 = 557 // { int getfsstat( \
SYS_MKNODAT_FREEBSD12 = 559 // { int mknodat(int fd, _In_z_ char *path, \
)
// See https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html.
var (
osreldateOnce sync.Once
osreldate uint32
)
// INO64_FIRST from /usr/src/lib/libc/sys/compat-ino64.h
const _ino64First = 1200031
func supportsABI(ver uint32) bool {
osreldateOnce.Do(func() { osreldate, _ = SysctlUint32("kern.osreldate") })
return osreldate >= ver
@ -159,38 +146,18 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
var (
_p0 unsafe.Pointer
bufsize uintptr
oldBuf []statfs_freebsd11_t
needsConvert bool
_p0 unsafe.Pointer
bufsize uintptr
)
if len(buf) > 0 {
if supportsABI(_ino64First) {
_p0 = unsafe.Pointer(&buf[0])
bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
} else {
n := len(buf)
oldBuf = make([]statfs_freebsd11_t, n)
_p0 = unsafe.Pointer(&oldBuf[0])
bufsize = unsafe.Sizeof(statfs_freebsd11_t{}) * uintptr(n)
needsConvert = true
}
_p0 = unsafe.Pointer(&buf[0])
bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
}
var sysno uintptr = SYS_GETFSSTAT
if supportsABI(_ino64First) {
sysno = SYS_GETFSSTAT_FREEBSD12
}
r0, _, e1 := Syscall(sysno, uintptr(_p0), bufsize, uintptr(flags))
r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
n = int(r0)
if e1 != 0 {
err = e1
}
if e1 == 0 && needsConvert {
for i := range oldBuf {
buf[i].convertFrom(&oldBuf[i])
}
}
return
}
@ -245,87 +212,11 @@ func Uname(uname *Utsname) error {
}
func Stat(path string, st *Stat_t) (err error) {
var oldStat stat_freebsd11_t
if supportsABI(_ino64First) {
return fstatat_freebsd12(AT_FDCWD, path, st, 0)
}
err = stat(path, &oldStat)
if err != nil {
return err
}
st.convertFrom(&oldStat)
return nil
return Fstatat(AT_FDCWD, path, st, 0)
}
func Lstat(path string, st *Stat_t) (err error) {
var oldStat stat_freebsd11_t
if supportsABI(_ino64First) {
return fstatat_freebsd12(AT_FDCWD, path, st, AT_SYMLINK_NOFOLLOW)
}
err = lstat(path, &oldStat)
if err != nil {
return err
}
st.convertFrom(&oldStat)
return nil
}
func Fstat(fd int, st *Stat_t) (err error) {
var oldStat stat_freebsd11_t
if supportsABI(_ino64First) {
return fstat_freebsd12(fd, st)
}
err = fstat(fd, &oldStat)
if err != nil {
return err
}
st.convertFrom(&oldStat)
return nil
}
func Fstatat(fd int, path string, st *Stat_t, flags int) (err error) {
var oldStat stat_freebsd11_t
if supportsABI(_ino64First) {
return fstatat_freebsd12(fd, path, st, flags)
}
err = fstatat(fd, path, &oldStat, flags)
if err != nil {
return err
}
st.convertFrom(&oldStat)
return nil
}
func Statfs(path string, st *Statfs_t) (err error) {
var oldStatfs statfs_freebsd11_t
if supportsABI(_ino64First) {
return statfs_freebsd12(path, st)
}
err = statfs(path, &oldStatfs)
if err != nil {
return err
}
st.convertFrom(&oldStatfs)
return nil
}
func Fstatfs(fd int, st *Statfs_t) (err error) {
var oldStatfs statfs_freebsd11_t
if supportsABI(_ino64First) {
return fstatfs_freebsd12(fd, st)
}
err = fstatfs(fd, &oldStatfs)
if err != nil {
return err
}
st.convertFrom(&oldStatfs)
return nil
return Fstatat(AT_FDCWD, path, st, AT_SYMLINK_NOFOLLOW)
}
func Getdents(fd int, buf []byte) (n int, err error) {
@ -333,162 +224,25 @@ func Getdents(fd int, buf []byte) (n int, err error) {
}
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
if supportsABI(_ino64First) {
if basep == nil || unsafe.Sizeof(*basep) == 8 {
return getdirentries_freebsd12(fd, buf, (*uint64)(unsafe.Pointer(basep)))
}
// The freebsd12 syscall needs a 64-bit base. On 32-bit machines
// we can't just use the basep passed in. See #32498.
var base uint64 = uint64(*basep)
n, err = getdirentries_freebsd12(fd, buf, &base)
*basep = uintptr(base)
if base>>32 != 0 {
// We can't stuff the base back into a uintptr, so any
// future calls would be suspect. Generate an error.
// EIO is allowed by getdirentries.
err = EIO
}
return
if basep == nil || unsafe.Sizeof(*basep) == 8 {
return getdirentries(fd, buf, (*uint64)(unsafe.Pointer(basep)))
}
// The old syscall entries are smaller than the new. Use 1/4 of the original
// buffer size rounded up to DIRBLKSIZ (see /usr/src/lib/libc/sys/getdirentries.c).
oldBufLen := roundup(len(buf)/4, _dirblksiz)
oldBuf := make([]byte, oldBufLen)
n, err = getdirentries(fd, oldBuf, basep)
if err == nil && n > 0 {
n = convertFromDirents11(buf, oldBuf[:n])
// The syscall needs a 64-bit base. On 32-bit machines
// we can't just use the basep passed in. See #32498.
var base uint64 = uint64(*basep)
n, err = getdirentries(fd, buf, &base)
*basep = uintptr(base)
if base>>32 != 0 {
// We can't stuff the base back into a uintptr, so any
// future calls would be suspect. Generate an error.
// EIO is allowed by getdirentries.
err = EIO
}
return
}
func Mknod(path string, mode uint32, dev uint64) (err error) {
var oldDev int
if supportsABI(_ino64First) {
return mknodat_freebsd12(AT_FDCWD, path, mode, dev)
}
oldDev = int(dev)
return mknod(path, mode, oldDev)
}
func Mknodat(fd int, path string, mode uint32, dev uint64) (err error) {
var oldDev int
if supportsABI(_ino64First) {
return mknodat_freebsd12(fd, path, mode, dev)
}
oldDev = int(dev)
return mknodat(fd, path, mode, oldDev)
}
// round x to the nearest multiple of y, larger or equal to x.
//
// from /usr/include/sys/param.h Macros for counting and rounding.
// #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
func roundup(x, y int) int {
return ((x + y - 1) / y) * y
}
func (s *Stat_t) convertFrom(old *stat_freebsd11_t) {
*s = Stat_t{
Dev: uint64(old.Dev),
Ino: uint64(old.Ino),
Nlink: uint64(old.Nlink),
Mode: old.Mode,
Uid: old.Uid,
Gid: old.Gid,
Rdev: uint64(old.Rdev),
Atim: old.Atim,
Mtim: old.Mtim,
Ctim: old.Ctim,
Btim: old.Btim,
Size: old.Size,
Blocks: old.Blocks,
Blksize: old.Blksize,
Flags: old.Flags,
Gen: uint64(old.Gen),
}
}
func (s *Statfs_t) convertFrom(old *statfs_freebsd11_t) {
*s = Statfs_t{
Version: _statfsVersion,
Type: old.Type,
Flags: old.Flags,
Bsize: old.Bsize,
Iosize: old.Iosize,
Blocks: old.Blocks,
Bfree: old.Bfree,
Bavail: old.Bavail,
Files: old.Files,
Ffree: old.Ffree,
Syncwrites: old.Syncwrites,
Asyncwrites: old.Asyncwrites,
Syncreads: old.Syncreads,
Asyncreads: old.Asyncreads,
// Spare
Namemax: old.Namemax,
Owner: old.Owner,
Fsid: old.Fsid,
// Charspare
// Fstypename
// Mntfromname
// Mntonname
}
sl := old.Fstypename[:]
n := clen(*(*[]byte)(unsafe.Pointer(&sl)))
copy(s.Fstypename[:], old.Fstypename[:n])
sl = old.Mntfromname[:]
n = clen(*(*[]byte)(unsafe.Pointer(&sl)))
copy(s.Mntfromname[:], old.Mntfromname[:n])
sl = old.Mntonname[:]
n = clen(*(*[]byte)(unsafe.Pointer(&sl)))
copy(s.Mntonname[:], old.Mntonname[:n])
}
func convertFromDirents11(buf []byte, old []byte) int {
const (
fixedSize = int(unsafe.Offsetof(Dirent{}.Name))
oldFixedSize = int(unsafe.Offsetof(dirent_freebsd11{}.Name))
)
dstPos := 0
srcPos := 0
for dstPos+fixedSize < len(buf) && srcPos+oldFixedSize < len(old) {
var dstDirent Dirent
var srcDirent dirent_freebsd11
// If multiple direntries are written, sometimes when we reach the final one,
// we may have cap of old less than size of dirent_freebsd11.
copy((*[unsafe.Sizeof(srcDirent)]byte)(unsafe.Pointer(&srcDirent))[:], old[srcPos:])
reclen := roundup(fixedSize+int(srcDirent.Namlen)+1, 8)
if dstPos+reclen > len(buf) {
break
}
dstDirent.Fileno = uint64(srcDirent.Fileno)
dstDirent.Off = 0
dstDirent.Reclen = uint16(reclen)
dstDirent.Type = srcDirent.Type
dstDirent.Pad0 = 0
dstDirent.Namlen = uint16(srcDirent.Namlen)
dstDirent.Pad1 = 0
copy(dstDirent.Name[:], srcDirent.Name[:srcDirent.Namlen])
copy(buf[dstPos:], (*[unsafe.Sizeof(dstDirent)]byte)(unsafe.Pointer(&dstDirent))[:])
padding := buf[dstPos+fixedSize+int(dstDirent.Namlen) : dstPos+reclen]
for i := range padding {
padding[i] = 0
}
dstPos += int(dstDirent.Reclen)
srcPos += int(srcDirent.Reclen)
}
return dstPos
return Mknodat(AT_FDCWD, path, mode, dev)
}
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
@ -501,31 +255,31 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sys ptrace(request int, pid int, addr uintptr, data int) (err error)
func PtraceAttach(pid int) (err error) {
return ptrace(PTRACE_ATTACH, pid, 0, 0)
return ptrace(PT_ATTACH, pid, 0, 0)
}
func PtraceCont(pid int, signal int) (err error) {
return ptrace(PTRACE_CONT, pid, 1, signal)
return ptrace(PT_CONTINUE, pid, 1, signal)
}
func PtraceDetach(pid int) (err error) {
return ptrace(PTRACE_DETACH, pid, 1, 0)
return ptrace(PT_DETACH, pid, 1, 0)
}
func PtraceGetFpRegs(pid int, fpregsout *FpReg) (err error) {
return ptrace(PTRACE_GETFPREGS, pid, uintptr(unsafe.Pointer(fpregsout)), 0)
return ptrace(PT_GETFPREGS, pid, uintptr(unsafe.Pointer(fpregsout)), 0)
}
func PtraceGetRegs(pid int, regsout *Reg) (err error) {
return ptrace(PTRACE_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0)
return ptrace(PT_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0)
}
func PtraceLwpEvents(pid int, enable int) (err error) {
return ptrace(PTRACE_LWPEVENTS, pid, 0, enable)
return ptrace(PT_LWP_EVENTS, pid, 0, enable)
}
func PtraceLwpInfo(pid int, info uintptr) (err error) {
return ptrace(PTRACE_LWPINFO, pid, info, int(unsafe.Sizeof(PtraceLwpInfoStruct{})))
return ptrace(PT_LWPINFO, pid, info, int(unsafe.Sizeof(PtraceLwpInfoStruct{})))
}
func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) {
@ -545,11 +299,11 @@ func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) {
}
func PtraceSetRegs(pid int, regs *Reg) (err error) {
return ptrace(PTRACE_SETREGS, pid, uintptr(unsafe.Pointer(regs)), 0)
return ptrace(PT_SETREGS, pid, uintptr(unsafe.Pointer(regs)), 0)
}
func PtraceSingleStep(pid int) (err error) {
return ptrace(PTRACE_SINGLESTEP, pid, 1, 0)
return ptrace(PT_STEP, pid, 1, 0)
}
/*
@ -591,16 +345,12 @@ func PtraceSingleStep(pid int) (err error) {
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error)
//sys fstat(fd int, stat *stat_freebsd11_t) (err error)
//sys fstat_freebsd12(fd int, stat *Stat_t) (err error)
//sys fstatat(fd int, path string, stat *stat_freebsd11_t, flags int) (err error)
//sys fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error)
//sys fstatfs(fd int, stat *statfs_freebsd11_t) (err error)
//sys fstatfs_freebsd12(fd int, stat *Statfs_t) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
//sys Fstatfs(fd int, stat *Statfs_t) (err error)
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
//sys getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
//sys getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error)
//sys getdirentries(fd int, buf []byte, basep *uint64) (n int, err error)
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
@ -622,13 +372,10 @@ func PtraceSingleStep(pid int) (err error) {
//sys Link(path string, link string) (err error)
//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
//sys Listen(s int, backlog int) (err error)
//sys lstat(path string, stat *stat_freebsd11_t) (err error)
//sys Mkdir(path string, mode uint32) (err error)
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
//sys mknod(path string, mode uint32, dev int) (err error)
//sys mknodat(fd int, path string, mode uint32, dev int) (err error)
//sys mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error)
//sys Mknodat(fd int, path string, mode uint32, dev uint64) (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Openat(fdat int, path string, mode int, perm uint32) (fd int, err error)
@ -658,9 +405,7 @@ func PtraceSingleStep(pid int) (err error) {
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
//sys stat(path string, stat *stat_freebsd11_t) (err error)
//sys statfs(path string, stat *statfs_freebsd11_t) (err error)
//sys statfs_freebsd12(path string, stat *Statfs_t) (err error)
//sys Statfs(path string, stat *Statfs_t) (err error)
//sys Symlink(path string, link string) (err error)
//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
//sys Sync() (err error)

View File

@ -57,11 +57,11 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
return ptrace(PTRACE_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
return ptrace(PT_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
}
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint32(countin)}
err = ptrace(PTRACE_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
return int(ioDesc.Len), err
}

Some files were not shown because too many files have changed in this diff Show More