Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c29dc79f96 | ||
|
|
508c94caec | ||
|
|
b96f963c7a | ||
|
|
518bc80c56 | ||
|
|
434e9b9ef7 | ||
|
|
0e87bccf19 | ||
|
|
0259301ae2 | ||
|
|
14cad164ec | ||
|
|
1868e4fe2d | ||
|
|
5c95925a71 | ||
|
|
505f5a7def | ||
|
|
dc8b8289fa | ||
|
|
196ed2d00e | ||
|
|
43139b3375 | ||
|
|
18d129f18b | ||
|
|
9397270f5e | ||
|
|
3656c69d0f | ||
|
|
3af6e6b61d | ||
|
|
427af8636f | ||
|
|
dc704d19d6 | ||
|
|
45a24d5d95 | ||
|
|
c0533466c8 | ||
|
|
ada798a3f7 | ||
|
|
eb49a034c4 | ||
|
|
670139cffa | ||
|
|
717b4337b5 | ||
|
|
ef076afac1 | ||
|
|
ccc1cfaa58 | ||
|
|
78ebd8bfb9 | ||
|
|
c666d1400d | ||
|
|
ab0b386b4e | ||
|
|
52da39d3aa | ||
|
|
597408952e | ||
|
|
6f05dc325a | ||
|
|
8ab3c63c2d | ||
|
|
c464674317 | ||
|
|
c860b78de4 | ||
|
|
9f1bf2a848 | ||
|
|
7567d28a73 | ||
|
|
ba5bdafe5d | ||
|
|
d34720b531 | ||
|
|
8fc26ce7a0 | ||
|
|
c8d165df6d | ||
|
|
1b5811957e | ||
|
|
8a3014f202 | ||
|
|
019727a392 | ||
|
|
352e0512e8 | ||
|
|
9c016b5d12 | ||
|
|
0729398940 | ||
|
|
394ab0d149 | ||
|
|
0144de0fcf | ||
|
|
47373d2612 | ||
|
|
8e8410f726 | ||
|
|
2bae9b67d3 | ||
|
|
976edfe1bc | ||
|
|
cb244060c2 | ||
|
|
d1aada912d | ||
|
|
8b2b1d20d6 | ||
|
|
14bdce598f | ||
|
|
7e131a0076 | ||
|
|
b6a0e0bc96 | ||
|
|
133a764c4d | ||
|
|
e6099fb83d | ||
|
|
1fb5bf669e | ||
|
|
3712c1cfcb | ||
|
|
825421709e | ||
|
|
d708217503 | ||
|
|
abee8ccc0d | ||
|
|
e1474463ef | ||
|
|
11ee4b61d9 | ||
|
|
a4cbf13a9b | ||
|
|
6cac5d603b | ||
|
|
333fc9a0d7 | ||
|
|
f90ac41ae4 | ||
|
|
93a1b3d0e7 | ||
|
|
00406f9d1e | ||
|
|
e82848a9cb | ||
|
|
5280b4d582 | ||
|
|
495a2cbb0c | ||
|
|
8c59fc1eea | ||
|
|
2eee7cef35 | ||
|
|
1079e113fe | ||
|
|
999ca15763 | ||
|
|
dad27e9f72 | ||
|
|
0b1a96ff30 | ||
|
|
c8c26897ba | ||
|
|
28c5faee75 | ||
|
|
d0d9e36662 | ||
|
|
f7662a2435 | ||
|
|
aacae5c053 | ||
|
|
6b7876125d | ||
|
|
2f0faf6721 | ||
|
|
37531cdaf5 | ||
|
|
a8d4e0a7dd | ||
|
|
845ef62b74 | ||
|
|
691186ca7f | ||
|
|
adaeedd6af | ||
|
|
19e5747a8c | ||
|
|
4cf3da4ae3 | ||
|
|
c20da1521f | ||
|
|
b66b5dd85f | ||
|
|
e727ad6697 | ||
|
|
18172539d8 | ||
|
|
f20b8408a4 | ||
|
|
6ff8e5eb86 | ||
|
|
61fa963636 | ||
|
|
33ccedc66f | ||
|
|
853b82d19f | ||
|
|
d216b0c39b | ||
|
|
f95505231a | ||
|
|
5f25a93a47 | ||
|
|
7c11d48630 | ||
|
|
9d9ec6e3e1 | ||
|
|
8fd63065a6 | ||
|
|
c1a7948b19 | ||
|
|
1561794ae9 | ||
|
|
fb8ca5d31e | ||
|
|
f2574a7cb1 | ||
|
|
438548a9dd | ||
|
|
8e69e38d51 | ||
|
|
0a100e5d8f | ||
|
|
3eb775c5e6 | ||
|
|
719f60bb91 | ||
|
|
2ba7f1608f | ||
|
|
bf79945c70 | ||
|
|
ba41448fe6 | ||
|
|
13fd3de77f | ||
|
|
283f200489 | ||
|
|
a7e8db00cb | ||
|
|
ffb2e2d7d1 | ||
|
|
d03b84d8f2 | ||
|
|
1512d727cb | ||
|
|
470eee1385 | ||
|
|
2216cff9e8 | ||
|
|
83029befef | ||
|
|
48aa2f4eef | ||
|
|
ca12d49b41 | ||
|
|
2b097c5a62 | ||
|
|
0389a29052 | ||
|
|
6265f4e4ca | ||
|
|
edab9efdea | ||
|
|
1b2dc7c2a4 |
2
.github/actions/retest-action/Dockerfile
vendored
2
.github/actions/retest-action/Dockerfile
vendored
@@ -1,4 +1,4 @@
|
||||
FROM alpine:3.17
|
||||
FROM alpine:3.20
|
||||
|
||||
RUN apk add --no-cache curl jq
|
||||
|
||||
|
||||
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@@ -17,3 +17,9 @@ updates:
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
golang:
|
||||
patterns:
|
||||
- "*"
|
||||
exclude-patterns:
|
||||
- "github.com/containernetworking/*"
|
||||
|
||||
2
.github/workflows/commands.yml
vendored
2
.github/workflows/commands.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Re-Test Action
|
||||
uses: ./.github/actions/retest-action
|
||||
|
||||
114
.github/workflows/release.yaml
vendored
Normal file
114
.github/workflows/release.yaml
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
---
|
||||
name: Release binaries
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
linux_release:
|
||||
name: Release linux binaries
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
goarch: [amd64, arm, arm64, mips64le, ppc64le, riscv64, s390x]
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.22
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
CGO_ENABLED: 0
|
||||
run: ./build_linux.sh -ldflags '-extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=${{ github.ref_name }}'
|
||||
|
||||
- name: COPY files
|
||||
run: cp README.md LICENSE bin/
|
||||
|
||||
- name: Change plugin file ownership
|
||||
working-directory: ./bin
|
||||
run: sudo chown root:root ./*
|
||||
|
||||
- name: Create dist directory
|
||||
run: mkdir dist
|
||||
|
||||
- name: Create archive file
|
||||
working-directory: ./bin
|
||||
run: tar cfzpv ../dist/cni-plugins-linux-${{ matrix.goarch }}-${{ github.ref_name }}.tgz .
|
||||
|
||||
- name: Create sha256 checksum
|
||||
working-directory: ./dist
|
||||
run: sha256sum cni-plugins-linux-${{ matrix.goarch }}-${{ github.ref_name }}.tgz | tee cni-plugins-linux-${{ matrix.goarch }}-${{ github.ref_name }}.tgz.sha256
|
||||
|
||||
- name: Create sha512 checksum
|
||||
working-directory: ./dist
|
||||
run: sha512sum cni-plugins-linux-${{ matrix.goarch }}-${{ github.ref_name }}.tgz | tee cni-plugins-linux-${{ matrix.goarch }}-${{ github.ref_name }}.tgz.sha512
|
||||
|
||||
- name: Upload binaries to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ./dist/*
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
|
||||
windows_releases:
|
||||
name: Release windows binaries
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
goarch: [amd64]
|
||||
steps:
|
||||
- name: Install dos2unix
|
||||
run: sudo apt-get install dos2unix
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
CGO_ENABLED: 0
|
||||
run: ./build_windows.sh -ldflags '-extldflags -static -X github.com/containernetworking/plugins/pkg/utils/buildversion.BuildVersion=${{ github.ref_name }}'
|
||||
|
||||
- name: COPY files
|
||||
run: cp README.md LICENSE bin/
|
||||
|
||||
- name: Change plugin file ownership
|
||||
working-directory: ./bin
|
||||
run: sudo chown root:root ./*
|
||||
|
||||
- name: Create dist directory
|
||||
run: mkdir dist
|
||||
|
||||
- name: Create archive file
|
||||
working-directory: ./bin
|
||||
run: tar cpfzv ../dist/cni-plugins-windows-${{ matrix.goarch }}-${{ github.ref_name }}.tgz .
|
||||
|
||||
- name: Create sha256 checksum
|
||||
working-directory: ./dist
|
||||
run: sha256sum cni-plugins-windows-${{ matrix.goarch }}-${{ github.ref_name }}.tgz | tee cni-plugins-windows-${{ matrix.goarch }}-${{ github.ref_name }}.tgz.sha256
|
||||
|
||||
- name: Create sha512 checksum
|
||||
working-directory: ./dist
|
||||
run: sha512sum cni-plugins-windows-${{ matrix.goarch }}-${{ github.ref_name }}.tgz | tee cni-plugins-windows-${{ matrix.goarch }}-${{ github.ref_name }}.tgz.sha512
|
||||
|
||||
- name: Upload binaries to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ./dist/*
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
file_glob: true
|
||||
13
.github/workflows/stale.yml
vendored
13
.github/workflows/stale.yml
vendored
@@ -1,13 +0,0 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
stale-pr-message: 'This PR has been untouched for too long without an update. It will be closed in 7 days.'
|
||||
exempt-issue-labels: 'keep'
|
||||
40
.github/workflows/test.yaml
vendored
40
.github/workflows/test.yaml
vendored
@@ -4,7 +4,7 @@ name: test
|
||||
on: ["push", "pull_request"]
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.20"
|
||||
GO_VERSION: "1.22"
|
||||
LINUX_ARCHES: "amd64 386 arm arm64 s390x mips64le ppc64le riscv64"
|
||||
|
||||
jobs:
|
||||
@@ -12,28 +12,29 @@ jobs:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- uses: actions/checkout@v3
|
||||
go-version-file: go.mod
|
||||
- uses: ibiqlik/action-yamllint@v3
|
||||
with:
|
||||
format: auto
|
||||
- uses: golangci/golangci-lint-action@v3
|
||||
- uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: v1.55.2
|
||||
args: -v
|
||||
skip-cache: true
|
||||
build:
|
||||
name: Build all linux architectures
|
||||
needs: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
go-version-file: go.mod
|
||||
- name: Build on all supported architectures
|
||||
run: |
|
||||
set -e
|
||||
@@ -53,24 +54,21 @@ jobs:
|
||||
sudo apt-get install linux-modules-extra-$(uname -r)
|
||||
- name: Install nftables
|
||||
run: sudo apt-get install nftables
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
go-version-file: go.mod
|
||||
- name: Set up Go for root
|
||||
run: |
|
||||
sudo ln -sf `which go` `sudo which go` || true
|
||||
sudo go version
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install test binaries
|
||||
env:
|
||||
GO111MODULE: off
|
||||
run: |
|
||||
go get github.com/containernetworking/cni/cnitool
|
||||
go get github.com/mattn/goveralls
|
||||
go get github.com/modocache/gover
|
||||
go install github.com/containernetworking/cni/cnitool@latest
|
||||
go install github.com/mattn/goveralls@latest
|
||||
go install github.com/modocache/gover@latest
|
||||
|
||||
- name: test
|
||||
run: PATH=$PATH:$(go env GOPATH)/bin COVERALLS=1 ./test_linux.sh
|
||||
@@ -87,10 +85,10 @@ jobs:
|
||||
needs: build
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: setup go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- uses: actions/checkout@v3
|
||||
go-version-file: go.mod
|
||||
- name: test
|
||||
run: bash ./test_windows.sh
|
||||
|
||||
@@ -6,6 +6,8 @@ issues:
|
||||
- linters:
|
||||
- revive
|
||||
text: " and that stutters;"
|
||||
- path: '(.+)_test\.go'
|
||||
text: "dot-imports: should not use dot imports"
|
||||
|
||||
linters:
|
||||
disable:
|
||||
@@ -40,3 +42,4 @@ linters-settings:
|
||||
run:
|
||||
skip-dirs:
|
||||
- vendor
|
||||
timeout: 5m
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
export GOOS="${GOOS:-linux}"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
|
||||
44
go.mod
44
go.mod
@@ -3,42 +3,46 @@ module github.com/containernetworking/plugins
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/Microsoft/hcsshim v0.9.9
|
||||
github.com/alexflint/go-filemutex v1.2.0
|
||||
github.com/Microsoft/hcsshim v0.12.3
|
||||
github.com/alexflint/go-filemutex v1.3.0
|
||||
github.com/buger/jsonparser v1.1.1
|
||||
github.com/containernetworking/cni v1.1.2
|
||||
github.com/coreos/go-iptables v0.6.0
|
||||
github.com/coreos/go-iptables v0.7.0
|
||||
github.com/coreos/go-systemd/v22 v22.5.0
|
||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c
|
||||
github.com/d2g/dhcp4client v1.0.0
|
||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5
|
||||
github.com/godbus/dbus/v5 v5.1.0
|
||||
github.com/mattn/go-shellwords v1.0.12
|
||||
github.com/networkplumbing/go-nft v0.3.0
|
||||
github.com/onsi/ginkgo/v2 v2.9.2
|
||||
github.com/onsi/gomega v1.27.6
|
||||
github.com/networkplumbing/go-nft v0.4.0
|
||||
github.com/onsi/ginkgo/v2 v2.19.0
|
||||
github.com/onsi/gomega v1.33.1
|
||||
github.com/opencontainers/selinux v1.11.0
|
||||
github.com/safchain/ethtool v0.3.0
|
||||
github.com/safchain/ethtool v0.4.0
|
||||
github.com/vishvananda/netlink v1.2.1-beta.2
|
||||
golang.org/x/sys v0.7.0
|
||||
golang.org/x/sys v0.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/go-logr/logr v1.2.4 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.2 // indirect
|
||||
github.com/containerd/errdefs v0.1.0 // indirect
|
||||
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4 // indirect
|
||||
github.com/go-logr/logr v1.4.1 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/tools v0.21.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
|
||||
google.golang.org/grpc v1.62.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
@@ -60,6 +61,13 @@ var _ = Describe("Basic PTP using cnitool", func() {
|
||||
netConfPath, err := filepath.Abs("./testdata")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Flush ipam stores to avoid conflicts
|
||||
err = os.RemoveAll("/tmp/chained-ptp-bandwidth-test")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = os.RemoveAll("/tmp/basic-ptp-test")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
env = TestEnv([]string{
|
||||
"CNI_PATH=" + cniPath,
|
||||
"NETCONFPATH=" + netConfPath,
|
||||
@@ -82,6 +90,7 @@ var _ = Describe("Basic PTP using cnitool", func() {
|
||||
env.runInNS(hostNS, cnitoolBin, "add", netName, contNS.LongName())
|
||||
|
||||
addrOutput := env.runInNS(contNS, "ip", "addr")
|
||||
|
||||
Expect(addrOutput).To(ContainSubstring(expectedIPPrefix))
|
||||
|
||||
env.runInNS(hostNS, cnitoolBin, "del", netName, contNS.LongName())
|
||||
@@ -145,9 +154,13 @@ var _ = Describe("Basic PTP using cnitool", func() {
|
||||
|
||||
chainedBridgeBandwidthEnv.runInNS(hostNS, cnitoolBin, "del", "network-chain-test", contNS1.LongName())
|
||||
basicBridgeEnv.runInNS(hostNS, cnitoolBin, "del", "network-chain-test", contNS2.LongName())
|
||||
|
||||
contNS1.Del()
|
||||
contNS2.Del()
|
||||
hostNS.Del()
|
||||
})
|
||||
|
||||
Measure("limits traffic only on the restricted bandwidth veth device", func(b Benchmarker) {
|
||||
It("limits traffic only on the restricted bandwidth veth device", func() {
|
||||
ipRegexp := regexp.MustCompile(`10\.1[12]\.2\.\d{1,3}`)
|
||||
|
||||
By(fmt.Sprintf("adding %s to %s\n\n", "chained-bridge-bandwidth", contNS1.ShortName()))
|
||||
@@ -168,21 +181,23 @@ var _ = Describe("Basic PTP using cnitool", func() {
|
||||
By(fmt.Sprintf("starting echo server in %s\n\n", contNS2.ShortName()))
|
||||
basicBridgePort, basicBridgeSession = startEchoServerInNamespace(contNS2)
|
||||
|
||||
packetInBytes := 20000 // The shaper needs to 'warm'. Send enough to cause it to throttle,
|
||||
// balanced by run time.
|
||||
packetInBytes := 3000
|
||||
|
||||
By(fmt.Sprintf("sending tcp traffic to the chained, bridged, traffic shaped container on ip address '%s:%d'\n\n", chainedBridgeIP, chainedBridgeBandwidthPort))
|
||||
runtimeWithLimit := b.Time("with chained bridge and bandwidth plugins", func() {
|
||||
makeTCPClientInNS(hostNS.ShortName(), chainedBridgeIP, chainedBridgeBandwidthPort, packetInBytes)
|
||||
})
|
||||
start := time.Now()
|
||||
makeTCPClientInNS(hostNS.ShortName(), chainedBridgeIP, chainedBridgeBandwidthPort, packetInBytes)
|
||||
runtimeWithLimit := time.Since(start)
|
||||
|
||||
log.Printf("Runtime with qos limit %.2f seconds", runtimeWithLimit.Seconds())
|
||||
|
||||
By(fmt.Sprintf("sending tcp traffic to the basic bridged container on ip address '%s:%d'\n\n", basicBridgeIP, basicBridgePort))
|
||||
runtimeWithoutLimit := b.Time("with basic bridged plugin", func() {
|
||||
makeTCPClientInNS(hostNS.ShortName(), basicBridgeIP, basicBridgePort, packetInBytes)
|
||||
})
|
||||
start = time.Now()
|
||||
makeTCPClientInNS(hostNS.ShortName(), basicBridgeIP, basicBridgePort, packetInBytes)
|
||||
runtimeWithoutLimit := time.Since(start)
|
||||
log.Printf("Runtime without qos limit %.2f seconds", runtimeWithLimit.Seconds())
|
||||
|
||||
Expect(runtimeWithLimit).To(BeNumerically(">", runtimeWithoutLimit+1000*time.Millisecond))
|
||||
}, 1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
3
integration/testdata/basic-ptp.json
vendored
3
integration/testdata/basic-ptp.json
vendored
@@ -6,6 +6,7 @@
|
||||
"mtu": 512,
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.1.2.0/24"
|
||||
"subnet": "10.1.2.0/24",
|
||||
"dataDir": "/tmp/basic-ptp-test"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"mtu": 512,
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.9.2.0/24"
|
||||
"subnet": "10.9.2.0/24",
|
||||
"dataDir": "/tmp/chained-ptp-bandwidth-test"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -90,7 +90,7 @@ func makeVeth(name, vethPeerName string, mtu int, mac string, hostNS ns.NetNS) (
|
||||
if peerExists(peerName) && vethPeerName == "" {
|
||||
continue
|
||||
}
|
||||
return peerName, veth, fmt.Errorf("container veth name provided (%v) already exists", name)
|
||||
return peerName, veth, fmt.Errorf("container veth name (%q) peer provided (%q) already exists", name, peerName)
|
||||
default:
|
||||
return peerName, veth, fmt.Errorf("failed to make veth pair: %v", err)
|
||||
}
|
||||
|
||||
@@ -149,9 +149,9 @@ var _ = Describe("Link", func() {
|
||||
It("returns useful error", func() {
|
||||
_ = containerNetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err := ip.SetupVeth(containerVethName, mtu, "", hostNetNS)
|
||||
Expect(err.Error()).To(Equal(fmt.Sprintf("container veth name provided (%s) already exists", containerVethName)))
|
||||
testHostVethName := "test" + hostVethName
|
||||
_, _, err := ip.SetupVethWithName(containerVethName, testHostVethName, mtu, "", hostNetNS)
|
||||
Expect(err.Error()).To(Equal(fmt.Sprintf("container veth name (%q) peer provided (%q) already exists", containerVethName, testHostVethName)))
|
||||
|
||||
return nil
|
||||
})
|
||||
@@ -180,9 +180,8 @@ var _ = Describe("Link", func() {
|
||||
It("returns useful error", func() {
|
||||
_ = containerNetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
_, _, err := ip.SetupVeth(containerVethName, mtu, "", hostNetNS)
|
||||
Expect(err.Error()).To(HavePrefix("container veth name provided"))
|
||||
Expect(err.Error()).To(HaveSuffix("already exists"))
|
||||
_, _, err := ip.SetupVethWithName(containerVethName, hostVethName, mtu, "", hostNetNS)
|
||||
Expect(err.Error()).To(Equal(fmt.Sprintf("container veth name (%q) peer provided (%q) already exists", containerVethName, hostVethName)))
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,7 +30,7 @@ const (
|
||||
)
|
||||
|
||||
type NftConfigurer interface {
|
||||
Apply(*nft.Config) error
|
||||
Apply(*nft.Config) (*nft.Config, error)
|
||||
Read(filterCommands ...string) (*nft.Config, error)
|
||||
}
|
||||
|
||||
@@ -39,12 +39,16 @@ type SpoofChecker struct {
|
||||
macAddress string
|
||||
refID string
|
||||
configurer NftConfigurer
|
||||
rulestore *nft.Config
|
||||
}
|
||||
|
||||
type defaultNftConfigurer struct{}
|
||||
|
||||
func (dnc defaultNftConfigurer) Apply(cfg *nft.Config) error {
|
||||
return nft.ApplyConfig(cfg)
|
||||
func (dnc defaultNftConfigurer) Apply(cfg *nft.Config) (*nft.Config, error) {
|
||||
const timeout = 55 * time.Second
|
||||
ctxWithTimeout, cancelFunc := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancelFunc()
|
||||
return nft.ApplyConfigEcho(ctxWithTimeout, cfg)
|
||||
}
|
||||
|
||||
func (dnc defaultNftConfigurer) Read(filterCommands ...string) (*nft.Config, error) {
|
||||
@@ -59,7 +63,7 @@ func NewSpoofChecker(iface, macAddress, refID string) *SpoofChecker {
|
||||
}
|
||||
|
||||
func NewSpoofCheckerWithConfigurer(iface, macAddress, refID string, configurer NftConfigurer) *SpoofChecker {
|
||||
return &SpoofChecker{iface, macAddress, refID, configurer}
|
||||
return &SpoofChecker{iface, macAddress, refID, configurer, nil}
|
||||
}
|
||||
|
||||
// Setup applies nftables configuration to restrict traffic
|
||||
@@ -88,7 +92,7 @@ func (sc *SpoofChecker) Setup() error {
|
||||
macChain := sc.macChain(ifaceChain.Name)
|
||||
baseConfig.AddChain(macChain)
|
||||
|
||||
if err := sc.configurer.Apply(baseConfig); err != nil {
|
||||
if _, err := sc.configurer.Apply(baseConfig); err != nil {
|
||||
return fmt.Errorf("failed to setup spoof-check: %v", err)
|
||||
}
|
||||
|
||||
@@ -102,37 +106,51 @@ func (sc *SpoofChecker) Setup() error {
|
||||
rulesConfig.AddRule(sc.matchMacRule(macChain.Name))
|
||||
rulesConfig.AddRule(sc.dropRule(macChain.Name))
|
||||
|
||||
if err := sc.configurer.Apply(rulesConfig); err != nil {
|
||||
rulestore, err := sc.configurer.Apply(rulesConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to setup spoof-check: %v", err)
|
||||
}
|
||||
sc.rulestore = rulestore
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sc *SpoofChecker) findPreroutingRule(ruleToFind *schema.Rule) ([]*schema.Rule, error) {
|
||||
ruleset := sc.rulestore
|
||||
if ruleset == nil {
|
||||
chain, err := sc.configurer.Read(listChainBridgeNatPrerouting()...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ruleset = chain
|
||||
}
|
||||
return ruleset.LookupRule(ruleToFind), nil
|
||||
}
|
||||
|
||||
// Teardown removes the interface and mac-address specific chains and their rules.
|
||||
// The table and base-chain are expected to survive while the base-chain rule that matches the
|
||||
// interface is removed.
|
||||
func (sc *SpoofChecker) Teardown() error {
|
||||
ifaceChain := sc.ifaceChain()
|
||||
currentConfig, ifaceMatchRuleErr := sc.configurer.Read(listChainBridgeNatPrerouting()...)
|
||||
if ifaceMatchRuleErr == nil {
|
||||
expectedRuleToFind := sc.matchIfaceJumpToChainRule(preRoutingBaseChainName, ifaceChain.Name)
|
||||
// It is safer to exclude the statement matching, avoiding cases where a current statement includes
|
||||
// additional default entries (e.g. counters).
|
||||
ruleToFindExcludingStatements := *expectedRuleToFind
|
||||
ruleToFindExcludingStatements.Expr = nil
|
||||
rules := currentConfig.LookupRule(&ruleToFindExcludingStatements)
|
||||
if len(rules) > 0 {
|
||||
c := nft.NewConfig()
|
||||
for _, rule := range rules {
|
||||
c.DeleteRule(rule)
|
||||
}
|
||||
if err := sc.configurer.Apply(c); err != nil {
|
||||
ifaceMatchRuleErr = fmt.Errorf("failed to delete iface match rule: %v", err)
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "spoofcheck/teardown: unable to detect iface match rule for deletion: %+v", expectedRuleToFind)
|
||||
expectedRuleToFind := sc.matchIfaceJumpToChainRule(preRoutingBaseChainName, ifaceChain.Name)
|
||||
// It is safer to exclude the statement matching, avoiding cases where a current statement includes
|
||||
// additional default entries (e.g. counters).
|
||||
ruleToFindExcludingStatements := *expectedRuleToFind
|
||||
ruleToFindExcludingStatements.Expr = nil
|
||||
|
||||
rules, ifaceMatchRuleErr := sc.findPreroutingRule(&ruleToFindExcludingStatements)
|
||||
if ifaceMatchRuleErr == nil && len(rules) > 0 {
|
||||
c := nft.NewConfig()
|
||||
for _, rule := range rules {
|
||||
c.DeleteRule(rule)
|
||||
}
|
||||
if _, err := sc.configurer.Apply(c); err != nil {
|
||||
ifaceMatchRuleErr = fmt.Errorf("failed to delete iface match rule: %v", err)
|
||||
}
|
||||
// Drop the cache, it should contain deleted rule(s) now
|
||||
sc.rulestore = nil
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "spoofcheck/teardown: unable to detect iface match rule for deletion: %+v", expectedRuleToFind)
|
||||
}
|
||||
|
||||
regularChainsConfig := nft.NewConfig()
|
||||
@@ -140,7 +158,7 @@ func (sc *SpoofChecker) Teardown() error {
|
||||
regularChainsConfig.DeleteChain(sc.macChain(ifaceChain.Name))
|
||||
|
||||
var regularChainsErr error
|
||||
if err := sc.configurer.Apply(regularChainsConfig); err != nil {
|
||||
if _, err := sc.configurer.Apply(regularChainsConfig); err != nil {
|
||||
regularChainsErr = fmt.Errorf("failed to delete regular chains: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,25 @@ var _ = Describe("spoofcheck", func() {
|
||||
)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("echo", func() {
|
||||
It("succeeds, no read called", func() {
|
||||
c := configurerStub{}
|
||||
sc := link.NewSpoofCheckerWithConfigurer(iface, mac, id, &c)
|
||||
Expect(sc.Setup()).To(Succeed())
|
||||
Expect(sc.Teardown()).To(Succeed())
|
||||
Expect(c.readCalled).To(BeFalse())
|
||||
})
|
||||
|
||||
It("succeeds, fall back to config read", func() {
|
||||
c := configurerStub{applyReturnNil: true}
|
||||
sc := link.NewSpoofCheckerWithConfigurer(iface, mac, id, &c)
|
||||
Expect(sc.Setup()).To(Succeed())
|
||||
c.readConfig = c.applyConfig[0]
|
||||
Expect(sc.Teardown()).To(Succeed())
|
||||
Expect(c.readCalled).To(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func assertExpectedRegularChainsDeletionInTeardownConfig(action configurerStub) {
|
||||
@@ -274,21 +293,28 @@ type configurerStub struct {
|
||||
failFirstApplyConfig bool
|
||||
failSecondApplyConfig bool
|
||||
failReadConfig bool
|
||||
|
||||
applyReturnNil bool
|
||||
readCalled bool
|
||||
}
|
||||
|
||||
func (a *configurerStub) Apply(c *nft.Config) error {
|
||||
func (a *configurerStub) Apply(c *nft.Config) (*nft.Config, error) {
|
||||
a.applyCounter++
|
||||
if a.failFirstApplyConfig && a.applyCounter == 1 {
|
||||
return fmt.Errorf(errorFirstApplyText)
|
||||
return nil, fmt.Errorf(errorFirstApplyText)
|
||||
}
|
||||
if a.failSecondApplyConfig && a.applyCounter == 2 {
|
||||
return fmt.Errorf(errorSecondApplyText)
|
||||
return nil, fmt.Errorf(errorSecondApplyText)
|
||||
}
|
||||
a.applyConfig = append(a.applyConfig, c)
|
||||
return nil
|
||||
if a.applyReturnNil {
|
||||
return nil, nil
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (a *configurerStub) Read(_ ...string) (*nft.Config, error) {
|
||||
a.readCalled = true
|
||||
if a.failReadConfig {
|
||||
return nil, fmt.Errorf(errorReadText)
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ var _ = Describe("Linux namespace operations", func() {
|
||||
testNsInode, err := getInodeNS(targetNetNS)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(testNsInode).NotTo(Equal(0))
|
||||
Expect(testNsInode).NotTo(Equal(uint64(0)))
|
||||
Expect(testNsInode).NotTo(Equal(origNSInode))
|
||||
})
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ func envCleanup() {
|
||||
os.Unsetenv("CNI_NETNS")
|
||||
os.Unsetenv("CNI_IFNAME")
|
||||
os.Unsetenv("CNI_CONTAINERID")
|
||||
os.Unsetenv("CNI_NETNS_OVERRIDE")
|
||||
}
|
||||
|
||||
func CmdAdd(cniNetns, cniContainerID, cniIfname string, conf []byte, f func() error) (types.Result, []byte, error) {
|
||||
@@ -37,6 +38,7 @@ func CmdAdd(cniNetns, cniContainerID, cniIfname string, conf []byte, f func() er
|
||||
os.Setenv("CNI_NETNS", cniNetns)
|
||||
os.Setenv("CNI_IFNAME", cniIfname)
|
||||
os.Setenv("CNI_CONTAINERID", cniContainerID)
|
||||
os.Setenv("CNI_NETNS_OVERRIDE", "1")
|
||||
defer envCleanup()
|
||||
|
||||
// Redirect stdout to capture plugin result
|
||||
@@ -87,6 +89,7 @@ func CmdCheck(cniNetns, cniContainerID, cniIfname string, f func() error) error
|
||||
os.Setenv("CNI_NETNS", cniNetns)
|
||||
os.Setenv("CNI_IFNAME", cniIfname)
|
||||
os.Setenv("CNI_CONTAINERID", cniContainerID)
|
||||
os.Setenv("CNI_NETNS_OVERRIDE", "1")
|
||||
defer envCleanup()
|
||||
|
||||
return f()
|
||||
@@ -102,6 +105,7 @@ func CmdDel(cniNetns, cniContainerID, cniIfname string, f func() error) error {
|
||||
os.Setenv("CNI_NETNS", cniNetns)
|
||||
os.Setenv("CNI_IFNAME", cniIfname)
|
||||
os.Setenv("CNI_CONTAINERID", cniContainerID)
|
||||
os.Setenv("CNI_NETNS_OVERRIDE", "1")
|
||||
defer envCleanup()
|
||||
|
||||
return f()
|
||||
|
||||
@@ -29,9 +29,9 @@ func EnsureChain(ipt *iptables.IPTables, table, chain string) error {
|
||||
if ipt == nil {
|
||||
return errors.New("failed to ensure iptable chain: IPTables was nil")
|
||||
}
|
||||
exists, err := ChainExists(ipt, table, chain)
|
||||
exists, err := ipt.ChainExists(table, chain)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list iptables chains: %v", err)
|
||||
return fmt.Errorf("failed to check iptables chain existence: %v", err)
|
||||
}
|
||||
if !exists {
|
||||
err = ipt.NewChain(table, chain)
|
||||
@@ -45,24 +45,6 @@ func EnsureChain(ipt *iptables.IPTables, table, chain string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChainExists checks whether an iptables chain exists.
|
||||
func ChainExists(ipt *iptables.IPTables, table, chain string) (bool, error) {
|
||||
if ipt == nil {
|
||||
return false, errors.New("failed to check iptable chain: IPTables was nil")
|
||||
}
|
||||
chains, err := ipt.ListChains(table)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, ch := range chains {
|
||||
if ch == chain {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// DeleteRule idempotently delete the iptables rule in the specified table/chain.
|
||||
// It does not return an error if the referring chain doesn't exist
|
||||
func DeleteRule(ipt *iptables.IPTables, table, chain string, rulespec ...string) error {
|
||||
|
||||
@@ -332,9 +332,17 @@ var _ = Describe("DHCP Operations", func() {
|
||||
started.Done()
|
||||
started.Wait()
|
||||
|
||||
err = originalNS.Do(func(ns.NetNS) error {
|
||||
err := originalNS.Do(func(ns.NetNS) error {
|
||||
return testutils.CmdDelWithArgs(args, func() error {
|
||||
return cmdDel(args)
|
||||
copiedArgs := &skel.CmdArgs{
|
||||
ContainerID: args.ContainerID,
|
||||
Netns: args.Netns,
|
||||
IfName: args.IfName,
|
||||
StdinData: args.StdinData,
|
||||
Path: args.Path,
|
||||
Args: args.Args,
|
||||
}
|
||||
return cmdDel(copiedArgs)
|
||||
})
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@@ -60,7 +60,7 @@ func New(network, dataDir string) (*Store, error) {
|
||||
func (s *Store) Reserve(id string, ifname string, ip net.IP, rangeID string) (bool, error) {
|
||||
fname := GetEscapedPath(s.dataDir, ip.String())
|
||||
|
||||
f, err := os.OpenFile(fname, os.O_RDWR|os.O_EXCL|os.O_CREATE, 0o644)
|
||||
f, err := os.OpenFile(fname, os.O_RDWR|os.O_EXCL|os.O_CREATE, 0o600)
|
||||
if os.IsExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
@@ -78,7 +78,7 @@ func (s *Store) Reserve(id string, ifname string, ip net.IP, rangeID string) (bo
|
||||
}
|
||||
// store the reserved ip in lastIPFile
|
||||
ipfile := GetEscapedPath(s.dataDir, lastIPFilePrefix+rangeID)
|
||||
err = os.WriteFile(ipfile, []byte(ip.String()), 0o644)
|
||||
err = os.WriteFile(ipfile, []byte(ip.String()), 0o600)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func parseResolvConf(filename string) (*types.DNS, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
dns := types.DNS{}
|
||||
scanner := bufio.NewScanner(fp)
|
||||
|
||||
@@ -47,19 +47,20 @@ const defaultBrName = "cni0"
|
||||
|
||||
type NetConf struct {
|
||||
types.NetConf
|
||||
BrName string `json:"bridge"`
|
||||
IsGW bool `json:"isGateway"`
|
||||
IsDefaultGW bool `json:"isDefaultGateway"`
|
||||
ForceAddress bool `json:"forceAddress"`
|
||||
IPMasq bool `json:"ipMasq"`
|
||||
MTU int `json:"mtu"`
|
||||
HairpinMode bool `json:"hairpinMode"`
|
||||
PromiscMode bool `json:"promiscMode"`
|
||||
Vlan int `json:"vlan"`
|
||||
VlanTrunk []*VlanTrunk `json:"vlanTrunk,omitempty"`
|
||||
PreserveDefaultVlan bool `json:"preserveDefaultVlan"`
|
||||
MacSpoofChk bool `json:"macspoofchk,omitempty"`
|
||||
EnableDad bool `json:"enabledad,omitempty"`
|
||||
BrName string `json:"bridge"`
|
||||
IsGW bool `json:"isGateway"`
|
||||
IsDefaultGW bool `json:"isDefaultGateway"`
|
||||
ForceAddress bool `json:"forceAddress"`
|
||||
IPMasq bool `json:"ipMasq"`
|
||||
MTU int `json:"mtu"`
|
||||
HairpinMode bool `json:"hairpinMode"`
|
||||
PromiscMode bool `json:"promiscMode"`
|
||||
Vlan int `json:"vlan"`
|
||||
VlanTrunk []*VlanTrunk `json:"vlanTrunk,omitempty"`
|
||||
PreserveDefaultVlan bool `json:"preserveDefaultVlan"`
|
||||
MacSpoofChk bool `json:"macspoofchk,omitempty"`
|
||||
EnableDad bool `json:"enabledad,omitempty"`
|
||||
DisableContainerInterface bool `json:"disableContainerInterface,omitempty"`
|
||||
|
||||
Args struct {
|
||||
Cni BridgeArgs `json:"cni,omitempty"`
|
||||
@@ -530,6 +531,10 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
|
||||
isLayer3 := n.IPAM.Type != ""
|
||||
|
||||
if isLayer3 && n.DisableContainerInterface {
|
||||
return fmt.Errorf("cannot use IPAM when DisableContainerInterface flag is set")
|
||||
}
|
||||
|
||||
if n.IsDefaultGW {
|
||||
n.IsGW = true
|
||||
}
|
||||
@@ -629,14 +634,10 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
|
||||
if n.IsGW {
|
||||
var firstV4Addr net.IP
|
||||
var vlanInterface *current.Interface
|
||||
// Set the IP address(es) on the bridge and enable forwarding
|
||||
for _, gws := range []*gwInfo{gwsV4, gwsV6} {
|
||||
for _, gw := range gws.gws {
|
||||
if gw.IP.To4() != nil && firstV4Addr == nil {
|
||||
firstV4Addr = gw.IP
|
||||
}
|
||||
if n.Vlan != 0 {
|
||||
vlanIface, err := ensureVlanInterface(br, n.Vlan, n.PreserveDefaultVlan)
|
||||
if err != nil {
|
||||
@@ -680,12 +681,13 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if !n.DisableContainerInterface {
|
||||
if err := netns.Do(func(_ ns.NetNS) error {
|
||||
link, err := netlink.LinkByName(args.IfName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to retrieve link: %v", err)
|
||||
}
|
||||
|
||||
// If layer 2 we still need to set the container veth to up
|
||||
if err = netlink.LinkSetUp(link); err != nil {
|
||||
return fmt.Errorf("failed to set %q up: %v", args.IfName, err)
|
||||
@@ -696,23 +698,28 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
}
|
||||
|
||||
var hostVeth netlink.Link
|
||||
hostVeth, err := netlink.LinkByName(hostInterface.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check bridge port state
|
||||
retries := []int{0, 50, 500, 1000, 1000}
|
||||
for idx, sleep := range retries {
|
||||
time.Sleep(time.Duration(sleep) * time.Millisecond)
|
||||
if !n.DisableContainerInterface {
|
||||
// check bridge port state
|
||||
retries := []int{0, 50, 500, 1000, 1000}
|
||||
for idx, sleep := range retries {
|
||||
time.Sleep(time.Duration(sleep) * time.Millisecond)
|
||||
|
||||
hostVeth, err = netlink.LinkByName(hostInterface.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hostVeth.Attrs().OperState == netlink.OperUp {
|
||||
break
|
||||
}
|
||||
hostVeth, err = netlink.LinkByName(hostInterface.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if hostVeth.Attrs().OperState == netlink.OperUp {
|
||||
break
|
||||
}
|
||||
|
||||
if idx == len(retries)-1 {
|
||||
return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState)
|
||||
if idx == len(retries)-1 {
|
||||
return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,7 +740,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
|
||||
// Use incoming DNS settings if provided, otherwise use the
|
||||
// settings that were already configued by the IPAM plugin
|
||||
// settings that were already configured by the IPAM plugin
|
||||
if dnsConfSet(n.DNS) {
|
||||
result.DNS = n.DNS
|
||||
}
|
||||
@@ -783,7 +790,6 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
|
||||
// so don't return an error if the device is already removed.
|
||||
|
||||
@@ -78,10 +78,12 @@ type testCase struct {
|
||||
removeDefaultVlan bool
|
||||
ipMasq bool
|
||||
macspoofchk bool
|
||||
AddErr020 string
|
||||
DelErr020 string
|
||||
AddErr010 string
|
||||
DelErr010 string
|
||||
disableContIface bool
|
||||
|
||||
AddErr020 string
|
||||
DelErr020 string
|
||||
AddErr010 string
|
||||
DelErr010 string
|
||||
|
||||
envArgs string // CNI_ARGS
|
||||
runtimeConfig struct {
|
||||
@@ -154,6 +156,9 @@ const (
|
||||
netDefault = `,
|
||||
"isDefaultGateway": true`
|
||||
|
||||
disableContainerInterface = `,
|
||||
"disableContainerInterface": true`
|
||||
|
||||
ipamStartStr = `,
|
||||
"ipam": {
|
||||
"type": "host-local"`
|
||||
@@ -248,6 +253,10 @@ func (tc testCase) netConfJSON(dataDir string) string {
|
||||
conf += fmt.Sprintf(macspoofchkFormat, tc.macspoofchk)
|
||||
}
|
||||
|
||||
if tc.disableContIface {
|
||||
conf += disableContainerInterface
|
||||
}
|
||||
|
||||
if !tc.isLayer2 {
|
||||
conf += netDefault
|
||||
if tc.subnet != "" || tc.ranges != nil {
|
||||
@@ -677,14 +686,16 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
||||
Expect(link).To(BeAssignableToTypeOf(&netlink.Veth{}))
|
||||
assertContainerInterfaceLinkState(&tc, link)
|
||||
|
||||
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
|
||||
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(addrs).To(HaveLen(len(expCIDRsV4)))
|
||||
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
|
||||
Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
assertIPv6Addresses(&tc, addrs, expCIDRsV6)
|
||||
|
||||
// Ignore link local address which may or may not be
|
||||
// ready when we read addresses.
|
||||
var foundAddrs int
|
||||
@@ -728,6 +739,15 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func assertContainerInterfaceLinkState(tc *testCase, link netlink.Link) {
|
||||
linkState := int(link.Attrs().OperState)
|
||||
if tc.disableContIface {
|
||||
Expect(linkState).ToNot(Equal(netlink.OperUp))
|
||||
} else {
|
||||
Expect(linkState).To(Equal(netlink.OperUp))
|
||||
}
|
||||
}
|
||||
|
||||
func (tester *testerV10x) cmdCheckTest(tc testCase, conf *Net, _ string) {
|
||||
// Generate network config and command arguments
|
||||
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
|
||||
@@ -1008,8 +1028,9 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(addrs).To(HaveLen(len(expCIDRsV4)))
|
||||
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6)
|
||||
Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
assertIPv6Addresses(&tc, addrs, expCIDRsV6)
|
||||
|
||||
// Ignore link local address which may or may not be
|
||||
// ready when we read addresses.
|
||||
var foundAddrs int
|
||||
@@ -1053,6 +1074,14 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func assertIPv6Addresses(tc *testCase, addrs []netlink.Addr, expCIDRsV6 []*net.IPNet) {
|
||||
if tc.disableContIface {
|
||||
Expect(addrs).To(BeEmpty())
|
||||
} else {
|
||||
Expect(addrs).To(HaveLen(len(expCIDRsV6) + 1)) // add one for the link-local
|
||||
}
|
||||
}
|
||||
|
||||
func (tester *testerV04x) cmdCheckTest(tc testCase, conf *Net, _ string) {
|
||||
// Generate network config and command arguments
|
||||
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
|
||||
@@ -2461,6 +2490,36 @@ var _ = Describe("bridge Operations", func() {
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] should fail when both IPAM and DisableContainerInterface are set", ver), func() {
|
||||
Expect(originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
tc := testCase{
|
||||
cniVersion: ver,
|
||||
subnet: "10.1.2.0/24",
|
||||
disableContIface: true,
|
||||
}
|
||||
args := tc.createCmdArgs(targetNS, dataDir)
|
||||
Expect(cmdAdd(args)).To(HaveOccurred())
|
||||
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] should set the container veth peer state down", ver), func() {
|
||||
Expect(originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
tc := testCase{
|
||||
cniVersion: ver,
|
||||
disableContIface: true,
|
||||
isLayer2: true,
|
||||
AddErr020: "cannot convert: no valid IP addresses",
|
||||
AddErr010: "cannot convert: no valid IP addresses",
|
||||
}
|
||||
cmdAddDelTest(originalNS, targetNS, tc, dataDir)
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
}
|
||||
|
||||
It("check vlan id when loading net conf", func() {
|
||||
|
||||
@@ -136,7 +136,6 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
err = netns.Do(func(_ ns.NetNS) error {
|
||||
return ipam.ConfigureIface(args.IfName, result)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -165,7 +164,6 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
|
||||
// so don't return an error if the device is already removed.
|
||||
|
||||
@@ -371,7 +371,7 @@ var _ = Describe("dummy Operations", func() {
|
||||
StdinData: []byte(fmt.Sprintf(confFmt, ver)),
|
||||
}
|
||||
|
||||
_ = originalNS.Do(func(netNS ns.NetNS) error {
|
||||
_ = originalNS.Do(func(_ ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||
|
||||
@@ -37,7 +37,10 @@ import (
|
||||
bv "github.com/containernetworking/plugins/pkg/utils/buildversion"
|
||||
)
|
||||
|
||||
var sysBusPCI = "/sys/bus/pci/devices"
|
||||
var (
|
||||
sysBusPCI = "/sys/bus/pci/devices"
|
||||
sysBusAuxiliary = "/sys/bus/auxiliary/devices"
|
||||
)
|
||||
|
||||
// Array of different linux drivers bound to network device needed for DPDK
|
||||
var userspaceDrivers = []string{"vfio-pci", "uio_pci_generic", "igb_uio"}
|
||||
@@ -53,6 +56,9 @@ type NetConf struct {
|
||||
RuntimeConfig struct {
|
||||
DeviceID string `json:"deviceID,omitempty"`
|
||||
} `json:"runtimeConfig,omitempty"`
|
||||
|
||||
// for internal use
|
||||
auxDevice string `json:"-"` // Auxiliary device name as appears on Auxiliary bus (/sys/bus/auxiliary)
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -62,6 +68,31 @@ func init() {
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
// handleDeviceID updates netconf fields with DeviceID runtime config
|
||||
func handleDeviceID(netconf *NetConf) error {
|
||||
deviceID := netconf.RuntimeConfig.DeviceID
|
||||
if deviceID == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if deviceID is a PCI device
|
||||
pciPath := filepath.Join(sysBusPCI, deviceID)
|
||||
if _, err := os.Stat(pciPath); err == nil {
|
||||
netconf.PCIAddr = deviceID
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if deviceID is an Auxiliary device
|
||||
auxPath := filepath.Join(sysBusAuxiliary, deviceID)
|
||||
if _, err := os.Stat(auxPath); err == nil {
|
||||
netconf.PCIAddr = ""
|
||||
netconf.auxDevice = deviceID
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("runtime config DeviceID %s not found or unsupported", deviceID)
|
||||
}
|
||||
|
||||
func loadConf(bytes []byte) (*NetConf, error) {
|
||||
n := &NetConf{}
|
||||
var err error
|
||||
@@ -69,12 +100,12 @@ func loadConf(bytes []byte) (*NetConf, error) {
|
||||
return nil, fmt.Errorf("failed to load netconf: %v", err)
|
||||
}
|
||||
|
||||
if n.RuntimeConfig.DeviceID != "" {
|
||||
// Override PCI device with the standardized DeviceID provided in Runtime Config.
|
||||
n.PCIAddr = n.RuntimeConfig.DeviceID
|
||||
// Override device with the standardized DeviceID if provided in Runtime Config.
|
||||
if err := handleDeviceID(n); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n.Device == "" && n.HWAddr == "" && n.KernelPath == "" && n.PCIAddr == "" {
|
||||
if n.Device == "" && n.HWAddr == "" && n.KernelPath == "" && n.PCIAddr == "" && n.auxDevice == "" {
|
||||
return nil, fmt.Errorf(`specify either "device", "hwaddr", "kernelpath" or "pciBusID"`)
|
||||
}
|
||||
|
||||
@@ -102,7 +133,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
result := ¤t.Result{}
|
||||
var contDev netlink.Link
|
||||
if !cfg.DPDKMode {
|
||||
hostDev, err := getLink(cfg.Device, cfg.HWAddr, cfg.KernelPath, cfg.PCIAddr)
|
||||
hostDev, err := getLink(cfg.Device, cfg.HWAddr, cfg.KernelPath, cfg.PCIAddr, cfg.auxDevice)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find host device: %v", err)
|
||||
}
|
||||
@@ -199,34 +230,112 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setTempName sets a temporary name for netdevice, returns updated Link object or error
|
||||
// if occurred.
|
||||
func setTempName(dev netlink.Link) (netlink.Link, error) {
|
||||
tempName := fmt.Sprintf("%s%d", "temp_", dev.Attrs().Index)
|
||||
|
||||
// rename to tempName
|
||||
if err := netlink.LinkSetName(dev, tempName); err != nil {
|
||||
return nil, fmt.Errorf("failed to rename device %q to %q: %v", dev.Attrs().Name, tempName, err)
|
||||
}
|
||||
|
||||
// Get updated Link obj
|
||||
tempDev, err := netlink.LinkByName(tempName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find %q after rename to %q: %v", dev.Attrs().Name, tempName, err)
|
||||
}
|
||||
|
||||
return tempDev, nil
|
||||
}
|
||||
|
||||
func moveLinkIn(hostDev netlink.Link, containerNs ns.NetNS, ifName string) (netlink.Link, error) {
|
||||
if err := netlink.LinkSetNsFd(hostDev, int(containerNs.Fd())); err != nil {
|
||||
return nil, err
|
||||
origLinkFlags := hostDev.Attrs().Flags
|
||||
hostDevName := hostDev.Attrs().Name
|
||||
defaultNs, err := ns.GetCurrentNS()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get host namespace: %v", err)
|
||||
}
|
||||
|
||||
// Devices can be renamed only when down
|
||||
if err = netlink.LinkSetDown(hostDev); err != nil {
|
||||
return nil, fmt.Errorf("failed to set %q down: %v", hostDev.Attrs().Name, err)
|
||||
}
|
||||
|
||||
// restore original link state in case of error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if origLinkFlags&net.FlagUp == net.FlagUp && hostDev != nil {
|
||||
_ = netlink.LinkSetUp(hostDev)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
hostDev, err = setTempName(hostDev)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to rename device %q to temporary name: %v", hostDevName, err)
|
||||
}
|
||||
|
||||
// restore original netdev name in case of error
|
||||
defer func() {
|
||||
if err != nil && hostDev != nil {
|
||||
_ = netlink.LinkSetName(hostDev, hostDevName)
|
||||
}
|
||||
}()
|
||||
|
||||
if err = netlink.LinkSetNsFd(hostDev, int(containerNs.Fd())); err != nil {
|
||||
return nil, fmt.Errorf("failed to move %q to container ns: %v", hostDev.Attrs().Name, err)
|
||||
}
|
||||
|
||||
var contDev netlink.Link
|
||||
if err := containerNs.Do(func(_ ns.NetNS) error {
|
||||
tempDevName := hostDev.Attrs().Name
|
||||
if err = containerNs.Do(func(_ ns.NetNS) error {
|
||||
var err error
|
||||
contDev, err = netlink.LinkByName(hostDev.Attrs().Name)
|
||||
contDev, err = netlink.LinkByName(tempDevName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find %q: %v", hostDev.Attrs().Name, err)
|
||||
}
|
||||
// Devices can be renamed only when down
|
||||
if err = netlink.LinkSetDown(contDev); err != nil {
|
||||
return fmt.Errorf("failed to set %q down: %v", hostDev.Attrs().Name, err)
|
||||
return fmt.Errorf("failed to find %q: %v", tempDevName, err)
|
||||
}
|
||||
|
||||
// move netdev back to host namespace in case of error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = netlink.LinkSetNsFd(contDev, int(defaultNs.Fd()))
|
||||
// we need to get updated link object as link was moved back to host namepsace
|
||||
_ = defaultNs.Do(func(_ ns.NetNS) error {
|
||||
hostDev, _ = netlink.LinkByName(tempDevName)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
// Save host device name into the container device's alias property
|
||||
if err := netlink.LinkSetAlias(contDev, hostDev.Attrs().Name); err != nil {
|
||||
return fmt.Errorf("failed to set alias to %q: %v", hostDev.Attrs().Name, err)
|
||||
if err = netlink.LinkSetAlias(contDev, hostDevName); err != nil {
|
||||
return fmt.Errorf("failed to set alias to %q: %v", tempDevName, err)
|
||||
}
|
||||
// Rename container device to respect args.IfName
|
||||
if err := netlink.LinkSetName(contDev, ifName); err != nil {
|
||||
return fmt.Errorf("failed to rename device %q to %q: %v", hostDev.Attrs().Name, ifName, err)
|
||||
if err = netlink.LinkSetName(contDev, ifName); err != nil {
|
||||
return fmt.Errorf("failed to rename device %q to %q: %v", tempDevName, ifName, err)
|
||||
}
|
||||
|
||||
// restore tempDevName in case of error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = netlink.LinkSetName(contDev, tempDevName)
|
||||
}
|
||||
}()
|
||||
|
||||
// Bring container device up
|
||||
if err = netlink.LinkSetUp(contDev); err != nil {
|
||||
return fmt.Errorf("failed to set %q up: %v", ifName, err)
|
||||
}
|
||||
|
||||
// bring device down in case of error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = netlink.LinkSetDown(contDev)
|
||||
}
|
||||
}()
|
||||
|
||||
// Retrieve link again to get up-to-date name and attributes
|
||||
contDev, err = netlink.LinkByName(ifName)
|
||||
if err != nil {
|
||||
@@ -247,11 +356,14 @@ func moveLinkOut(containerNs ns.NetNS, ifName string) error {
|
||||
}
|
||||
defer defaultNs.Close()
|
||||
|
||||
return containerNs.Do(func(_ ns.NetNS) error {
|
||||
var tempName string
|
||||
var origDev netlink.Link
|
||||
err = containerNs.Do(func(_ ns.NetNS) error {
|
||||
dev, err := netlink.LinkByName(ifName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find %q: %v", ifName, err)
|
||||
}
|
||||
origDev = dev
|
||||
|
||||
// Devices can be renamed only when down
|
||||
if err = netlink.LinkSetDown(dev); err != nil {
|
||||
@@ -269,16 +381,49 @@ func moveLinkOut(containerNs ns.NetNS, ifName string) error {
|
||||
}
|
||||
}()
|
||||
|
||||
// Rename the device to its original name from the host namespace
|
||||
if err = netlink.LinkSetName(dev, dev.Attrs().Alias); err != nil {
|
||||
return fmt.Errorf("failed to restore %q to original name %q: %v", ifName, dev.Attrs().Alias, err)
|
||||
newLink, err := setTempName(dev)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rename device %q to temporary name: %v", ifName, err)
|
||||
}
|
||||
dev = newLink
|
||||
tempName = dev.Attrs().Name
|
||||
|
||||
if err = netlink.LinkSetNsFd(dev, int(defaultNs.Fd())); err != nil {
|
||||
return fmt.Errorf("failed to move %q to host netns: %v", dev.Attrs().Alias, err)
|
||||
return fmt.Errorf("failed to move %q to host netns: %v", tempName, err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Rename the device to its original name from the host namespace
|
||||
tempDev, err := netlink.LinkByName(tempName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find %q in host namespace: %v", tempName, err)
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetName(tempDev, tempDev.Attrs().Alias); err != nil {
|
||||
// move device back to container ns so it may be retired
|
||||
defer func() {
|
||||
_ = netlink.LinkSetNsFd(tempDev, int(containerNs.Fd()))
|
||||
_ = containerNs.Do(func(_ ns.NetNS) error {
|
||||
lnk, err := netlink.LinkByName(tempName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = netlink.LinkSetName(lnk, ifName)
|
||||
if origDev.Attrs().Flags&net.FlagUp == net.FlagUp {
|
||||
_ = netlink.LinkSetUp(lnk)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}()
|
||||
return fmt.Errorf("failed to restore %q to original name %q: %v", tempName, tempDev.Attrs().Alias, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasDpdkDriver(pciaddr string) (bool, error) {
|
||||
@@ -314,11 +459,19 @@ func printLink(dev netlink.Link, cniVersion string, containerNs ns.NetNS) error
|
||||
return types.PrintResult(&result, cniVersion)
|
||||
}
|
||||
|
||||
func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error) {
|
||||
links, err := netlink.LinkList()
|
||||
func linkFromPath(path string) (netlink.Link, error) {
|
||||
entries, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list node links: %v", err)
|
||||
return nil, fmt.Errorf("failed to read directory %s: %q", path, err)
|
||||
}
|
||||
if len(entries) > 0 {
|
||||
// grab the first net device
|
||||
return netlink.LinkByName(entries[0].Name())
|
||||
}
|
||||
return nil, fmt.Errorf("failed to find network device in path %s", path)
|
||||
}
|
||||
|
||||
func getLink(devname, hwaddr, kernelpath, pciaddr string, auxDev string) (netlink.Link, error) {
|
||||
switch {
|
||||
|
||||
case len(devname) > 0:
|
||||
@@ -329,6 +482,11 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
|
||||
return nil, fmt.Errorf("failed to parse MAC address %q: %v", hwaddr, err)
|
||||
}
|
||||
|
||||
links, err := netlink.LinkList()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list node links: %v", err)
|
||||
}
|
||||
|
||||
for _, link := range links {
|
||||
if bytes.Equal(link.Attrs().HardwareAddr, hwAddr) {
|
||||
return link, nil
|
||||
@@ -339,20 +497,7 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
|
||||
return nil, fmt.Errorf("kernel device path %q must be absolute and begin with /sys/devices/", kernelpath)
|
||||
}
|
||||
netDir := filepath.Join(kernelpath, "net")
|
||||
entries, err := os.ReadDir(netDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find network devices at %q", netDir)
|
||||
}
|
||||
|
||||
// Grab the first device from eg /sys/devices/pci0000:00/0000:00:19.0/net
|
||||
for _, entry := range entries {
|
||||
// Make sure it's really an interface
|
||||
for _, l := range links {
|
||||
if entry.Name() == l.Attrs().Name {
|
||||
return l, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return linkFromPath(netDir)
|
||||
case len(pciaddr) > 0:
|
||||
netDir := filepath.Join(sysBusPCI, pciaddr, "net")
|
||||
if _, err := os.Lstat(netDir); err != nil {
|
||||
@@ -363,14 +508,10 @@ func getLink(devname, hwaddr, kernelpath, pciaddr string) (netlink.Link, error)
|
||||
}
|
||||
netDir = matches[0]
|
||||
}
|
||||
entries, err := os.ReadDir(netDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read net directory %s: %q", netDir, err)
|
||||
}
|
||||
if len(entries) > 0 {
|
||||
return netlink.LinkByName(entries[0].Name())
|
||||
}
|
||||
return nil, fmt.Errorf("failed to find device name for pci address %s", pciaddr)
|
||||
return linkFromPath(netDir)
|
||||
case len(auxDev) > 0:
|
||||
netDir := filepath.Join(sysBusAuxiliary, auxDev, "net")
|
||||
return linkFromPath(netDir)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to find physical interface")
|
||||
|
||||
@@ -898,6 +898,71 @@ var _ = Describe("base functionality", func() {
|
||||
})
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("Works with a valid %s config on auxiliary device", ver), func() {
|
||||
var origLink netlink.Link
|
||||
ifname := "eth0"
|
||||
|
||||
fs := &fakeFilesystem{
|
||||
dirs: []string{
|
||||
fmt.Sprintf("sys/bus/auxiliary/devices/mlx5_core.sf.4/net/%s", ifname),
|
||||
},
|
||||
}
|
||||
defer fs.use()()
|
||||
|
||||
// prepare ifname in original namespace
|
||||
_ = originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
err := netlink.LinkAdd(&netlink.Dummy{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: ifname,
|
||||
},
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
origLink, err = netlink.LinkByName(ifname)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = netlink.LinkSetUp(origLink)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
|
||||
// call CmdAdd
|
||||
cniName := "net1"
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-host-device-test",
|
||||
"type": "host-device",
|
||||
"runtimeConfig": {"deviceID": %q}
|
||||
}`, ver, "mlx5_core.sf.4")
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
IfName: cniName,
|
||||
Netns: targetNS.Path(),
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
var resI types.Result
|
||||
err := originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
var err error
|
||||
resI, _, err = testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// check that the result was sane
|
||||
t := newTesterByVersion(ver)
|
||||
t.expectInterfaces(resI, cniName, origLink.Attrs().HardwareAddr.String(), targetNS.Path())
|
||||
|
||||
// call CmdDel
|
||||
_ = originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
err = testutils.CmdDelWithArgs(args, func() error {
|
||||
return cmdDel(args)
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("Works with a valid %s config with IPAM", ver), func() {
|
||||
var origLink netlink.Link
|
||||
|
||||
@@ -1149,6 +1214,114 @@ var _ = Describe("base functionality", func() {
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("Test CmdAdd/Del when additioinal interface alreay exists in container ns with same name. %s config", ver), func() {
|
||||
var (
|
||||
origLink netlink.Link
|
||||
containerLink netlink.Link
|
||||
)
|
||||
|
||||
hostIfname := "eth0"
|
||||
containerAdditionalIfname := "eth0"
|
||||
|
||||
// prepare host device in original namespace
|
||||
_ = originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
err := netlink.LinkAdd(&netlink.Dummy{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: hostIfname,
|
||||
},
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
origLink, err = netlink.LinkByName(hostIfname)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = netlink.LinkSetUp(origLink)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
|
||||
// prepare device in container namespace with same name as host device
|
||||
_ = targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
err := netlink.LinkAdd(&netlink.Dummy{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: containerAdditionalIfname,
|
||||
},
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
containerLink, err = netlink.LinkByName(containerAdditionalIfname)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = netlink.LinkSetUp(containerLink)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
|
||||
// call CmdAdd
|
||||
cniName := "net1"
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-host-device-test",
|
||||
"type": "host-device",
|
||||
"device": %q
|
||||
}`, ver, hostIfname)
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: targetNS.Path(),
|
||||
IfName: cniName,
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
var resI types.Result
|
||||
err := originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
var err error
|
||||
resI, _, err = testutils.CmdAddWithArgs(args, func() error { return cmdAdd(args) })
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// check that the result was sane
|
||||
t := newTesterByVersion(ver)
|
||||
t.expectInterfaces(resI, cniName, origLink.Attrs().HardwareAddr.String(), targetNS.Path())
|
||||
|
||||
// assert that host device is now in the target namespace and is up
|
||||
_ = targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
link, err := netlink.LinkByName(cniName)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().HardwareAddr).To(Equal(origLink.Attrs().HardwareAddr))
|
||||
Expect(link.Attrs().Flags & net.FlagUp).To(Equal(net.FlagUp))
|
||||
return nil
|
||||
})
|
||||
|
||||
// call CmdDel, expect it to succeed
|
||||
_ = originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
err = testutils.CmdDelWithArgs(args, func() error {
|
||||
return cmdDel(args)
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
|
||||
// assert container interface "eth0" still exists in target namespace and is up
|
||||
err = targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
link, err := netlink.LinkByName(containerAdditionalIfname)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().HardwareAddr).To(Equal(containerLink.Attrs().HardwareAddr))
|
||||
Expect(link.Attrs().Flags & net.FlagUp).To(Equal(net.FlagUp))
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// assert that host device is now back in the original namespace
|
||||
_ = originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
_, err := netlink.LinkByName(hostIfname)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1181,6 +1354,7 @@ func (fs *fakeFilesystem) use() func() {
|
||||
}
|
||||
|
||||
sysBusPCI = path.Join(fs.rootDir, "/sys/bus/pci/devices")
|
||||
sysBusAuxiliary = path.Join(fs.rootDir, "/sys/bus/auxiliary/devices")
|
||||
|
||||
return func() {
|
||||
// remove temporary fake fs
|
||||
|
||||
@@ -293,6 +293,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
|
||||
err = netns.Do(func(_ ns.NetNS) error {
|
||||
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1")
|
||||
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv6/conf/%s/ndisc_notify", args.IfName), "1")
|
||||
|
||||
return ipam.ConfigureIface(args.IfName, result)
|
||||
})
|
||||
@@ -333,7 +334,6 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
|
||||
// so don't return an error if the device is already removed.
|
||||
|
||||
@@ -351,6 +351,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
|
||||
err = netns.Do(func(_ ns.NetNS) error {
|
||||
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1")
|
||||
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv6/conf/%s/ndisc_notify", args.IfName), "1")
|
||||
|
||||
return ipam.ConfigureIface(args.IfName, result)
|
||||
})
|
||||
@@ -382,13 +383,13 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
|
||||
func cmdDel(args *skel.CmdArgs) error {
|
||||
n, _, err := loadConf(args, args.Args)
|
||||
var n NetConf
|
||||
err := json.Unmarshal(args.StdinData, &n)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to load netConf: %v", err)
|
||||
}
|
||||
|
||||
isLayer3 := n.IPAM.Type != ""
|
||||
|
||||
if isLayer3 {
|
||||
err = ipam.ExecDel(n.IPAM.Type, args.StdinData)
|
||||
if err != nil {
|
||||
@@ -410,7 +411,6 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
|
||||
// so don't return an error if the device is already removed.
|
||||
|
||||
@@ -47,6 +47,7 @@ type NetConf struct {
|
||||
Owner *uint32 `json:"owner,omitempty"`
|
||||
Group *uint32 `json:"group,omitempty"`
|
||||
SelinuxContext string `json:"selinuxContext,omitempty"`
|
||||
Bridge string `json:"bridge,omitempty"`
|
||||
Args *struct{} `json:"args,omitempty"`
|
||||
RuntimeConfig struct {
|
||||
Mac string `json:"mac,omitempty"`
|
||||
@@ -216,6 +217,18 @@ func createTap(conf *NetConf, ifName string, netns ns.NetNS) (*current.Interface
|
||||
return fmt.Errorf("failed to refetch tap %q: %v", ifName, err)
|
||||
}
|
||||
|
||||
if conf.Bridge != "" {
|
||||
bridge, err := netlink.LinkByName(conf.Bridge)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get bridge %s: %v", conf.Bridge, err)
|
||||
}
|
||||
|
||||
tapDev := link
|
||||
if err := netlink.LinkSetMaster(tapDev, bridge); err != nil {
|
||||
return fmt.Errorf("failed to set tap %s as a port of bridge %s: %v", tap.Name, conf.Bridge, err)
|
||||
}
|
||||
}
|
||||
|
||||
err = netlink.LinkSetUp(link)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to set tap interface up: %v", err)
|
||||
@@ -358,7 +371,6 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
|
||||
// so don't return an error if the device is already removed.
|
||||
|
||||
@@ -314,5 +314,120 @@ var _ = Describe("Add, check, remove tap plugin", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] add, check and remove a tap device as a bridge port", ver), func() {
|
||||
const bridgeName = "br1"
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "tapTest",
|
||||
"type": "tap",
|
||||
"owner": 0,
|
||||
"group": 0,
|
||||
"bridge": %q,
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.1.2.0/24",
|
||||
"dataDir": "%s"
|
||||
}
|
||||
}`, ver, bridgeName, dataDir)
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: targetNS.Path(),
|
||||
IfName: IFNAME,
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
t := newTesterByVersion(ver)
|
||||
|
||||
var bridge netlink.Link
|
||||
var result types.Result
|
||||
var macAddress string
|
||||
var err error
|
||||
|
||||
Expect(
|
||||
targetNS.Do(func(ns.NetNS) error {
|
||||
if err := netlink.LinkAdd(&netlink.Bridge{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: bridgeName,
|
||||
},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
bridge, err = netlink.LinkByName(bridgeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
).To(Succeed())
|
||||
|
||||
err = originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
result, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||
return cmdAdd(args)
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
macAddress = t.verifyResult(result, IFNAME)
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Make sure the tap link exists in the target namespace")
|
||||
err = targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
link, err := netlink.LinkByName(IFNAME)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().Name).To(Equal(IFNAME))
|
||||
Expect(link.Type()).To(Equal(TYPETAP))
|
||||
Expect(link.Attrs().MasterIndex).To(Equal(bridge.Attrs().Index))
|
||||
|
||||
if macAddress != "" {
|
||||
hwaddr, err := net.ParseMAC(macAddress)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
|
||||
}
|
||||
addrs, err := netlink.AddrList(link, syscall.AF_INET)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(addrs).To(HaveLen(1))
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Running cmdDel")
|
||||
args.StdinData = []byte(conf)
|
||||
err = originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
err = testutils.CmdDelWithArgs(args, func() error {
|
||||
return cmdDel(args)
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
link, err := netlink.LinkByName(IFNAME)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(link).To(BeNil())
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Running cmdDel more than once without error")
|
||||
err = originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
err = testutils.CmdDelWithArgs(args, func() error {
|
||||
return cmdDel(args)
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -244,7 +244,6 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
|
||||
// so don't return an error if the device is already removed.
|
||||
|
||||
@@ -499,7 +499,7 @@ var _ = Describe("vlan Operations", func() {
|
||||
StdinData: []byte(fmt.Sprintf(confFmt, ver, masterInterface, 1600, isInContainer, dataDir)),
|
||||
}
|
||||
|
||||
_ = originalNS.Do(func(netNS ns.NetNS) error {
|
||||
_ = originalNS.Do(func(_ ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||
@@ -520,7 +520,7 @@ var _ = Describe("vlan Operations", func() {
|
||||
StdinData: []byte(fmt.Sprintf(confFmt, ver, masterInterface, -100, isInContainer, dataDir)),
|
||||
}
|
||||
|
||||
_ = originalNS.Do(func(netNS ns.NetNS) error {
|
||||
_ = originalNS.Do(func(_ ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err = testutils.CmdAddWithArgs(args, func() error {
|
||||
|
||||
563
plugins/meta/bandwidth/bandwidth_config_test.go
Normal file
563
plugins/meta/bandwidth/bandwidth_config_test.go
Normal file
@@ -0,0 +1,563 @@
|
||||
// Copyright 2023 CNI authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vishvananda/netlink"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
types100 "github.com/containernetworking/cni/pkg/types/100"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
"github.com/containernetworking/plugins/pkg/testutils"
|
||||
)
|
||||
|
||||
var _ = Describe("bandwidth config test", func() {
|
||||
var (
|
||||
hostNs ns.NetNS
|
||||
containerNs ns.NetNS
|
||||
ifbDeviceName string
|
||||
hostIfname string
|
||||
containerIfname string
|
||||
hostIP net.IP
|
||||
containerIP net.IP
|
||||
hostIfaceMTU int
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
|
||||
hostIfname = "host-veth"
|
||||
containerIfname = "container-veth"
|
||||
|
||||
hostNs, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerNs, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
hostIP = net.IP{169, 254, 0, 1}
|
||||
containerIP = net.IP{10, 254, 0, 1}
|
||||
hostIfaceMTU = 1024
|
||||
ifbDeviceName = "bwpa8eda89404b7"
|
||||
|
||||
createVeth(hostNs, hostIfname, containerNs, containerIfname, hostIP, containerIP, hostIfaceMTU)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(containerNs.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerNs)).To(Succeed())
|
||||
Expect(hostNs.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(hostNs)).To(Succeed())
|
||||
})
|
||||
|
||||
// Bandwidth requires host-side interface info, and thus only
|
||||
// supports 0.3.0 and later CNI versions
|
||||
for _, ver := range []string{"0.3.0", "0.3.1", "0.4.0", "1.0.0"} {
|
||||
// Redefine ver inside for scope so real value is picked up by each dynamically defined It()
|
||||
// See Gingkgo's "Patterns for dynamically generating tests" documentation.
|
||||
ver := ver
|
||||
|
||||
Describe("cmdADD", func() {
|
||||
It(fmt.Sprintf("[%s] fails with invalid UnshapedSubnets", ver), func() {
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-bandwidth-test",
|
||||
"type": "bandwidth",
|
||||
"ingressRate": 123,
|
||||
"ingressBurst": 123,
|
||||
"egressRate": 123,
|
||||
"egressBurst": 123,
|
||||
"unshapedSubnets": ["10.0.0.0/8", "hello"],
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": ""
|
||||
},
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": "%s"
|
||||
}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "%s/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 1
|
||||
}
|
||||
],
|
||||
"routes": []
|
||||
}
|
||||
}`, ver, hostIfname, containerIfname, containerNs.Path(), containerIP.String())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: containerNs.Path(),
|
||||
IfName: "eth0",
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
Expect(hostNs.Do(func(netNS ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
|
||||
Expect(err).To(MatchError("bad subnet \"hello\" provided, details invalid CIDR address: hello"))
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] fails with invalid ShapedSubnets", ver), func() {
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-bandwidth-test",
|
||||
"type": "bandwidth",
|
||||
"ingressRate": 123,
|
||||
"ingressBurst": 123,
|
||||
"egressRate": 123,
|
||||
"egressBurst": 123,
|
||||
"ShapedSubnets": ["10.0.0.0/8", "hello"],
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": ""
|
||||
},
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": "%s"
|
||||
}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "%s/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 1
|
||||
}
|
||||
],
|
||||
"routes": []
|
||||
}
|
||||
}`, ver, hostIfname, containerIfname, containerNs.Path(), containerIP.String())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: containerNs.Path(),
|
||||
IfName: "eth0",
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
Expect(hostNs.Do(func(netNS ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
|
||||
Expect(err).To(MatchError("bad subnet \"hello\" provided, details invalid CIDR address: hello"))
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] fails with both ShapedSubnets and UnshapedSubnets specified", ver), func() {
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-bandwidth-test",
|
||||
"type": "bandwidth",
|
||||
"ingressRate": 123,
|
||||
"ingressBurst": 123,
|
||||
"egressRate": 123,
|
||||
"egressBurst": 123,
|
||||
"shapedSubnets": ["10.0.0.0/8"],
|
||||
"unshapedSubnets": ["192.168.0.0/16"],
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": ""
|
||||
},
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": "%s"
|
||||
}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "%s/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 1
|
||||
}
|
||||
],
|
||||
"routes": []
|
||||
}
|
||||
}`, ver, hostIfname, containerIfname, containerNs.Path(), containerIP.String())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: containerNs.Path(),
|
||||
IfName: "eth0",
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
Expect(hostNs.Do(func(netNS ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
|
||||
Expect(err).To(MatchError("unshapedSubnets and shapedSubnets cannot be both specified, one of them should be discarded"))
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] fails an invalid ingress config", ver), func() {
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-bandwidth-test",
|
||||
"type": "bandwidth",
|
||||
"ingressRate": 0,
|
||||
"ingressBurst": 123,
|
||||
"egressRate": 123,
|
||||
"egressBurst": 123,
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": ""
|
||||
},
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": "%s"
|
||||
}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "%s/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 1
|
||||
}
|
||||
],
|
||||
"routes": []
|
||||
}
|
||||
}`, ver, hostIfname, containerIfname, containerNs.Path(), containerIP.String())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: containerNs.Path(),
|
||||
IfName: "eth0",
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
Expect(hostNs.Do(func(netNS ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
|
||||
Expect(err).To(MatchError("if burst is set, rate must also be set"))
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] fails an invalid egress config", ver), func() {
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-bandwidth-test",
|
||||
"type": "bandwidth",
|
||||
"ingressRate": 123,
|
||||
"ingressBurst": 123,
|
||||
"egressRate": 0,
|
||||
"egressBurst": 123,
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": ""
|
||||
},
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": "%s"
|
||||
}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "%s/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 1
|
||||
}
|
||||
],
|
||||
"routes": []
|
||||
}
|
||||
}`, ver, hostIfname, containerIfname, containerNs.Path(), containerIP.String())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: containerNs.Path(),
|
||||
IfName: "eth0",
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
Expect(hostNs.Do(func(netNS ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
|
||||
Expect(err).To(MatchError("if burst is set, rate must also be set"))
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
|
||||
// Runtime config parameters are expected to be preempted by the global config ones whenever specified
|
||||
It(fmt.Sprintf("[%s] should apply static config when both static config and runtime config exist", ver), func() {
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-bandwidth-test",
|
||||
"type": "bandwidth",
|
||||
"ingressRate": 0,
|
||||
"ingressBurst": 0,
|
||||
"egressRate": 123,
|
||||
"egressBurst": 123,
|
||||
"unshapedSubnets": ["192.168.0.0/24"],
|
||||
"runtimeConfig": {
|
||||
"bandWidth": {
|
||||
"ingressRate": 8,
|
||||
"ingressBurst": 8,
|
||||
"egressRate": 16,
|
||||
"egressBurst": 9,
|
||||
"unshapedSubnets": ["10.0.0.0/8", "fd00:db8:abcd:1234:e000::/68"]
|
||||
}
|
||||
},
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": ""
|
||||
},
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": "%s"
|
||||
}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "%s/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 1
|
||||
}
|
||||
],
|
||||
"routes": []
|
||||
}
|
||||
}`, ver, hostIfname, containerIfname, containerNs.Path(), containerIP.String())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: containerNs.Path(),
|
||||
IfName: containerIfname,
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
Expect(hostNs.Do(func(netNS ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
r, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
|
||||
Expect(err).NotTo(HaveOccurred(), string(out))
|
||||
result, err := types100.GetResult(r)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(result.Interfaces).To(HaveLen(3))
|
||||
Expect(result.Interfaces[2].Name).To(Equal(ifbDeviceName))
|
||||
Expect(result.Interfaces[2].Sandbox).To(Equal(""))
|
||||
|
||||
ifbLink, err := netlink.LinkByName(ifbDeviceName)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ifbLink.Attrs().MTU).To(Equal(hostIfaceMTU))
|
||||
|
||||
qdiscs, err := netlink.QdiscList(ifbLink)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(qdiscs).To(HaveLen(1))
|
||||
Expect(qdiscs[0].Attrs().LinkIndex).To(Equal(ifbLink.Attrs().Index))
|
||||
Expect(qdiscs[0]).To(BeAssignableToTypeOf(&netlink.Htb{}))
|
||||
Expect(qdiscs[0].(*netlink.Htb).Defcls).To(Equal(uint32(ShapedClassMinorID)))
|
||||
|
||||
classes, err := netlink.ClassList(ifbLink, qdiscs[0].Attrs().Handle)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(classes).To(HaveLen(2))
|
||||
|
||||
// Uncapped class
|
||||
Expect(classes[0]).To(BeAssignableToTypeOf(&netlink.HtbClass{}))
|
||||
Expect(classes[0].(*netlink.HtbClass).Handle).To(Equal(netlink.MakeHandle(1, 1)))
|
||||
Expect(classes[0].(*netlink.HtbClass).Rate).To(Equal(UncappedRate))
|
||||
Expect(classes[0].(*netlink.HtbClass).Buffer).To(Equal(uint32(0)))
|
||||
Expect(classes[0].(*netlink.HtbClass).Ceil).To(Equal(UncappedRate))
|
||||
Expect(classes[0].(*netlink.HtbClass).Cbuffer).To(Equal(uint32(0)))
|
||||
|
||||
// Class with traffic shapping settings
|
||||
Expect(classes[1]).To(BeAssignableToTypeOf(&netlink.HtbClass{}))
|
||||
Expect(classes[1].(*netlink.HtbClass).Handle).To(Equal(netlink.MakeHandle(1, uint16(qdiscs[0].(*netlink.Htb).Defcls))))
|
||||
Expect(classes[1].(*netlink.HtbClass).Rate).To(Equal(uint64(15)))
|
||||
// Expect(classes[1].(*netlink.HtbClass).Buffer).To(Equal(uint32(7812500)))
|
||||
Expect(classes[1].(*netlink.HtbClass).Ceil).To(Equal(uint64(30)))
|
||||
// Expect(classes[1].(*netlink.HtbClass).Cbuffer).To(Equal(uint32(0)))
|
||||
|
||||
filters, err := netlink.FilterList(ifbLink, qdiscs[0].Attrs().Handle)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(filters).To(HaveLen(1))
|
||||
|
||||
// traffic to 192.168.0.0/24 redirected to uncapped class
|
||||
Expect(filters[0]).To(BeAssignableToTypeOf(&netlink.U32{}))
|
||||
Expect(filters[0].(*netlink.U32).Actions).To(BeEmpty())
|
||||
Expect(filters[0].Attrs().Protocol).To(Equal(uint16(syscall.ETH_P_IP)))
|
||||
Expect(filters[0].Attrs().LinkIndex).To(Equal(ifbLink.Attrs().Index))
|
||||
Expect(filters[0].Attrs().Priority).To(Equal(uint16(16)))
|
||||
Expect(filters[0].Attrs().Parent).To(Equal(qdiscs[0].Attrs().Handle))
|
||||
Expect(filters[0].(*netlink.U32).ClassId).To(Equal(netlink.MakeHandle(1, 1)))
|
||||
|
||||
filterSel := filters[0].(*netlink.U32).Sel
|
||||
Expect(filterSel).To(BeAssignableToTypeOf(&netlink.TcU32Sel{}))
|
||||
Expect(filterSel.Flags).To(Equal(uint8(netlink.TC_U32_TERMINAL)))
|
||||
Expect(filterSel.Keys).To(HaveLen(1))
|
||||
Expect(filterSel.Nkeys).To(Equal(uint8(1)))
|
||||
|
||||
// The filter should match to 192.168.0.0/24 dst address in other words it should be:
|
||||
// match c0a80000/ffffff00 at 16
|
||||
selKey := filterSel.Keys[0]
|
||||
Expect(selKey.Val).To(Equal(uint32(192*math.Pow(256, 3) + 168*math.Pow(256, 2))))
|
||||
Expect(selKey.Off).To(Equal(int32(16)))
|
||||
Expect(selKey.Mask).To(Equal(uint32(255*math.Pow(256, 3) + 255*math.Pow(256, 2) + 255*256)))
|
||||
|
||||
hostVethLink, err := netlink.LinkByName(hostIfname)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
qdiscFilters, err := netlink.FilterList(hostVethLink, netlink.MakeHandle(0xffff, 0))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(qdiscFilters).To(HaveLen(1))
|
||||
Expect(qdiscFilters[0].(*netlink.U32).Actions[0].(*netlink.MirredAction).Ifindex).To(Equal(ifbLink.Attrs().Index))
|
||||
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
|
||||
// Container ingress (host egress)
|
||||
Expect(hostNs.Do(func(n ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
vethLink, err := netlink.LinkByName(hostIfname)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
qdiscs, err := netlink.QdiscList(vethLink)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// No ingress QoS just mirroring
|
||||
Expect(qdiscs).To(HaveLen(2))
|
||||
Expect(qdiscs[0].Attrs().LinkIndex).To(Equal(vethLink.Attrs().Index))
|
||||
Expect(qdiscs[0]).NotTo(BeAssignableToTypeOf(&netlink.Htb{}))
|
||||
Expect(qdiscs[1]).NotTo(BeAssignableToTypeOf(&netlink.Htb{}))
|
||||
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] should apply static config when both static config and runtime config exist (bad config example)", ver), func() {
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "cni-plugin-bandwidth-test",
|
||||
"type": "bandwidth",
|
||||
"ingressRate": 0,
|
||||
"ingressBurst": 123,
|
||||
"egressRate": 123,
|
||||
"egressBurst": 123,
|
||||
"runtimeConfig": {
|
||||
"bandWidth": {
|
||||
"ingressRate": 8,
|
||||
"ingressBurst": 8,
|
||||
"egressRate": 16,
|
||||
"egressBurst": 9
|
||||
}
|
||||
},
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": ""
|
||||
},
|
||||
{
|
||||
"name": "%s",
|
||||
"sandbox": "%s"
|
||||
}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "%s/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 1
|
||||
}
|
||||
],
|
||||
"routes": []
|
||||
}
|
||||
}`, ver, hostIfname, containerIfname, containerNs.Path(), containerIP.String())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: containerNs.Path(),
|
||||
IfName: "eth0",
|
||||
StdinData: []byte(conf),
|
||||
}
|
||||
|
||||
Expect(hostNs.Do(func(netNS ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
|
||||
Expect(err).To(MatchError("if burst is set, rate must also be set"))
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Describe("Validating input", func() {
|
||||
It("Should allow only 4GB burst rate", func() {
|
||||
err := validateRateAndBurst(5000, 4*1024*1024*1024*8-16) // 2 bytes less than the max should pass
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
err = validateRateAndBurst(5000, 4*1024*1024*1024*8) // we're 1 bit above MaxUint32
|
||||
Expect(err).To(HaveOccurred())
|
||||
err = validateRateAndBurst(0, 1)
|
||||
Expect(err).To(HaveOccurred())
|
||||
err = validateRateAndBurst(1, 0)
|
||||
Expect(err).To(HaveOccurred())
|
||||
err = validateRateAndBurst(0, 0)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Should fail if both ShapedSubnets and UnshapedSubnets are specified", func() {
|
||||
err := validateSubnets([]string{"10.0.0.0/8"}, []string{"192.168.0.0/24"})
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Should fail if specified UnshapedSubnets are not valid CIDRs", func() {
|
||||
err := validateSubnets([]string{"10.0.0.0/8", "hello"}, []string{})
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Should fail if specified ShapedSubnets are not valid CIDRs", func() {
|
||||
err := validateSubnets([]string{}, []string{"10.0.0.0/8", "hello"})
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
824
plugins/meta/bandwidth/bandwidth_measure_linux_test.go
Normal file
824
plugins/meta/bandwidth/bandwidth_measure_linux_test.go
Normal file
@@ -0,0 +1,824 @@
|
||||
// Copyright 2023 CNI authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/gexec"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/invoke"
|
||||
"github.com/containernetworking/cni/pkg/skel"
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
types100 "github.com/containernetworking/cni/pkg/types/100"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
"github.com/containernetworking/plugins/pkg/testutils"
|
||||
)
|
||||
|
||||
var _ = Describe("bandwidth measure test", func() {
|
||||
var (
|
||||
hostNs ns.NetNS
|
||||
containerNs ns.NetNS
|
||||
hostIfname string
|
||||
containerIfname string
|
||||
hostIP net.IP
|
||||
containerIP net.IP
|
||||
hostIfaceMTU int
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
|
||||
hostIfname = "host-veth"
|
||||
containerIfname = "container-veth"
|
||||
|
||||
hostNs, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerNs, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
hostIP = net.IP{169, 254, 0, 1}
|
||||
containerIP = net.IP{10, 254, 0, 1}
|
||||
hostIfaceMTU = 1024
|
||||
|
||||
createVeth(hostNs, hostIfname, containerNs, containerIfname, hostIP, containerIP, hostIfaceMTU)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(containerNs.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerNs)).To(Succeed())
|
||||
Expect(hostNs.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(hostNs)).To(Succeed())
|
||||
})
|
||||
|
||||
// Bandwidth requires host-side interface info, and thus only
|
||||
// supports 0.3.0 and later CNI versions
|
||||
for _, ver := range []string{"0.3.0", "0.3.1", "0.4.0", "1.0.0"} {
|
||||
Describe(fmt.Sprintf("[%s] QoS effective", ver), func() {
|
||||
Context(fmt.Sprintf("[%s] when chaining bandwidth plugin with PTP", ver), func() {
|
||||
var ptpConf string
|
||||
var rateInBits uint64
|
||||
var burstInBits uint64
|
||||
var packetInBytes int
|
||||
var containerWithoutQoSNS ns.NetNS
|
||||
var containerWithQoSNS ns.NetNS
|
||||
var portServerWithQoS int
|
||||
var portServerWithoutQoS int
|
||||
|
||||
var containerWithQoSRes types.Result
|
||||
var containerWithoutQoSRes types.Result
|
||||
var echoServerWithQoS *gexec.Session
|
||||
var echoServerWithoutQoS *gexec.Session
|
||||
var dataDir string
|
||||
|
||||
BeforeEach(func() {
|
||||
rateInBytes := 1000
|
||||
rateInBits = uint64(rateInBytes * 8)
|
||||
burstInBits = rateInBits * 2
|
||||
|
||||
// NOTE: Traffic shapping is not that precise at low rates, would be better to use higher rates + simple time+netcat for data transfer, rather than the provided
|
||||
// client/server bin (limited to small amount of data)
|
||||
packetInBytes = rateInBytes * 3
|
||||
|
||||
var err error
|
||||
dataDir, err = os.MkdirTemp("", "bandwidth_linux_test")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ptpConf = fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "myBWnet",
|
||||
"type": "ptp",
|
||||
"ipMasq": true,
|
||||
"mtu": 512,
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.1.2.0/24",
|
||||
"dataDir": "%s"
|
||||
}
|
||||
}`, ver, dataDir)
|
||||
|
||||
const (
|
||||
containerWithQoSIFName = "ptp0"
|
||||
containerWithoutQoSIFName = "ptp1"
|
||||
)
|
||||
|
||||
containerWithQoSNS, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithoutQoSNS, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("create two containers, and use the bandwidth plugin on one of them")
|
||||
Expect(hostNs.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
containerWithQoSRes, _, err = testutils.CmdAdd(containerWithQoSNS.Path(), "dummy", containerWithQoSIFName, []byte(ptpConf), func() error {
|
||||
r, err := invoke.DelegateAdd(context.TODO(), "ptp", []byte(ptpConf), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(r.Print()).To(Succeed())
|
||||
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithoutQoSRes, _, err = testutils.CmdAdd(containerWithoutQoSNS.Path(), "dummy2", containerWithoutQoSIFName, []byte(ptpConf), func() error {
|
||||
r, err := invoke.DelegateAdd(context.TODO(), "ptp", []byte(ptpConf), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(r.Print()).To(Succeed())
|
||||
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithQoSResult, err := types100.GetResult(containerWithQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
bandwidthPluginConf := &PluginConf{}
|
||||
err = json.Unmarshal([]byte(ptpConf), &bandwidthPluginConf)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
bandwidthPluginConf.RuntimeConfig.Bandwidth = &BandwidthEntry{
|
||||
IngressBurst: burstInBits,
|
||||
IngressRate: rateInBits,
|
||||
EgressBurst: burstInBits,
|
||||
EgressRate: rateInBits,
|
||||
}
|
||||
bandwidthPluginConf.Type = "bandwidth"
|
||||
newConfBytes, err := buildOneConfig(ver, bandwidthPluginConf, containerWithQoSResult)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy3",
|
||||
Netns: containerWithQoSNS.Path(),
|
||||
IfName: containerWithQoSIFName,
|
||||
StdinData: newConfBytes,
|
||||
}
|
||||
|
||||
result, out, err := testutils.CmdAdd(containerWithQoSNS.Path(), args.ContainerID, "", newConfBytes, func() error { return cmdAdd(args) })
|
||||
Expect(err).NotTo(HaveOccurred(), string(out))
|
||||
|
||||
if testutils.SpecVersionHasCHECK(ver) {
|
||||
// Do CNI Check
|
||||
checkConf := &PluginConf{}
|
||||
err = json.Unmarshal([]byte(ptpConf), &checkConf)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
checkConf.RuntimeConfig.Bandwidth = &BandwidthEntry{
|
||||
IngressBurst: burstInBits,
|
||||
IngressRate: rateInBits,
|
||||
EgressBurst: burstInBits,
|
||||
EgressRate: rateInBits,
|
||||
}
|
||||
checkConf.Type = "bandwidth"
|
||||
|
||||
newCheckBytes, err := buildOneConfig(ver, checkConf, result)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args = &skel.CmdArgs{
|
||||
ContainerID: "dummy3",
|
||||
Netns: containerWithQoSNS.Path(),
|
||||
IfName: containerWithQoSIFName,
|
||||
StdinData: newCheckBytes,
|
||||
}
|
||||
|
||||
err = testutils.CmdCheck(containerWithQoSNS.Path(), args.ContainerID, "", func() error { return cmdCheck(args) })
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
|
||||
By("starting a tcp server on both containers")
|
||||
portServerWithQoS, echoServerWithQoS = startEchoServerInNamespace(containerWithQoSNS)
|
||||
portServerWithoutQoS, echoServerWithoutQoS = startEchoServerInNamespace(containerWithoutQoSNS)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(os.RemoveAll(dataDir)).To(Succeed())
|
||||
|
||||
Expect(containerWithQoSNS.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerWithQoSNS)).To(Succeed())
|
||||
Expect(containerWithoutQoSNS.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerWithoutQoSNS)).To(Succeed())
|
||||
|
||||
if echoServerWithoutQoS != nil {
|
||||
echoServerWithoutQoS.Kill()
|
||||
}
|
||||
if echoServerWithQoS != nil {
|
||||
echoServerWithQoS.Kill()
|
||||
}
|
||||
})
|
||||
|
||||
It("limits ingress traffic on veth device", func() {
|
||||
var runtimeWithLimit time.Duration
|
||||
var runtimeWithoutLimit time.Duration
|
||||
|
||||
By("gather timing statistics about both containers")
|
||||
|
||||
By("sending tcp traffic to the container that has traffic shaped", func() {
|
||||
start := time.Now()
|
||||
result, err := types100.GetResult(containerWithQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
makeTCPClientInNS(hostNs.Path(), result.IPs[0].Address.IP.String(), portServerWithQoS, packetInBytes)
|
||||
end := time.Now()
|
||||
runtimeWithLimit = end.Sub(start)
|
||||
log.Printf("Elapsed with qos %.2f", runtimeWithLimit.Seconds())
|
||||
})
|
||||
|
||||
By("sending tcp traffic to the container that does not have traffic shaped", func() {
|
||||
start := time.Now()
|
||||
result, err := types100.GetResult(containerWithoutQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
makeTCPClientInNS(hostNs.Path(), result.IPs[0].Address.IP.String(), portServerWithoutQoS, packetInBytes)
|
||||
end := time.Now()
|
||||
runtimeWithoutLimit = end.Sub(start)
|
||||
log.Printf("Elapsed without qos %.2f", runtimeWithoutLimit.Seconds())
|
||||
})
|
||||
|
||||
Expect(runtimeWithLimit).To(BeNumerically(">", runtimeWithoutLimit+1000*time.Millisecond))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context(fmt.Sprintf("[%s] when chaining bandwidth plugin with PTP and excluding specific subnets from traffic", ver), func() {
|
||||
var ptpConf string
|
||||
var rateInBits uint64
|
||||
var burstInBits uint64
|
||||
var packetInBytes int
|
||||
var containerWithoutQoSNS ns.NetNS
|
||||
var containerWithQoSNS ns.NetNS
|
||||
var portServerWithQoS int
|
||||
var portServerWithoutQoS int
|
||||
|
||||
var containerWithQoSRes types.Result
|
||||
var containerWithoutQoSRes types.Result
|
||||
var echoServerWithQoS *gexec.Session
|
||||
var echoServerWithoutQoS *gexec.Session
|
||||
var dataDir string
|
||||
|
||||
BeforeEach(func() {
|
||||
rateInBytes := 1000
|
||||
rateInBits = uint64(rateInBytes * 8)
|
||||
burstInBits = rateInBits * 2
|
||||
unshapedSubnets := []string{"10.1.2.0/24"}
|
||||
// NOTE: Traffic shapping is not that precise at low rates, would be better to use higher rates + simple time+netcat for data transfer, rather than the provided
|
||||
// client/server bin (limited to small amount of data)
|
||||
packetInBytes = rateInBytes * 3
|
||||
|
||||
var err error
|
||||
dataDir, err = os.MkdirTemp("", "bandwidth_linux_test")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ptpConf = fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "myBWnet",
|
||||
"type": "ptp",
|
||||
"ipMasq": true,
|
||||
"mtu": 512,
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.1.2.0/24",
|
||||
"dataDir": "%s"
|
||||
}
|
||||
}`, ver, dataDir)
|
||||
|
||||
const (
|
||||
containerWithQoSIFName = "ptp0"
|
||||
containerWithoutQoSIFName = "ptp1"
|
||||
)
|
||||
|
||||
containerWithQoSNS, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithoutQoSNS, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("create two containers, and use the bandwidth plugin on one of them")
|
||||
Expect(hostNs.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
containerWithQoSRes, _, err = testutils.CmdAdd(containerWithQoSNS.Path(), "dummy", containerWithQoSIFName, []byte(ptpConf), func() error {
|
||||
r, err := invoke.DelegateAdd(context.TODO(), "ptp", []byte(ptpConf), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(r.Print()).To(Succeed())
|
||||
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithoutQoSRes, _, err = testutils.CmdAdd(containerWithoutQoSNS.Path(), "dummy2", containerWithoutQoSIFName, []byte(ptpConf), func() error {
|
||||
r, err := invoke.DelegateAdd(context.TODO(), "ptp", []byte(ptpConf), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(r.Print()).To(Succeed())
|
||||
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithQoSResult, err := types100.GetResult(containerWithQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
bandwidthPluginConf := &PluginConf{}
|
||||
err = json.Unmarshal([]byte(ptpConf), &bandwidthPluginConf)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
bandwidthPluginConf.RuntimeConfig.Bandwidth = &BandwidthEntry{
|
||||
IngressBurst: burstInBits,
|
||||
IngressRate: rateInBits,
|
||||
EgressBurst: burstInBits,
|
||||
EgressRate: rateInBits,
|
||||
UnshapedSubnets: unshapedSubnets,
|
||||
}
|
||||
bandwidthPluginConf.Type = "bandwidth"
|
||||
newConfBytes, err := buildOneConfig(ver, bandwidthPluginConf, containerWithQoSResult)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy3",
|
||||
Netns: containerWithQoSNS.Path(),
|
||||
IfName: containerWithQoSIFName,
|
||||
StdinData: newConfBytes,
|
||||
}
|
||||
|
||||
result, out, err := testutils.CmdAdd(containerWithQoSNS.Path(), args.ContainerID, "", newConfBytes, func() error { return cmdAdd(args) })
|
||||
Expect(err).NotTo(HaveOccurred(), string(out))
|
||||
|
||||
if testutils.SpecVersionHasCHECK(ver) {
|
||||
// Do CNI Check
|
||||
checkConf := &PluginConf{}
|
||||
err = json.Unmarshal([]byte(ptpConf), &checkConf)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
checkConf.RuntimeConfig.Bandwidth = &BandwidthEntry{
|
||||
IngressBurst: burstInBits,
|
||||
IngressRate: rateInBits,
|
||||
EgressBurst: burstInBits,
|
||||
EgressRate: rateInBits,
|
||||
UnshapedSubnets: unshapedSubnets,
|
||||
}
|
||||
checkConf.Type = "bandwidth"
|
||||
|
||||
newCheckBytes, err := buildOneConfig(ver, checkConf, result)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args = &skel.CmdArgs{
|
||||
ContainerID: "dummy3",
|
||||
Netns: containerWithQoSNS.Path(),
|
||||
IfName: containerWithQoSIFName,
|
||||
StdinData: newCheckBytes,
|
||||
}
|
||||
|
||||
err = testutils.CmdCheck(containerWithQoSNS.Path(), args.ContainerID, "", func() error { return cmdCheck(args) })
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
|
||||
By("starting a tcp server on both containers")
|
||||
portServerWithQoS, echoServerWithQoS = startEchoServerInNamespace(containerWithQoSNS)
|
||||
portServerWithoutQoS, echoServerWithoutQoS = startEchoServerInNamespace(containerWithoutQoSNS)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(os.RemoveAll(dataDir)).To(Succeed())
|
||||
|
||||
Expect(containerWithQoSNS.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerWithQoSNS)).To(Succeed())
|
||||
Expect(containerWithoutQoSNS.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerWithoutQoSNS)).To(Succeed())
|
||||
|
||||
if echoServerWithoutQoS != nil {
|
||||
echoServerWithoutQoS.Kill()
|
||||
}
|
||||
if echoServerWithQoS != nil {
|
||||
echoServerWithQoS.Kill()
|
||||
}
|
||||
})
|
||||
|
||||
It("does not limits ingress traffic on veth device coming from 10.1.2.0/24", func() {
|
||||
var runtimeWithLimit time.Duration
|
||||
var runtimeWithoutLimit time.Duration
|
||||
|
||||
By("gather timing statistics about both containers")
|
||||
|
||||
By("sending tcp traffic to the container that has traffic shaped", func() {
|
||||
start := time.Now()
|
||||
result, err := types100.GetResult(containerWithQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
makeTCPClientInNS(hostNs.Path(), result.IPs[0].Address.IP.String(), portServerWithQoS, packetInBytes)
|
||||
end := time.Now()
|
||||
runtimeWithLimit = end.Sub(start)
|
||||
log.Printf("Elapsed with qos %.2f", runtimeWithLimit.Seconds())
|
||||
})
|
||||
|
||||
By("sending tcp traffic to the container that does not have traffic shaped", func() {
|
||||
start := time.Now()
|
||||
result, err := types100.GetResult(containerWithoutQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
makeTCPClientInNS(hostNs.Path(), result.IPs[0].Address.IP.String(), portServerWithoutQoS, packetInBytes)
|
||||
end := time.Now()
|
||||
runtimeWithoutLimit = end.Sub(start)
|
||||
log.Printf("Elapsed without qos %.2f", runtimeWithoutLimit.Seconds())
|
||||
})
|
||||
|
||||
Expect(runtimeWithLimit - runtimeWithoutLimit).To(BeNumerically("<", 100*time.Millisecond))
|
||||
})
|
||||
})
|
||||
|
||||
Context(fmt.Sprintf("[%s] when chaining bandwidth plugin with PTP and only including specific subnets in traffic shapping (not including the main ns one)", ver), func() {
|
||||
var ptpConf string
|
||||
var rateInBits uint64
|
||||
var burstInBits uint64
|
||||
var packetInBytes int
|
||||
var containerWithoutQoSNS ns.NetNS
|
||||
var containerWithQoSNS ns.NetNS
|
||||
var portServerWithQoS int
|
||||
var portServerWithoutQoS int
|
||||
|
||||
var containerWithQoSRes types.Result
|
||||
var containerWithoutQoSRes types.Result
|
||||
var echoServerWithQoS *gexec.Session
|
||||
var echoServerWithoutQoS *gexec.Session
|
||||
var dataDir string
|
||||
|
||||
BeforeEach(func() {
|
||||
rateInBytes := 1000
|
||||
rateInBits = uint64(rateInBytes * 8)
|
||||
burstInBits = rateInBits * 2
|
||||
shapedSubnets := []string{"10.2.2.0/24"}
|
||||
// NOTE: Traffic shapping is not that precise at low rates, would be better to use higher rates + simple time+netcat for data transfer, rather than the provided
|
||||
// client/server bin (limited to small amount of data)
|
||||
packetInBytes = rateInBytes * 3
|
||||
|
||||
var err error
|
||||
dataDir, err = os.MkdirTemp("", "bandwidth_linux_test")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ptpConf = fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "myBWnet",
|
||||
"type": "ptp",
|
||||
"ipMasq": true,
|
||||
"mtu": 512,
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.1.2.0/24",
|
||||
"dataDir": "%s"
|
||||
}
|
||||
}`, ver, dataDir)
|
||||
|
||||
const (
|
||||
containerWithQoSIFName = "ptp0"
|
||||
containerWithoutQoSIFName = "ptp1"
|
||||
)
|
||||
|
||||
containerWithQoSNS, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithoutQoSNS, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("create two containers, and use the bandwidth plugin on one of them")
|
||||
|
||||
Expect(hostNs.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
containerWithQoSRes, _, err = testutils.CmdAdd(containerWithQoSNS.Path(), "dummy", containerWithQoSIFName, []byte(ptpConf), func() error {
|
||||
r, err := invoke.DelegateAdd(context.TODO(), "ptp", []byte(ptpConf), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(r.Print()).To(Succeed())
|
||||
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithoutQoSRes, _, err = testutils.CmdAdd(containerWithoutQoSNS.Path(), "dummy2", containerWithoutQoSIFName, []byte(ptpConf), func() error {
|
||||
r, err := invoke.DelegateAdd(context.TODO(), "ptp", []byte(ptpConf), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(r.Print()).To(Succeed())
|
||||
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithQoSResult, err := types100.GetResult(containerWithQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
bandwidthPluginConf := &PluginConf{}
|
||||
err = json.Unmarshal([]byte(ptpConf), &bandwidthPluginConf)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
bandwidthPluginConf.RuntimeConfig.Bandwidth = &BandwidthEntry{
|
||||
IngressBurst: burstInBits,
|
||||
IngressRate: rateInBits,
|
||||
EgressBurst: burstInBits,
|
||||
EgressRate: rateInBits,
|
||||
ShapedSubnets: shapedSubnets,
|
||||
}
|
||||
bandwidthPluginConf.Type = "bandwidth"
|
||||
newConfBytes, err := buildOneConfig(ver, bandwidthPluginConf, containerWithQoSResult)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy3",
|
||||
Netns: containerWithQoSNS.Path(),
|
||||
IfName: containerWithQoSIFName,
|
||||
StdinData: newConfBytes,
|
||||
}
|
||||
|
||||
result, out, err := testutils.CmdAdd(containerWithQoSNS.Path(), args.ContainerID, "", newConfBytes, func() error { return cmdAdd(args) })
|
||||
Expect(err).NotTo(HaveOccurred(), string(out))
|
||||
|
||||
if testutils.SpecVersionHasCHECK(ver) {
|
||||
// Do CNI Check
|
||||
checkConf := &PluginConf{}
|
||||
err = json.Unmarshal([]byte(ptpConf), &checkConf)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
checkConf.RuntimeConfig.Bandwidth = &BandwidthEntry{
|
||||
IngressBurst: burstInBits,
|
||||
IngressRate: rateInBits,
|
||||
EgressBurst: burstInBits,
|
||||
EgressRate: rateInBits,
|
||||
ShapedSubnets: shapedSubnets,
|
||||
}
|
||||
checkConf.Type = "bandwidth"
|
||||
|
||||
newCheckBytes, err := buildOneConfig(ver, checkConf, result)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args = &skel.CmdArgs{
|
||||
ContainerID: "dummy3",
|
||||
Netns: containerWithQoSNS.Path(),
|
||||
IfName: containerWithQoSIFName,
|
||||
StdinData: newCheckBytes,
|
||||
}
|
||||
|
||||
err = testutils.CmdCheck(containerWithQoSNS.Path(), args.ContainerID, "", func() error { return cmdCheck(args) })
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
|
||||
By("starting a tcp server on both containers")
|
||||
portServerWithQoS, echoServerWithQoS = startEchoServerInNamespace(containerWithQoSNS)
|
||||
portServerWithoutQoS, echoServerWithoutQoS = startEchoServerInNamespace(containerWithoutQoSNS)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(os.RemoveAll(dataDir)).To(Succeed())
|
||||
|
||||
Expect(containerWithQoSNS.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerWithQoSNS)).To(Succeed())
|
||||
Expect(containerWithoutQoSNS.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerWithoutQoSNS)).To(Succeed())
|
||||
|
||||
if echoServerWithoutQoS != nil {
|
||||
echoServerWithoutQoS.Kill()
|
||||
}
|
||||
if echoServerWithQoS != nil {
|
||||
echoServerWithQoS.Kill()
|
||||
}
|
||||
})
|
||||
|
||||
It("does not limit ingress traffic on veth device coming from non included subnets", func() {
|
||||
var runtimeWithLimit time.Duration
|
||||
var runtimeWithoutLimit time.Duration
|
||||
|
||||
By("gather timing statistics about both containers")
|
||||
|
||||
By("sending tcp traffic to the container that has traffic shaped", func() {
|
||||
start := time.Now()
|
||||
result, err := types100.GetResult(containerWithQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
makeTCPClientInNS(hostNs.Path(), result.IPs[0].Address.IP.String(), portServerWithQoS, packetInBytes)
|
||||
end := time.Now()
|
||||
runtimeWithLimit = end.Sub(start)
|
||||
log.Printf("Elapsed with qos %.2f", runtimeWithLimit.Seconds())
|
||||
})
|
||||
|
||||
By("sending tcp traffic to the container that does not have traffic shaped", func() {
|
||||
start := time.Now()
|
||||
result, err := types100.GetResult(containerWithoutQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
makeTCPClientInNS(hostNs.Path(), result.IPs[0].Address.IP.String(), portServerWithoutQoS, packetInBytes)
|
||||
end := time.Now()
|
||||
runtimeWithoutLimit = end.Sub(start)
|
||||
log.Printf("Elapsed without qos %.2f", runtimeWithoutLimit.Seconds())
|
||||
})
|
||||
|
||||
Expect(runtimeWithLimit - runtimeWithoutLimit).To(BeNumerically("<", 100*time.Millisecond))
|
||||
})
|
||||
})
|
||||
|
||||
Context(fmt.Sprintf("[%s] when chaining bandwidth plugin with PTP and only including specific subnets in traffic shapping (including the main ns one)", ver), func() {
|
||||
var ptpConf string
|
||||
var rateInBits uint64
|
||||
var burstInBits uint64
|
||||
var packetInBytes int
|
||||
var containerWithoutQoSNS ns.NetNS
|
||||
var containerWithQoSNS ns.NetNS
|
||||
var portServerWithQoS int
|
||||
var portServerWithoutQoS int
|
||||
|
||||
var containerWithQoSRes types.Result
|
||||
var containerWithoutQoSRes types.Result
|
||||
var echoServerWithQoS *gexec.Session
|
||||
var echoServerWithoutQoS *gexec.Session
|
||||
var dataDir string
|
||||
|
||||
BeforeEach(func() {
|
||||
rateInBytes := 1000
|
||||
rateInBits = uint64(rateInBytes * 8)
|
||||
burstInBits = rateInBits * 2
|
||||
shapedSubnets := []string{"10.1.2.1/32"}
|
||||
// NOTE: Traffic shapping is not that precise at low rates, would be better to use higher rates + simple time+netcat for data transfer, rather than the provided
|
||||
// client/server bin (limited to small amount of data)
|
||||
packetInBytes = rateInBytes * 3
|
||||
|
||||
var err error
|
||||
dataDir, err = os.MkdirTemp("", "bandwidth_linux_test")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ptpConf = fmt.Sprintf(`{
|
||||
"cniVersion": "%s",
|
||||
"name": "myBWnet",
|
||||
"type": "ptp",
|
||||
"ipMasq": true,
|
||||
"mtu": 512,
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.1.2.0/24",
|
||||
"dataDir": "%s"
|
||||
}
|
||||
}`, ver, dataDir)
|
||||
|
||||
const (
|
||||
containerWithQoSIFName = "ptp0"
|
||||
containerWithoutQoSIFName = "ptp1"
|
||||
)
|
||||
|
||||
containerWithQoSNS, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithoutQoSNS, err = testutils.NewNS()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("create two containers, and use the bandwidth plugin on one of them")
|
||||
|
||||
Expect(hostNs.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
containerWithQoSRes, _, err = testutils.CmdAdd(containerWithQoSNS.Path(), "dummy", containerWithQoSIFName, []byte(ptpConf), func() error {
|
||||
r, err := invoke.DelegateAdd(context.TODO(), "ptp", []byte(ptpConf), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(r.Print()).To(Succeed())
|
||||
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithoutQoSRes, _, err = testutils.CmdAdd(containerWithoutQoSNS.Path(), "dummy2", containerWithoutQoSIFName, []byte(ptpConf), func() error {
|
||||
r, err := invoke.DelegateAdd(context.TODO(), "ptp", []byte(ptpConf), nil)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(r.Print()).To(Succeed())
|
||||
|
||||
return err
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
containerWithQoSResult, err := types100.GetResult(containerWithQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
bandwidthPluginConf := &PluginConf{}
|
||||
err = json.Unmarshal([]byte(ptpConf), &bandwidthPluginConf)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
bandwidthPluginConf.RuntimeConfig.Bandwidth = &BandwidthEntry{
|
||||
IngressBurst: burstInBits,
|
||||
IngressRate: rateInBits,
|
||||
EgressBurst: burstInBits,
|
||||
EgressRate: rateInBits,
|
||||
ShapedSubnets: shapedSubnets,
|
||||
}
|
||||
bandwidthPluginConf.Type = "bandwidth"
|
||||
newConfBytes, err := buildOneConfig(ver, bandwidthPluginConf, containerWithQoSResult)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy3",
|
||||
Netns: containerWithQoSNS.Path(),
|
||||
IfName: containerWithQoSIFName,
|
||||
StdinData: newConfBytes,
|
||||
}
|
||||
|
||||
result, out, err := testutils.CmdAdd(containerWithQoSNS.Path(), args.ContainerID, "", newConfBytes, func() error { return cmdAdd(args) })
|
||||
Expect(err).NotTo(HaveOccurred(), string(out))
|
||||
|
||||
if testutils.SpecVersionHasCHECK(ver) {
|
||||
// Do CNI Check
|
||||
checkConf := &PluginConf{}
|
||||
err = json.Unmarshal([]byte(ptpConf), &checkConf)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
checkConf.RuntimeConfig.Bandwidth = &BandwidthEntry{
|
||||
IngressBurst: burstInBits,
|
||||
IngressRate: rateInBits,
|
||||
EgressBurst: burstInBits,
|
||||
EgressRate: rateInBits,
|
||||
ShapedSubnets: shapedSubnets,
|
||||
}
|
||||
checkConf.Type = "bandwidth"
|
||||
|
||||
newCheckBytes, err := buildOneConfig(ver, checkConf, result)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args = &skel.CmdArgs{
|
||||
ContainerID: "dummy3",
|
||||
Netns: containerWithQoSNS.Path(),
|
||||
IfName: containerWithQoSIFName,
|
||||
StdinData: newCheckBytes,
|
||||
}
|
||||
|
||||
err = testutils.CmdCheck(containerWithQoSNS.Path(), args.ContainerID, "", func() error { return cmdCheck(args) })
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
return nil
|
||||
})).To(Succeed())
|
||||
|
||||
By("starting a tcp server on both containers")
|
||||
portServerWithQoS, echoServerWithQoS = startEchoServerInNamespace(containerWithQoSNS)
|
||||
portServerWithoutQoS, echoServerWithoutQoS = startEchoServerInNamespace(containerWithoutQoSNS)
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(os.RemoveAll(dataDir)).To(Succeed())
|
||||
|
||||
Expect(containerWithQoSNS.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerWithQoSNS)).To(Succeed())
|
||||
Expect(containerWithoutQoSNS.Close()).To(Succeed())
|
||||
Expect(testutils.UnmountNS(containerWithoutQoSNS)).To(Succeed())
|
||||
|
||||
if echoServerWithoutQoS != nil {
|
||||
echoServerWithoutQoS.Kill()
|
||||
}
|
||||
if echoServerWithQoS != nil {
|
||||
echoServerWithQoS.Kill()
|
||||
}
|
||||
})
|
||||
|
||||
It("limits ingress traffic on veth device coming from included subnets", func() {
|
||||
var runtimeWithLimit time.Duration
|
||||
var runtimeWithoutLimit time.Duration
|
||||
|
||||
By("gather timing statistics about both containers")
|
||||
|
||||
By("sending tcp traffic to the container that has traffic shaped", func() {
|
||||
start := time.Now()
|
||||
result, err := types100.GetResult(containerWithQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
makeTCPClientInNS(hostNs.Path(), result.IPs[0].Address.IP.String(), portServerWithQoS, packetInBytes)
|
||||
end := time.Now()
|
||||
runtimeWithLimit = end.Sub(start)
|
||||
log.Printf("Elapsed with qos %.2f", runtimeWithLimit.Seconds())
|
||||
})
|
||||
|
||||
By("sending tcp traffic to the container that does not have traffic shaped", func() {
|
||||
start := time.Now()
|
||||
result, err := types100.GetResult(containerWithoutQoSRes)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
makeTCPClientInNS(hostNs.Path(), result.IPs[0].Address.IP.String(), portServerWithoutQoS, packetInBytes)
|
||||
end := time.Now()
|
||||
runtimeWithoutLimit = end.Sub(start)
|
||||
log.Printf("Elapsed without qos %.2f", runtimeWithoutLimit.Seconds())
|
||||
})
|
||||
|
||||
Expect(runtimeWithLimit).To(BeNumerically(">", runtimeWithoutLimit+1000*time.Millisecond))
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -15,6 +15,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@@ -30,10 +31,11 @@ import (
|
||||
"github.com/onsi/gomega/gexec"
|
||||
"github.com/vishvananda/netlink"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
)
|
||||
|
||||
func TestTBF(t *testing.T) {
|
||||
func TestHTB(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "plugins/meta/bandwidth")
|
||||
}
|
||||
@@ -243,3 +245,47 @@ func createMacvlan(netNS ns.NetNS, master, macvlanName string) {
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
func buildOneConfig(cniVersion string, orig *PluginConf, prevResult types.Result) ([]byte, error) {
|
||||
var err error
|
||||
|
||||
inject := map[string]interface{}{
|
||||
"name": "myBWnet",
|
||||
"cniVersion": cniVersion,
|
||||
}
|
||||
// Add previous plugin result
|
||||
if prevResult != nil {
|
||||
r, err := prevResult.GetAsVersion(cniVersion)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
inject["prevResult"] = r
|
||||
}
|
||||
|
||||
// Ensure every config uses the same name and version
|
||||
config := make(map[string]interface{})
|
||||
|
||||
confBytes, err := json.Marshal(orig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(confBytes, &config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unmarshal existing network bytes: %s", err)
|
||||
}
|
||||
|
||||
for key, value := range inject {
|
||||
config[key] = value
|
||||
}
|
||||
|
||||
newBytes, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conf := &PluginConf{}
|
||||
if err := json.Unmarshal(newBytes, &conf); err != nil {
|
||||
return nil, fmt.Errorf("error parsing configuration: %s", err)
|
||||
}
|
||||
|
||||
return newBytes, nil
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
@@ -24,14 +26,24 @@ import (
|
||||
"github.com/containernetworking/plugins/pkg/ip"
|
||||
)
|
||||
|
||||
const latencyInMillis = 25
|
||||
const (
|
||||
latencyInMillis = 25
|
||||
UncappedRate uint64 = 100_000_000_000
|
||||
ShapedClassMinorID uint16 = 48
|
||||
UnShapedClassMinorID uint16 = 1
|
||||
)
|
||||
|
||||
func CreateIfb(ifbDeviceName string, mtu int, qlen int) error {
|
||||
if qlen < 1000 {
|
||||
qlen = 1000
|
||||
}
|
||||
|
||||
func CreateIfb(ifbDeviceName string, mtu int) error {
|
||||
err := netlink.LinkAdd(&netlink.Ifb{
|
||||
LinkAttrs: netlink.LinkAttrs{
|
||||
Name: ifbDeviceName,
|
||||
Flags: net.FlagUp,
|
||||
MTU: mtu,
|
||||
Name: ifbDeviceName,
|
||||
Flags: net.FlagUp,
|
||||
MTU: mtu,
|
||||
TxQLen: qlen,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -49,15 +61,24 @@ func TeardownIfb(deviceName string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func CreateIngressQdisc(rateInBits, burstInBits uint64, hostDeviceName string) error {
|
||||
func CreateIngressQdisc(rateInBits, burstInBits uint64, excludeSubnets []string, includeSubnets []string, hostDeviceName string) error {
|
||||
hostDevice, err := netlink.LinkByName(hostDeviceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get host device: %s", err)
|
||||
}
|
||||
return createTBF(rateInBits, burstInBits, hostDevice.Attrs().Index)
|
||||
|
||||
subnets := includeSubnets
|
||||
exclude := false
|
||||
|
||||
if len(excludeSubnets) > 0 {
|
||||
subnets = excludeSubnets
|
||||
exclude = true
|
||||
}
|
||||
|
||||
return createHTB(rateInBits, burstInBits, hostDevice.Attrs().Index, subnets, exclude)
|
||||
}
|
||||
|
||||
func CreateEgressQdisc(rateInBits, burstInBits uint64, hostDeviceName string, ifbDeviceName string) error {
|
||||
func CreateEgressQdisc(rateInBits, burstInBits uint64, excludeSubnets []string, includeSubnets []string, hostDeviceName string, ifbDeviceName string) error {
|
||||
ifbDevice, err := netlink.LinkByName(ifbDeviceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get ifb device: %s", err)
|
||||
@@ -104,44 +125,216 @@ func CreateEgressQdisc(rateInBits, burstInBits uint64, hostDeviceName string, if
|
||||
return fmt.Errorf("add filter: %s", err)
|
||||
}
|
||||
|
||||
subnets := excludeSubnets
|
||||
exclude := true
|
||||
|
||||
if len(includeSubnets) > 0 {
|
||||
subnets = includeSubnets
|
||||
exclude = false
|
||||
}
|
||||
|
||||
// throttle traffic on ifb device
|
||||
err = createTBF(rateInBits, burstInBits, ifbDevice.Attrs().Index)
|
||||
err = createHTB(rateInBits, burstInBits, ifbDevice.Attrs().Index, subnets, exclude)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create ifb qdisc: %s", err)
|
||||
// egress from the container/netns pov = ingress from the main netns/host pov
|
||||
return fmt.Errorf("create htb container egress qos rules: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createTBF(rateInBits, burstInBits uint64, linkIndex int) error {
|
||||
// Equivalent to
|
||||
// tc qdisc add dev link root tbf
|
||||
// rate netConf.BandwidthLimits.Rate
|
||||
// burst netConf.BandwidthLimits.Burst
|
||||
if rateInBits <= 0 {
|
||||
return fmt.Errorf("invalid rate: %d", rateInBits)
|
||||
}
|
||||
if burstInBits <= 0 {
|
||||
return fmt.Errorf("invalid burst: %d", burstInBits)
|
||||
}
|
||||
rateInBytes := rateInBits / 8
|
||||
burstInBytes := burstInBits / 8
|
||||
bufferInBytes := buffer(rateInBytes, uint32(burstInBytes))
|
||||
latency := latencyInUsec(latencyInMillis)
|
||||
limitInBytes := limit(rateInBytes, latency, uint32(burstInBytes))
|
||||
func createHTB(rateInBits, burstInBits uint64, linkIndex int, subnets []string, excludeSubnets bool) error {
|
||||
// Netlink struct fields are not clear, let's use shell
|
||||
|
||||
qdisc := &netlink.Tbf{
|
||||
defaultClassID := UnShapedClassMinorID
|
||||
// If no subnets are specified, then shaping should apply to everything
|
||||
if len(subnets) == 0 || excludeSubnets {
|
||||
defaultClassID = ShapedClassMinorID
|
||||
}
|
||||
|
||||
// Step 1 qdisc
|
||||
// cmd := exec.Command("/usr/sbin/tc", "qdisc", "add", "dev", interfaceName, "root", "handle", "1:", "htb", "default", "30")
|
||||
qdisc := &netlink.Htb{
|
||||
QdiscAttrs: netlink.QdiscAttrs{
|
||||
LinkIndex: linkIndex,
|
||||
Handle: netlink.MakeHandle(1, 0),
|
||||
Parent: netlink.HANDLE_ROOT,
|
||||
},
|
||||
Limit: limitInBytes,
|
||||
Rate: rateInBytes,
|
||||
Buffer: bufferInBytes,
|
||||
Defcls: uint32(defaultClassID),
|
||||
// No idea what these are so let's keep the default values from source code...
|
||||
Version: 3,
|
||||
Rate2Quantum: 10,
|
||||
}
|
||||
err := netlink.QdiscAdd(qdisc)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create qdisc: %s", err)
|
||||
return fmt.Errorf("error while creating qdisc: %s", err)
|
||||
}
|
||||
|
||||
// Step 2 classes
|
||||
|
||||
rateInBytes := rateInBits / 8
|
||||
burstInBytes := burstInBits / 8
|
||||
bufferInBytes := buffer(rateInBytes, uint32(burstInBytes))
|
||||
|
||||
// The capped class for shaped traffic (included subnets or all but excluded subnets)
|
||||
// cmd = exec.Command("/usr/sbin/tc", "class", "add", "dev", interfaceName, "parent", "1:", "classid", "1:30", "htb", "rate",
|
||||
// fmt.Sprintf("%d", rateInBits), "burst", fmt.Sprintf("%d", burstInBits))
|
||||
shapedClass := &netlink.HtbClass{
|
||||
ClassAttrs: netlink.ClassAttrs{
|
||||
LinkIndex: linkIndex,
|
||||
Handle: netlink.MakeHandle(1, ShapedClassMinorID),
|
||||
Parent: netlink.MakeHandle(1, 0),
|
||||
},
|
||||
Rate: rateInBytes,
|
||||
Buffer: bufferInBytes,
|
||||
// Let's set up the "burst" rate to twice the specified rate
|
||||
Ceil: 2 * rateInBytes,
|
||||
Cbuffer: bufferInBytes,
|
||||
}
|
||||
|
||||
err = netlink.ClassAdd(shapedClass)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while creating htb default class: %s", err)
|
||||
}
|
||||
|
||||
// The uncapped class for non shaped traffic (either all but included subnets or excluded subnets only)
|
||||
// cmd = exec.Command("/usr/sbin/tc", "class", "add", "dev", interfaceName, "parent", "1:", "classid", "1:1", "htb",
|
||||
// "rate", "100000000000")
|
||||
bigRate := UncappedRate
|
||||
unshapedClass := &netlink.HtbClass{
|
||||
ClassAttrs: netlink.ClassAttrs{
|
||||
LinkIndex: linkIndex,
|
||||
Handle: netlink.MakeHandle(1, UnShapedClassMinorID),
|
||||
Parent: qdisc.Handle,
|
||||
},
|
||||
Rate: bigRate,
|
||||
Ceil: bigRate,
|
||||
// No need for any burst, the minimum buffer size in q_htb.c should be enough to handle the rate which
|
||||
// is already more than enough
|
||||
}
|
||||
err = netlink.ClassAdd(unshapedClass)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error while creating htb uncapped class: %s", err)
|
||||
}
|
||||
|
||||
// Now add filters to redirect subnets to the class 1 if excluded instead of the default one (30)
|
||||
for _, subnet := range subnets {
|
||||
|
||||
// cmd = exec.Command("/usr/sbin/tc", "filter", "add", "dev", interfaceName, "parent", "1:", "protocol", protocol,
|
||||
// "prio", "16", "u32", "match", "ip", "dst", subnet, "flowid", "1:1")
|
||||
_, nw, err := net.ParseCIDR(subnet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad subnet %s: %s", subnet, err)
|
||||
}
|
||||
var maskBytes []byte = nw.Mask
|
||||
var subnetBytes []byte = nw.IP
|
||||
|
||||
if len(maskBytes) != len(subnetBytes) {
|
||||
return fmt.Errorf("error using net lib for subnet %s len(maskBytes) != len(subnetBytes) "+
|
||||
"(%d != %d) should not happen", subnet, len(maskBytes), len(subnetBytes))
|
||||
}
|
||||
|
||||
isIpv4 := nw.IP.To4() != nil
|
||||
protocol := syscall.ETH_P_IPV6
|
||||
var prio uint16 = 15
|
||||
var offset int32 = 24
|
||||
keepBytes := 16
|
||||
if isIpv4 {
|
||||
protocol = syscall.ETH_P_IP
|
||||
offset = 16
|
||||
keepBytes = 4
|
||||
// prio/pref needs to be changed if we change the protocol, looks like we cannot mix protocols with the same pref
|
||||
prio = 16
|
||||
}
|
||||
|
||||
if len(maskBytes) < keepBytes {
|
||||
return fmt.Errorf("error with net lib, unexpected count of bytes for ipv4 mask (%d < %d)",
|
||||
len(maskBytes), keepBytes)
|
||||
}
|
||||
if len(subnetBytes) < keepBytes {
|
||||
return fmt.Errorf("error with net lib, unexpected count of bytes for ipv4 subnet (%d < %d)",
|
||||
len(subnetBytes), keepBytes)
|
||||
}
|
||||
maskBytes = maskBytes[len(maskBytes)-keepBytes:]
|
||||
subnetBytes = subnetBytes[len(subnetBytes)-keepBytes:]
|
||||
|
||||
// For ipv4 we should have at most 1 key, for ipv6 at most 4
|
||||
keys := make([]netlink.TcU32Key, 0, 4)
|
||||
|
||||
for i := 0; i < len(maskBytes); i += 4 {
|
||||
var mask, subnetI uint32
|
||||
buf := bytes.NewReader(maskBytes[i : i+4])
|
||||
err = binary.Read(buf, binary.BigEndian, &mask)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error, htb filter, unable to build mask match filter, iter %d for subnet %s",
|
||||
i, subnet)
|
||||
}
|
||||
|
||||
if mask != 0 {
|
||||
// If mask == 0, any value on this section will be a match and we do not need a filter for this
|
||||
buf = bytes.NewReader(subnetBytes[i : i+4])
|
||||
err = binary.Read(buf, binary.BigEndian, &subnetI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error, htb filter, unable to build subnet match filter, iter %d for subnet %s",
|
||||
i, subnet)
|
||||
}
|
||||
keys = append(keys, netlink.TcU32Key{
|
||||
Mask: mask,
|
||||
Val: subnetI,
|
||||
Off: offset,
|
||||
OffMask: 0,
|
||||
})
|
||||
}
|
||||
|
||||
offset += 4
|
||||
}
|
||||
|
||||
if len(keys) != cap(keys) {
|
||||
shrinkedKeys := make([]netlink.TcU32Key, len(keys))
|
||||
copied := copy(shrinkedKeys, keys)
|
||||
if copied != len(keys) {
|
||||
return fmt.Errorf("copy tc u32 keys error, for subnet %s copied %d != keys %d", subnet, copied, len(keys))
|
||||
}
|
||||
keys = shrinkedKeys
|
||||
}
|
||||
|
||||
if isIpv4 && len(keys) > 1 {
|
||||
return fmt.Errorf("error, htb ipv4 filter, unexpected rule length (%d > 1), for subnet %s",
|
||||
len(keys), subnet)
|
||||
} else if len(keys) > 4 {
|
||||
return fmt.Errorf("error, htb ipv6 filter, unexpected rule length (%d > 4), for subnet %s",
|
||||
len(keys), subnet)
|
||||
}
|
||||
|
||||
// If len(keys) == 0, it means that we want to wildcard all traffic on the non default/uncapped class
|
||||
var selector *netlink.TcU32Sel
|
||||
if len(keys) > 0 {
|
||||
selector = &netlink.TcU32Sel{
|
||||
Nkeys: uint8(len(keys)),
|
||||
Flags: netlink.TC_U32_TERMINAL,
|
||||
Keys: keys,
|
||||
}
|
||||
}
|
||||
|
||||
classID := shapedClass.Handle
|
||||
if excludeSubnets {
|
||||
classID = unshapedClass.Handle
|
||||
}
|
||||
|
||||
tcFilter := netlink.U32{
|
||||
FilterAttrs: netlink.FilterAttrs{
|
||||
LinkIndex: linkIndex,
|
||||
Parent: qdisc.Handle,
|
||||
Priority: prio,
|
||||
Protocol: uint16(protocol),
|
||||
},
|
||||
ClassId: classID,
|
||||
Sel: selector,
|
||||
}
|
||||
|
||||
err = netlink.FilterAdd(&tcFilter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error, unable to create htb filter, details %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -153,11 +346,3 @@ func time2Tick(time uint32) uint32 {
|
||||
func buffer(rate uint64, burst uint32) uint32 {
|
||||
return time2Tick(uint32(float64(burst) * float64(netlink.TIME_UNITS_PER_SEC) / float64(rate)))
|
||||
}
|
||||
|
||||
func limit(rate uint64, latency float64, buffer uint32) uint32 {
|
||||
return uint32(float64(rate)*latency/float64(netlink.TIME_UNITS_PER_SEC)) + buffer
|
||||
}
|
||||
|
||||
func latencyInUsec(latencyInMillis float64) float64 {
|
||||
return float64(netlink.TIME_UNITS_PER_SEC) * (latencyInMillis / 1000.0)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
|
||||
@@ -39,11 +40,12 @@ const (
|
||||
// BandwidthEntry corresponds to a single entry in the bandwidth argument,
|
||||
// see CONVENTIONS.md
|
||||
type BandwidthEntry struct {
|
||||
IngressRate uint64 `json:"ingressRate"` // Bandwidth rate in bps for traffic through container. 0 for no limit. If ingressRate is set, ingressBurst must also be set
|
||||
IngressBurst uint64 `json:"ingressBurst"` // Bandwidth burst in bits for traffic through container. 0 for no limit. If ingressBurst is set, ingressRate must also be set
|
||||
|
||||
EgressRate uint64 `json:"egressRate"` // Bandwidth rate in bps for traffic through container. 0 for no limit. If egressRate is set, egressBurst must also be set
|
||||
EgressBurst uint64 `json:"egressBurst"` // Bandwidth burst in bits for traffic through container. 0 for no limit. If egressBurst is set, egressRate must also be set
|
||||
UnshapedSubnets []string `json:"unshapedSubnets"` // Ipv4/ipv6 subnets to be excluded from traffic shaping. UnshapedSubnets and ShapedSubnets parameters are mutually exlusive
|
||||
ShapedSubnets []string `json:"shapedSubnets"` // Ipv4/ipv6 subnets to be included in traffic shaping. UnshapedSubnets and ShapedSubnets parameters are mutually exlusive
|
||||
IngressRate uint64 `json:"ingressRate"` // Bandwidth rate in bps for traffic through container. 0 for no limit. If ingressRate is set, ingressBurst must also be set
|
||||
IngressBurst uint64 `json:"ingressBurst"` // Bandwidth burst in bits for traffic through container. 0 for no limit. If ingressBurst is set, ingressRate must also be set
|
||||
EgressRate uint64 `json:"egressRate"` // Bandwidth rate in bps for traffic through container. 0 for no limit. If egressRate is set, egressBurst must also be set
|
||||
EgressBurst uint64 `json:"egressBurst"` // Bandwidth burst in bits for traffic through container. 0 for no limit. If egressBurst is set, egressRate must also be set
|
||||
}
|
||||
|
||||
func (bw *BandwidthEntry) isZero() bool {
|
||||
@@ -96,10 +98,21 @@ func parseConfig(stdin []byte) (*PluginConf, error) {
|
||||
}
|
||||
|
||||
func getBandwidth(conf *PluginConf) *BandwidthEntry {
|
||||
if conf.BandwidthEntry == nil && conf.RuntimeConfig.Bandwidth != nil {
|
||||
return conf.RuntimeConfig.Bandwidth
|
||||
bw := conf.BandwidthEntry
|
||||
if bw == nil && conf.RuntimeConfig.Bandwidth != nil {
|
||||
bw = conf.RuntimeConfig.Bandwidth
|
||||
}
|
||||
return conf.BandwidthEntry
|
||||
|
||||
if bw != nil {
|
||||
if bw.UnshapedSubnets == nil {
|
||||
bw.UnshapedSubnets = make([]string, 0)
|
||||
}
|
||||
if bw.ShapedSubnets == nil {
|
||||
bw.ShapedSubnets = make([]string, 0)
|
||||
}
|
||||
}
|
||||
|
||||
return bw
|
||||
}
|
||||
|
||||
func validateRateAndBurst(rate, burst uint64) error {
|
||||
@@ -119,13 +132,13 @@ func getIfbDeviceName(networkName string, containerID string) string {
|
||||
return utils.MustFormatHashWithPrefix(maxIfbDeviceLength, ifbDevicePrefix, networkName+containerID)
|
||||
}
|
||||
|
||||
func getMTU(deviceName string) (int, error) {
|
||||
func getMTUAndQLen(deviceName string) (int, int, error) {
|
||||
link, err := netlink.LinkByName(deviceName)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
return -1, -1, err
|
||||
}
|
||||
|
||||
return link.Attrs().MTU, nil
|
||||
return link.Attrs().MTU, link.Attrs().TxQLen, nil
|
||||
}
|
||||
|
||||
// get the veth peer of container interface in host namespace
|
||||
@@ -159,6 +172,28 @@ func getHostInterface(interfaces []*current.Interface, containerIfName string, n
|
||||
return nil, fmt.Errorf("no veth peer of container interface found in host ns")
|
||||
}
|
||||
|
||||
func validateSubnets(unshapedSubnets []string, shapedSubnets []string) error {
|
||||
if len(unshapedSubnets) > 0 && len(shapedSubnets) > 0 {
|
||||
return fmt.Errorf("unshapedSubnets and shapedSubnets cannot be both specified, one of them should be discarded")
|
||||
}
|
||||
|
||||
for _, subnet := range unshapedSubnets {
|
||||
_, _, err := net.ParseCIDR(subnet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad subnet %q provided, details %s", subnet, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, subnet := range shapedSubnets {
|
||||
_, _, err := net.ParseCIDR(subnet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("bad subnet %q provided, details %s", subnet, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cmdAdd(args *skel.CmdArgs) error {
|
||||
conf, err := parseConfig(args.StdinData)
|
||||
if err != nil {
|
||||
@@ -170,6 +205,10 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
return types.PrintResult(conf.PrevResult, conf.CNIVersion)
|
||||
}
|
||||
|
||||
if err = validateSubnets(bandwidth.UnshapedSubnets, bandwidth.ShapedSubnets); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if conf.PrevResult == nil {
|
||||
return fmt.Errorf("must be called as chained plugin")
|
||||
}
|
||||
@@ -191,21 +230,22 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
|
||||
if bandwidth.IngressRate > 0 && bandwidth.IngressBurst > 0 {
|
||||
err = CreateIngressQdisc(bandwidth.IngressRate, bandwidth.IngressBurst, hostInterface.Name)
|
||||
err = CreateIngressQdisc(bandwidth.IngressRate, bandwidth.IngressBurst,
|
||||
bandwidth.UnshapedSubnets, bandwidth.ShapedSubnets, hostInterface.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if bandwidth.EgressRate > 0 && bandwidth.EgressBurst > 0 {
|
||||
mtu, err := getMTU(hostInterface.Name)
|
||||
mtu, qlen, err := getMTUAndQLen(hostInterface.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ifbDeviceName := getIfbDeviceName(conf.Name, args.ContainerID)
|
||||
|
||||
err = CreateIfb(ifbDeviceName, mtu)
|
||||
err = CreateIfb(ifbDeviceName, mtu, qlen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -219,7 +259,9 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
Name: ifbDeviceName,
|
||||
Mac: ifbDevice.Attrs().HardwareAddr.String(),
|
||||
})
|
||||
err = CreateEgressQdisc(bandwidth.EgressRate, bandwidth.EgressBurst, hostInterface.Name, ifbDeviceName)
|
||||
err = CreateEgressQdisc(bandwidth.EgressRate, bandwidth.EgressBurst,
|
||||
bandwidth.UnshapedSubnets, bandwidth.ShapedSubnets, hostInterface.Name,
|
||||
ifbDeviceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -292,75 +334,99 @@ func cmdCheck(args *skel.CmdArgs) error {
|
||||
|
||||
bandwidth := getBandwidth(bwConf)
|
||||
|
||||
if err = validateSubnets(bandwidth.UnshapedSubnets, bandwidth.ShapedSubnets); err != nil {
|
||||
return fmt.Errorf("failed to check subnets, details %s", err)
|
||||
}
|
||||
|
||||
if bandwidth.IngressRate > 0 && bandwidth.IngressBurst > 0 {
|
||||
rateInBytes := bandwidth.IngressRate / 8
|
||||
burstInBytes := bandwidth.IngressBurst / 8
|
||||
bufferInBytes := buffer(rateInBytes, uint32(burstInBytes))
|
||||
latency := latencyInUsec(latencyInMillis)
|
||||
limitInBytes := limit(rateInBytes, latency, uint32(burstInBytes))
|
||||
|
||||
qdiscs, err := SafeQdiscList(link)
|
||||
err = checkHTB(link, rateInBytes, bufferInBytes, bandwidth.ShapedSubnets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(qdiscs) == 0 {
|
||||
return fmt.Errorf("Failed to find qdisc")
|
||||
}
|
||||
|
||||
for _, qdisc := range qdiscs {
|
||||
tbf, isTbf := qdisc.(*netlink.Tbf)
|
||||
if !isTbf {
|
||||
break
|
||||
}
|
||||
if tbf.Rate != rateInBytes {
|
||||
return fmt.Errorf("Rate doesn't match")
|
||||
}
|
||||
if tbf.Limit != limitInBytes {
|
||||
return fmt.Errorf("Limit doesn't match")
|
||||
}
|
||||
if tbf.Buffer != bufferInBytes {
|
||||
return fmt.Errorf("Buffer doesn't match")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bandwidth.EgressRate > 0 && bandwidth.EgressBurst > 0 {
|
||||
rateInBytes := bandwidth.EgressRate / 8
|
||||
burstInBytes := bandwidth.EgressBurst / 8
|
||||
bufferInBytes := buffer(rateInBytes, uint32(burstInBytes))
|
||||
latency := latencyInUsec(latencyInMillis)
|
||||
limitInBytes := limit(rateInBytes, latency, uint32(burstInBytes))
|
||||
|
||||
ifbDeviceName := getIfbDeviceName(bwConf.Name, args.ContainerID)
|
||||
|
||||
ifbDevice, err := netlink.LinkByName(ifbDeviceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get ifb device: %s", err)
|
||||
}
|
||||
|
||||
qdiscs, err := SafeQdiscList(ifbDevice)
|
||||
err = checkHTB(ifbDevice, rateInBytes, bufferInBytes, bandwidth.ShapedSubnets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(qdiscs) == 0 {
|
||||
return fmt.Errorf("Failed to find qdisc")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkHTB(link netlink.Link, rateInBytes uint64, bufferInBytes uint32, shapedSubnets []string) error {
|
||||
qdiscs, err := SafeQdiscList(link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(qdiscs) == 0 {
|
||||
return fmt.Errorf("Failed to find qdisc")
|
||||
}
|
||||
foundHTB := false
|
||||
for _, qdisc := range qdiscs {
|
||||
htb, isHtb := qdisc.(*netlink.Htb)
|
||||
if !isHtb {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, qdisc := range qdiscs {
|
||||
tbf, isTbf := qdisc.(*netlink.Tbf)
|
||||
if !isTbf {
|
||||
break
|
||||
if foundHTB {
|
||||
return fmt.Errorf("Several htb qdisc found for device %s", link.Attrs().Name)
|
||||
}
|
||||
|
||||
foundHTB = true
|
||||
defaultClassMinorID := ShapedClassMinorID
|
||||
if len(shapedSubnets) > 0 {
|
||||
defaultClassMinorID = UnShapedClassMinorID
|
||||
}
|
||||
|
||||
if htb.Defcls != uint32(defaultClassMinorID) {
|
||||
return fmt.Errorf("Default class does not match")
|
||||
}
|
||||
|
||||
classes, err := netlink.ClassList(link, htb.Handle)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to list classes bound to htb qdisc for device %s. Details %s",
|
||||
link.Attrs().Name, err)
|
||||
}
|
||||
if len(classes) != 2 {
|
||||
return fmt.Errorf("Number of htb classes does not match for device %s (%d != 2)",
|
||||
link.Attrs().Name, len(classes))
|
||||
}
|
||||
|
||||
for _, c := range classes {
|
||||
htbClass, isHtb := c.(*netlink.HtbClass)
|
||||
if !isHtb {
|
||||
return fmt.Errorf("Unexpected class for parent htb qdisc bound to device %s", link.Attrs().Name)
|
||||
}
|
||||
if tbf.Rate != rateInBytes {
|
||||
return fmt.Errorf("Rate doesn't match")
|
||||
}
|
||||
if tbf.Limit != limitInBytes {
|
||||
return fmt.Errorf("Limit doesn't match")
|
||||
}
|
||||
if tbf.Buffer != bufferInBytes {
|
||||
return fmt.Errorf("Buffer doesn't match")
|
||||
if htbClass.Handle == htb.Defcls {
|
||||
if htbClass.Rate != rateInBytes {
|
||||
return fmt.Errorf("Rate does not match for the default class for device %s (%d != %d)",
|
||||
link.Attrs().Name, htbClass.Rate, rateInBytes)
|
||||
}
|
||||
|
||||
if htbClass.Buffer != bufferInBytes {
|
||||
return fmt.Errorf("Burst buffer size does not match for the default class for device %s (%d != %d)",
|
||||
link.Attrs().Name, htbClass.Buffer, bufferInBytes)
|
||||
}
|
||||
} else if htbClass.Handle == netlink.MakeHandle(1, 1) {
|
||||
if htbClass.Rate != UncappedRate {
|
||||
return fmt.Errorf("Rate does not match for the uncapped class for device %s (%d != %d)",
|
||||
link.Attrs().Name, htbClass.Rate, UncappedRate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: check subnet filters
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -86,7 +86,8 @@ func spawnSessionDbus(wg *sync.WaitGroup) (string, *exec.Cmd) {
|
||||
bytes, err := bufio.NewReader(stdout).ReadString('\n')
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
busAddr := strings.TrimSpace(bytes)
|
||||
Expect(strings.HasPrefix(busAddr, "unix:abstract")).To(BeTrue())
|
||||
Expect(strings.HasPrefix(busAddr, "unix:abstract") ||
|
||||
strings.HasPrefix(busAddr, "unix:path")).To(BeTrue())
|
||||
|
||||
var startWg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
|
||||
@@ -67,13 +67,27 @@ func (c *chain) setup(ipt *iptables.IPTables) error {
|
||||
// teardown idempotently deletes a chain. It will not error if the chain doesn't exist.
|
||||
// It will first delete all references to this chain in the entryChains.
|
||||
func (c *chain) teardown(ipt *iptables.IPTables) error {
|
||||
// flush the chain
|
||||
// This will succeed *and create the chain* if it does not exist.
|
||||
// If the chain doesn't exist, the next checks will fail.
|
||||
if err := utils.ClearChain(ipt, c.table, c.name); err != nil {
|
||||
return err
|
||||
// nothing to do if the custom chain doesn't exist to begin with
|
||||
exists, err := ipt.ChainExists(c.table, c.name)
|
||||
if err == nil && !exists {
|
||||
return nil
|
||||
}
|
||||
// delete references created by setup()
|
||||
for _, entryChain := range c.entryChains {
|
||||
for _, rule := range c.entryRules {
|
||||
r := []string{}
|
||||
r = append(r, rule...)
|
||||
r = append(r, "-j", c.name)
|
||||
|
||||
ipt.Delete(c.table, entryChain, r...)
|
||||
}
|
||||
}
|
||||
// if chain deletion succeeds now, all references are gone
|
||||
if err := ipt.ClearAndDeleteChain(c.table, c.name); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// find references the hard way
|
||||
for _, entryChain := range c.entryChains {
|
||||
entryChainRules, err := ipt.List(c.table, entryChain)
|
||||
if err != nil || len(entryChainRules) < 1 {
|
||||
@@ -98,12 +112,12 @@ func (c *chain) teardown(ipt *iptables.IPTables) error {
|
||||
}
|
||||
}
|
||||
|
||||
return utils.DeleteChain(ipt, c.table, c.name)
|
||||
return ipt.ClearAndDeleteChain(c.table, c.name)
|
||||
}
|
||||
|
||||
// check the chain.
|
||||
func (c *chain) check(ipt *iptables.IPTables) error {
|
||||
exists, err := utils.ChainExists(ipt, c.table, c.name)
|
||||
exists, err := ipt.ChainExists(c.table, c.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ func withLockAndNetNS(nspath string, toRun func(_ ns.NetNS) error) error {
|
||||
}
|
||||
|
||||
err = ns.WithNetNSPath(nspath, toRun)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ type TuningConf struct {
|
||||
Mac string `json:"mac,omitempty"`
|
||||
Promisc bool `json:"promisc,omitempty"`
|
||||
Mtu int `json:"mtu,omitempty"`
|
||||
TxQLen *int `json:"txQLen,omitempty"`
|
||||
Allmulti *bool `json:"allmulti,omitempty"`
|
||||
|
||||
RuntimeConfig struct {
|
||||
@@ -69,6 +70,7 @@ type IPAMArgs struct {
|
||||
Promisc *bool `json:"promisc,omitempty"`
|
||||
Mtu *int `json:"mtu,omitempty"`
|
||||
Allmulti *bool `json:"allmulti,omitempty"`
|
||||
TxQLen *int `json:"txQLen,omitempty"`
|
||||
}
|
||||
|
||||
// configToRestore will contain interface attributes that should be restored on cmdDel
|
||||
@@ -77,6 +79,7 @@ type configToRestore struct {
|
||||
Promisc *bool `json:"promisc,omitempty"`
|
||||
Mtu int `json:"mtu,omitempty"`
|
||||
Allmulti *bool `json:"allmulti,omitempty"`
|
||||
TxQLen *int `json:"txQLen,omitempty"`
|
||||
}
|
||||
|
||||
// MacEnvArgs represents CNI_ARG
|
||||
@@ -136,6 +139,10 @@ func parseConf(data []byte, envArgs string) (*TuningConf, error) {
|
||||
if conf.Args.A.Allmulti != nil {
|
||||
conf.Allmulti = conf.Args.A.Allmulti
|
||||
}
|
||||
|
||||
if conf.Args.A.TxQLen != nil {
|
||||
conf.TxQLen = conf.Args.A.TxQLen
|
||||
}
|
||||
}
|
||||
|
||||
return &conf, nil
|
||||
@@ -204,6 +211,14 @@ func changeAllmulti(ifName string, val bool) error {
|
||||
return netlink.LinkSetAllmulticastOff(link)
|
||||
}
|
||||
|
||||
func changeTxQLen(ifName string, txQLen int) error {
|
||||
link, err := netlink.LinkByName(ifName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get %q: %v", ifName, err)
|
||||
}
|
||||
return netlink.LinkSetTxQLen(link, txQLen)
|
||||
}
|
||||
|
||||
func createBackup(ifName, containerID, backupPath string, tuningConf *TuningConf) error {
|
||||
config := configToRestore{}
|
||||
link, err := netlink.LinkByName(ifName)
|
||||
@@ -224,6 +239,10 @@ func createBackup(ifName, containerID, backupPath string, tuningConf *TuningConf
|
||||
config.Allmulti = new(bool)
|
||||
*config.Allmulti = (link.Attrs().RawFlags&unix.IFF_ALLMULTI != 0)
|
||||
}
|
||||
if tuningConf.TxQLen != nil {
|
||||
qlen := link.Attrs().TxQLen
|
||||
config.TxQLen = &qlen
|
||||
}
|
||||
|
||||
if _, err := os.Stat(backupPath); os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(backupPath, 0o600); err != nil {
|
||||
@@ -292,6 +311,13 @@ func restoreBackup(ifName, containerID, backupPath string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if config.TxQLen != nil {
|
||||
if err = changeTxQLen(ifName, *config.TxQLen); err != nil {
|
||||
err = fmt.Errorf("failed to restore transmit queue length: %v", err)
|
||||
errStr = append(errStr, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errStr) > 0 {
|
||||
return fmt.Errorf(strings.Join(errStr, "; "))
|
||||
}
|
||||
@@ -346,7 +372,7 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
}
|
||||
|
||||
if tuningConf.Mac != "" || tuningConf.Mtu != 0 || tuningConf.Promisc || tuningConf.Allmulti != nil {
|
||||
if tuningConf.Mac != "" || tuningConf.Mtu != 0 || tuningConf.Promisc || tuningConf.Allmulti != nil || tuningConf.TxQLen != nil {
|
||||
if err = createBackup(args.IfName, args.ContainerID, tuningConf.DataDir, tuningConf); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -377,6 +403,12 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tuningConf.TxQLen != nil {
|
||||
if err = changeTxQLen(args.IfName, *tuningConf.TxQLen); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -483,6 +515,13 @@ func cmdCheck(args *skel.CmdArgs) error {
|
||||
args.IfName, tuningConf.Allmulti, allmulti)
|
||||
}
|
||||
}
|
||||
|
||||
if tuningConf.TxQLen != nil {
|
||||
if *tuningConf.TxQLen != link.Attrs().TxQLen {
|
||||
return fmt.Errorf("Error: Tuning configured Transmit Queue Length of %s is %d, current value is %d",
|
||||
args.IfName, tuningConf.TxQLen, link.Attrs().TxQLen)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -125,6 +125,8 @@ var _ = Describe("tuning plugin", func() {
|
||||
*beforeConf.Promisc = (link.Attrs().Promisc != 0)
|
||||
beforeConf.Allmulti = new(bool)
|
||||
*beforeConf.Allmulti = (link.Attrs().RawFlags&unix.IFF_ALLMULTI != 0)
|
||||
beforeConf.TxQLen = new(int)
|
||||
*beforeConf.TxQLen = link.Attrs().TxQLen
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -487,6 +489,138 @@ var _ = Describe("tuning plugin", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] configures and deconfigures tx queue len with ADD/DEL", ver), func() {
|
||||
conf := []byte(fmt.Sprintf(`{
|
||||
"name": "test",
|
||||
"type": "iplink",
|
||||
"cniVersion": "%s",
|
||||
"txQLen": 20000,
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{"name": "dummy0", "sandbox":"netns"}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "10.0.0.2/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}`, ver))
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: originalNS.Path(),
|
||||
IfName: IFNAME,
|
||||
StdinData: conf,
|
||||
}
|
||||
|
||||
err := originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||
return cmdAdd(args)
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
link, err := netlink.LinkByName(IFNAME)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().TxQLen).To(Equal(20000))
|
||||
|
||||
if testutils.SpecVersionHasCHECK(ver) {
|
||||
n := &TuningConf{}
|
||||
Expect(json.Unmarshal(conf, &n)).NotTo(HaveOccurred())
|
||||
|
||||
confString, err := buildOneConfig(ver, n, r)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
args.StdinData = confString
|
||||
|
||||
Expect(testutils.CmdCheckWithArgs(args, func() error {
|
||||
return cmdCheck(args)
|
||||
})).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
err = testutils.CmdDel(originalNS.Path(),
|
||||
args.ContainerID, "", func() error { return cmdDel(args) })
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
link, err = netlink.LinkByName(IFNAME)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().TxQLen).To(Equal(*beforeConf.TxQLen))
|
||||
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] configures and deconfigures tx queue len from args with ADD/DEL", ver), func() {
|
||||
conf := []byte(fmt.Sprintf(`{
|
||||
"name": "test",
|
||||
"type": "iplink",
|
||||
"cniVersion": "%s",
|
||||
"args": {
|
||||
"cni": {
|
||||
"txQLen": 20000
|
||||
}
|
||||
},
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{"name": "dummy0", "sandbox":"netns"}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "10.0.0.2/24",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
}`, ver))
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: originalNS.Path(),
|
||||
IfName: IFNAME,
|
||||
StdinData: conf,
|
||||
}
|
||||
|
||||
err := originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||
return cmdAdd(args)
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
result, err := types100.GetResult(r)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(result.Interfaces).To(HaveLen(1))
|
||||
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
|
||||
Expect(result.IPs).To(HaveLen(1))
|
||||
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
|
||||
|
||||
link, err := netlink.LinkByName(IFNAME)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().TxQLen).To(Equal(20000))
|
||||
|
||||
err = testutils.CmdDel(originalNS.Path(),
|
||||
args.ContainerID, "", func() error { return cmdDel(args) })
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
link, err = netlink.LinkByName(IFNAME)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(link.Attrs().TxQLen).To(Equal(*beforeConf.TxQLen))
|
||||
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] configures and deconfigures mac address (from conf file) with ADD/DEL", ver), func() {
|
||||
mac := "c2:11:22:33:44:55"
|
||||
conf := []byte(fmt.Sprintf(`{
|
||||
@@ -780,7 +914,7 @@ var _ = Describe("tuning plugin", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It(fmt.Sprintf("[%s] configures and deconfigures mac address, promisc mode and MTU (from conf file) with custom dataDir", ver), func() {
|
||||
It(fmt.Sprintf("[%s] configures and deconfigures mac address, promisc mode, MTU and tx queue len (from conf file) with custom dataDir", ver), func() {
|
||||
conf := []byte(fmt.Sprintf(`{
|
||||
"name": "test",
|
||||
"type": "iplink",
|
||||
@@ -788,6 +922,7 @@ var _ = Describe("tuning plugin", func() {
|
||||
"mac": "c2:11:22:33:44:77",
|
||||
"promisc": true,
|
||||
"mtu": 4000,
|
||||
"txQLen": 20000,
|
||||
"dataDir": "/tmp/tuning-test",
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
@@ -834,6 +969,7 @@ var _ = Describe("tuning plugin", func() {
|
||||
Expect(link.Attrs().HardwareAddr).To(Equal(hw))
|
||||
Expect(link.Attrs().Promisc).To(Equal(1))
|
||||
Expect(link.Attrs().MTU).To(Equal(4000))
|
||||
Expect(link.Attrs().TxQLen).To(Equal(20000))
|
||||
|
||||
Expect("/tmp/tuning-test/dummy_dummy0.json").Should(BeAnExistingFile())
|
||||
|
||||
@@ -862,6 +998,7 @@ var _ = Describe("tuning plugin", func() {
|
||||
Expect(link.Attrs().HardwareAddr.String()).To(Equal(beforeConf.Mac))
|
||||
Expect(link.Attrs().MTU).To(Equal(beforeConf.Mtu))
|
||||
Expect(link.Attrs().Promisc != 0).To(Equal(*beforeConf.Promisc))
|
||||
Expect(link.Attrs().TxQLen).To(Equal(*beforeConf.TxQLen))
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -75,7 +75,6 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("cmdAdd failed: %v", err)
|
||||
}
|
||||
@@ -121,7 +120,6 @@ func cmdDel(args *skel.CmdArgs) error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times
|
||||
// so don't return an error if the device is already removed.
|
||||
|
||||
@@ -104,6 +104,19 @@ func addInterface(vrf *netlink.Vrf, intf string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed getting ipv6 addresses for %s", intf)
|
||||
}
|
||||
|
||||
// Save all routes that are not local and connected, before setting master,
|
||||
// because otherwise those routes will be deleted after interface is moved.
|
||||
filter := &netlink.Route{
|
||||
LinkIndex: i.Attrs().Index,
|
||||
Scope: netlink.SCOPE_UNIVERSE, // Exclude local and connected routes
|
||||
}
|
||||
filterMask := netlink.RT_FILTER_OIF | netlink.RT_FILTER_SCOPE // Filter based on link index and scope
|
||||
routes, err := netlink.RouteListFiltered(netlink.FAMILY_ALL, filter, filterMask)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed getting all routes for %s", intf)
|
||||
}
|
||||
|
||||
err = netlink.LinkSetMaster(i, vrf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not set vrf %s as master of %s: %v", vrf.Name, intf, err)
|
||||
@@ -130,6 +143,18 @@ CONTINUE:
|
||||
}
|
||||
}
|
||||
|
||||
// Apply all saved routes for the interface that was moved to the VRF
|
||||
for _, route := range routes {
|
||||
r := route
|
||||
// Modify original table to vrf one,
|
||||
r.Table = int(vrf.Table)
|
||||
// equivalent of 'ip route replace <address> table <int>'.
|
||||
err = netlink.RouteReplace(&r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not add route '%s': %v", r, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -107,7 +109,7 @@ var _ = Describe("vrf plugin", func() {
|
||||
},
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = netlink.LinkByName(IF0Name)
|
||||
_, err = netlink.LinkByName(IF1Name)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
return nil
|
||||
})
|
||||
@@ -177,6 +179,256 @@ var _ = Describe("vrf plugin", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("adds the interface and custom routing to new VRF", func() {
|
||||
conf := configWithRouteFor("test", IF0Name, VRF0Name, "10.0.0.2/24", "10.10.10.0/24")
|
||||
|
||||
By("Setting custom routing first", func() {
|
||||
err := targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
ipv4, err := types.ParseCIDR("10.0.0.2/24")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ipv4).NotTo(BeNil())
|
||||
|
||||
_, routev4, err := net.ParseCIDR("10.10.10.0/24")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ipv6, err := types.ParseCIDR("abcd:1234:ffff::cdde/64")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ipv6).NotTo(BeNil())
|
||||
|
||||
_, routev6, err := net.ParseCIDR("1111:dddd::/80")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(routev6).NotTo(BeNil())
|
||||
|
||||
link, err := netlink.LinkByName(IF0Name)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Add IP addresses for network reachability
|
||||
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv4})
|
||||
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv6})
|
||||
|
||||
ipAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
// Check if address was assigned properly
|
||||
Expect(ipAddrs[0].IP.String()).To(Equal("10.0.0.2"))
|
||||
|
||||
// Set interface UP, otherwise local route to 10.0.0.0/24 is not present
|
||||
err = netlink.LinkSetUp(link)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Add additional route to 10.10.10.0/24 via 10.0.0.1 gateway
|
||||
r := netlink.Route{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Src: ipv4.IP,
|
||||
Dst: routev4,
|
||||
Gw: net.ParseIP("10.0.0.1"),
|
||||
}
|
||||
err = netlink.RouteAdd(&r)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
r6 := netlink.Route{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Src: ipv6.IP,
|
||||
Dst: routev6,
|
||||
Gw: net.ParseIP("abcd:1234:ffff::1"),
|
||||
}
|
||||
err = netlink.RouteAdd(&r6)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: targetNS.Path(),
|
||||
IfName: IF0Name,
|
||||
StdinData: conf,
|
||||
}
|
||||
|
||||
err := originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
r, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||
return cmdAdd(args)
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
result, err := current.GetResult(r)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(result.Interfaces).To(HaveLen(1))
|
||||
Expect(result.Interfaces[0].Name).To(Equal(IF0Name))
|
||||
Expect(result.Routes).To(HaveLen(1))
|
||||
Expect(result.Routes[0].Dst.IP.String()).To(Equal("10.10.10.0"))
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
checkInterfaceOnVRF(VRF0Name, IF0Name)
|
||||
checkRoutesOnVRF(VRF0Name, IF0Name, "10.0.0.2", "10.10.10.0/24", "1111:dddd::/80")
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("filters the correct routes to import to new VRF", func() {
|
||||
_ = configWithRouteFor("test0", IF0Name, VRF0Name, "10.0.0.2/24", "10.10.10.0/24")
|
||||
conf1 := configWithRouteFor("test1", IF1Name, VRF1Name, "10.0.0.3/24", "10.11.10.0/24")
|
||||
|
||||
By("Setting custom routing for IF0Name", func() {
|
||||
err := targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
ipv4, err := types.ParseCIDR("10.0.0.2/24")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ipv4).NotTo(BeNil())
|
||||
|
||||
_, routev4, err := net.ParseCIDR("10.10.10.0/24")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ipv6, err := types.ParseCIDR("abcd:1234:ffff::cdde/64")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ipv6).NotTo(BeNil())
|
||||
|
||||
_, routev6, err := net.ParseCIDR("1111:dddd::/80")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(routev6).NotTo(BeNil())
|
||||
|
||||
link, err := netlink.LinkByName(IF0Name)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Add IP addresses for network reachability
|
||||
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv4})
|
||||
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv6})
|
||||
|
||||
ipAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
// Check if address was assigned properly
|
||||
Expect(ipAddrs[0].IP.String()).To(Equal("10.0.0.2"))
|
||||
|
||||
// Set interface UP, otherwise local route to 10.0.0.0/24 is not present
|
||||
err = netlink.LinkSetUp(link)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Add additional route to 10.10.10.0/24 via 10.0.0.1 gateway
|
||||
r := netlink.Route{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Dst: routev4,
|
||||
Gw: net.ParseIP("10.0.0.1"),
|
||||
}
|
||||
err = netlink.RouteAdd(&r)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
r6 := netlink.Route{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Src: ipv6.IP,
|
||||
Dst: routev6,
|
||||
Gw: net.ParseIP("abcd:1234:ffff::1"),
|
||||
}
|
||||
err = netlink.RouteAdd(&r6)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
By("Setting custom routing for IF1Name", func() {
|
||||
err := targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
ipv4, err := types.ParseCIDR("10.0.0.3/24")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ipv4).NotTo(BeNil())
|
||||
|
||||
_, routev4, err := net.ParseCIDR("10.11.10.0/24")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ipv6, err := types.ParseCIDR("abcd:1234:ffff::cddf/64")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ipv6).NotTo(BeNil())
|
||||
|
||||
_, routev6, err := net.ParseCIDR("1111:ddde::/80")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(routev6).NotTo(BeNil())
|
||||
|
||||
link, err := netlink.LinkByName(IF1Name)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Add IP addresses for network reachability
|
||||
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv4})
|
||||
netlink.AddrAdd(link, &netlink.Addr{IPNet: ipv6})
|
||||
|
||||
ipAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
// Check if address was assigned properly
|
||||
Expect(ipAddrs[0].IP.String()).To(Equal("10.0.0.3"))
|
||||
|
||||
// Set interface UP, otherwise local route to 10.0.0.0/24 is not present
|
||||
err = netlink.LinkSetUp(link)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Add additional route to 10.11.10.0/24 via 10.0.0.1 gateway
|
||||
r := netlink.Route{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Dst: routev4,
|
||||
Gw: net.ParseIP("10.0.0.1"),
|
||||
Priority: 100,
|
||||
}
|
||||
err = netlink.RouteAdd(&r)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
r6 := netlink.Route{
|
||||
LinkIndex: link.Attrs().Index,
|
||||
Src: ipv6.IP,
|
||||
Dst: routev6,
|
||||
Gw: net.ParseIP("abcd:1234:ffff::1"),
|
||||
}
|
||||
err = netlink.RouteAdd(&r6)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
By("Adding if1 to the VRF", func() {
|
||||
err := originalNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
Netns: targetNS.Path(),
|
||||
IfName: IF1Name,
|
||||
StdinData: conf1,
|
||||
}
|
||||
_, _, err := testutils.CmdAddWithArgs(args, func() error {
|
||||
return cmdAdd(args)
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
By("Checking routes are moved correctly to VRF", func() {
|
||||
err := targetNS.Do(func(ns.NetNS) error {
|
||||
defer GinkgoRecover()
|
||||
|
||||
checkInterfaceOnVRF(VRF1Name, IF1Name)
|
||||
checkRoutesOnVRF(VRF1Name, IF1Name, "10.0.0.3", "10.11.10.0/24", "1111:ddde::/80")
|
||||
|
||||
return nil
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
It("fails if the interface already has a master set", func() {
|
||||
conf := configFor("test", IF0Name, VRF0Name, "10.0.0.2/24")
|
||||
|
||||
@@ -690,6 +942,35 @@ func configWithTableFor(name, intf, vrf, ip string, tableID int) []byte {
|
||||
return []byte(conf)
|
||||
}
|
||||
|
||||
func configWithRouteFor(name, intf, vrf, ip, route string) []byte {
|
||||
conf := fmt.Sprintf(`{
|
||||
"name": "%s",
|
||||
"type": "vrf",
|
||||
"cniVersion": "0.3.1",
|
||||
"vrfName": "%s",
|
||||
"prevResult": {
|
||||
"interfaces": [
|
||||
{"name": "%s", "sandbox":"netns"}
|
||||
],
|
||||
"ips": [
|
||||
{
|
||||
"version": "4",
|
||||
"address": "%s",
|
||||
"gateway": "10.0.0.1",
|
||||
"interface": 0
|
||||
}
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"dst": "%s",
|
||||
"gw": "10.0.0.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}`, name, vrf, intf, ip, route)
|
||||
return []byte(conf)
|
||||
}
|
||||
|
||||
func checkInterfaceOnVRF(vrfName, intfName string) {
|
||||
vrf, err := netlink.LinkByName(vrfName)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -702,3 +983,46 @@ func checkInterfaceOnVRF(vrfName, intfName string) {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(master.Attrs().Name).To(Equal(vrfName))
|
||||
}
|
||||
|
||||
func checkRoutesOnVRF(vrfName, intfName string, addrStr string, routesToCheck ...string) {
|
||||
l, err := netlink.LinkByName(vrfName)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(l).To(BeAssignableToTypeOf(&netlink.Vrf{}))
|
||||
|
||||
vrf, ok := l.(*netlink.Vrf)
|
||||
Expect(ok).To(BeTrue())
|
||||
|
||||
link, err := netlink.LinkByName(intfName)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = netlink.LinkSetUp(link)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
ipAddrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ipAddrs).To(HaveLen(1))
|
||||
Expect(ipAddrs[0].IP.String()).To(Equal(addrStr))
|
||||
|
||||
routeFilter := &netlink.Route{
|
||||
Table: int(vrf.Table),
|
||||
}
|
||||
|
||||
routes, err := netlink.RouteListFiltered(netlink.FAMILY_ALL,
|
||||
routeFilter,
|
||||
netlink.RT_FILTER_TABLE)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
routesRead := []string{}
|
||||
for _, route := range routes {
|
||||
routesRead = append(routesRead, route.String())
|
||||
Expect(uint32(route.Table)).To(Equal(vrf.Table))
|
||||
}
|
||||
routesStr := strings.Join(routesRead, "\n")
|
||||
for _, route := range routesToCheck {
|
||||
Expect(routesStr).To(ContainSubstring(route))
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
Expect(route.LinkIndex).To(Equal(link.Attrs().Index))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
set -xe
|
||||
|
||||
SRC_DIR="${SRC_DIR:-$PWD}"
|
||||
DOCKER="${DOCKER:-docker}"
|
||||
GOLANG="${GOLANG:-golang:1.22-alpine}"
|
||||
|
||||
TAG=$(git describe --tags --dirty)
|
||||
RELEASE_DIR=release-${TAG}
|
||||
@@ -16,7 +17,7 @@ rm -Rf ${SRC_DIR}/${RELEASE_DIR}
|
||||
mkdir -p ${SRC_DIR}/${RELEASE_DIR}
|
||||
mkdir -p ${OUTPUT_DIR}
|
||||
|
||||
$DOCKER run -ti -v ${SRC_DIR}:/go/src/github.com/containernetworking/plugins:z --rm golang:1.20-alpine \
|
||||
$DOCKER run -ti -v ${SRC_DIR}:/go/src/github.com/containernetworking/plugins:z --rm "${GOLANG}" \
|
||||
/bin/sh -xe -c "\
|
||||
apk --no-cache add bash tar;
|
||||
cd /go/src/github.com/containernetworking/plugins; umask 0022;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# Run CNI plugin tests.
|
||||
#
|
||||
@@ -10,12 +10,12 @@ set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Build all plugins before testing
|
||||
source ./build_linux.sh
|
||||
. ./build_linux.sh
|
||||
|
||||
echo "Running tests"
|
||||
|
||||
function testrun {
|
||||
sudo -E bash -c "umask 0; PATH=${GOPATH}/bin:$(pwd)/bin:${PATH} go test $@"
|
||||
testrun() {
|
||||
sudo -E sh -c "umask 0; PATH=${GOPATH}/bin:$(pwd)/bin:${PATH} go test -race $*"
|
||||
}
|
||||
|
||||
COVERALLS=${COVERALLS:-""}
|
||||
@@ -31,7 +31,7 @@ PKG=${PKG:-$(go list ./... | xargs echo)}
|
||||
i=0
|
||||
for t in ${PKG}; do
|
||||
if [ -n "${COVERALLS}" ]; then
|
||||
COVERFLAGS="-covermode set -coverprofile ${i}.coverprofile"
|
||||
COVERFLAGS="-covermode atomic -coverprofile ${i}.coverprofile"
|
||||
fi
|
||||
echo "${t}"
|
||||
testrun "${COVERFLAGS:-""} ${t}"
|
||||
@@ -39,5 +39,5 @@ for t in ${PKG}; do
|
||||
done
|
||||
|
||||
# Run the pkg/ns tests as non root user
|
||||
mkdir /tmp/cni-rootless
|
||||
mkdir -p /tmp/cni-rootless
|
||||
(export XDG_RUNTIME_DIR=/tmp/cni-rootless; cd pkg/ns/; unshare -rmn go test)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# Run CNI plugin tests.
|
||||
#
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
source ./build_windows.sh
|
||||
. ./build_windows.sh
|
||||
|
||||
echo "Running tests"
|
||||
|
||||
@@ -17,4 +17,4 @@ for d in $PLUGINS; do
|
||||
done
|
||||
|
||||
echo "testing packages $PKGS"
|
||||
go test -v $PKGS -ginkgo.randomizeAllSpecs -ginkgo.failOnPending -ginkgo.progress
|
||||
go test -race -v $PKGS -ginkgo.randomizeAllSpecs -ginkgo.failOnPending -ginkgo.progress
|
||||
|
||||
37
vendor/github.com/Microsoft/go-winio/.golangci.yml
generated
vendored
37
vendor/github.com/Microsoft/go-winio/.golangci.yml
generated
vendored
@@ -1,19 +1,11 @@
|
||||
run:
|
||||
skip-dirs:
|
||||
- pkg/etw/sample
|
||||
|
||||
linters:
|
||||
enable:
|
||||
# style
|
||||
- containedctx # struct contains a context
|
||||
- dupl # duplicate code
|
||||
- errname # erorrs are named correctly
|
||||
- goconst # strings that should be constants
|
||||
- godot # comments end in a period
|
||||
- misspell
|
||||
- nolintlint # "//nolint" directives are properly explained
|
||||
- revive # golint replacement
|
||||
- stylecheck # golint replacement, less configurable than revive
|
||||
- unconvert # unnecessary conversions
|
||||
- wastedassign
|
||||
|
||||
@@ -23,13 +15,14 @@ linters:
|
||||
- exhaustive # check exhaustiveness of enum switch statements
|
||||
- gofmt # files are gofmt'ed
|
||||
- gosec # security
|
||||
- nestif # deeply nested ifs
|
||||
- nilerr # returns nil even with non-nil error
|
||||
- prealloc # slices that can be pre-allocated
|
||||
- structcheck # unused struct fields
|
||||
- thelper # test helpers without t.Helper()
|
||||
- unparam # unused function params
|
||||
|
||||
issues:
|
||||
exclude-dirs:
|
||||
- pkg/etw/sample
|
||||
|
||||
exclude-rules:
|
||||
# err is very often shadowed in nested scopes
|
||||
- linters:
|
||||
@@ -42,6 +35,18 @@ issues:
|
||||
text: "^line-length-limit: "
|
||||
source: "^//(go:generate|sys) "
|
||||
|
||||
#TODO: remove after upgrading to go1.18
|
||||
# ignore comment spacing for nolint and sys directives
|
||||
- linters:
|
||||
- revive
|
||||
text: "^comment-spacings: no space between comment delimiter and comment text"
|
||||
source: "//(cspell:|nolint:|sys |todo)"
|
||||
|
||||
# not on go 1.18 yet, so no any
|
||||
- linters:
|
||||
- revive
|
||||
text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'"
|
||||
|
||||
# allow unjustified ignores of error checks in defer statements
|
||||
- linters:
|
||||
- nolintlint
|
||||
@@ -56,15 +61,15 @@ issues:
|
||||
|
||||
|
||||
linters-settings:
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
govet:
|
||||
enable-all: true
|
||||
disable:
|
||||
# struct order is often for Win32 compat
|
||||
# also, ignore pointer bytes/GC issues for now until performance becomes an issue
|
||||
- fieldalignment
|
||||
check-shadowing: true
|
||||
nolintlint:
|
||||
allow-leading-space: false
|
||||
require-explanation: true
|
||||
require-specific: true
|
||||
revive:
|
||||
@@ -98,6 +103,8 @@ linters-settings:
|
||||
disabled: true
|
||||
- name: flag-parameter # excessive, and a common idiom we use
|
||||
disabled: true
|
||||
- name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
|
||||
disabled: true
|
||||
# general config
|
||||
- name: line-length-limit
|
||||
arguments:
|
||||
@@ -138,7 +145,3 @@ linters-settings:
|
||||
- VPCI
|
||||
- WCOW
|
||||
- WIM
|
||||
stylecheck:
|
||||
checks:
|
||||
- "all"
|
||||
- "-ST1003" # use revive's var naming
|
||||
|
||||
33
vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
33
vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
@@ -10,14 +10,14 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/fs"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
|
||||
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
|
||||
//sys backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
|
||||
//sys backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
|
||||
|
||||
const (
|
||||
BackupData = uint32(iota + 1)
|
||||
@@ -104,7 +104,7 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
||||
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hdr.Name = syscall.UTF16ToString(name)
|
||||
hdr.Name = windows.UTF16ToString(name)
|
||||
}
|
||||
if wsi.StreamID == BackupSparseBlock {
|
||||
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
|
||||
@@ -205,7 +205,7 @@ func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
|
||||
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
|
||||
func (r *BackupFileReader) Read(b []byte) (int, error) {
|
||||
var bytesRead uint32
|
||||
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
||||
err := backupRead(windows.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: err}
|
||||
}
|
||||
@@ -220,7 +220,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
|
||||
// the underlying file.
|
||||
func (r *BackupFileReader) Close() error {
|
||||
if r.ctx != 0 {
|
||||
_ = backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
|
||||
_ = backupRead(windows.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
|
||||
runtime.KeepAlive(r.f)
|
||||
r.ctx = 0
|
||||
}
|
||||
@@ -244,7 +244,7 @@ func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
|
||||
// Write restores a portion of the file using the provided backup stream.
|
||||
func (w *BackupFileWriter) Write(b []byte) (int, error) {
|
||||
var bytesWritten uint32
|
||||
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
||||
err := backupWrite(windows.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: err}
|
||||
}
|
||||
@@ -259,7 +259,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
|
||||
// close the underlying file.
|
||||
func (w *BackupFileWriter) Close() error {
|
||||
if w.ctx != 0 {
|
||||
_ = backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
|
||||
_ = backupWrite(windows.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
|
||||
runtime.KeepAlive(w.f)
|
||||
w.ctx = 0
|
||||
}
|
||||
@@ -271,17 +271,14 @@ func (w *BackupFileWriter) Close() error {
|
||||
//
|
||||
// If the file opened was a directory, it cannot be used with Readdir().
|
||||
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
|
||||
winPath, err := syscall.UTF16FromString(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, err := syscall.CreateFile(&winPath[0],
|
||||
access,
|
||||
share,
|
||||
h, err := fs.CreateFile(path,
|
||||
fs.AccessMask(access),
|
||||
fs.FileShareMode(share),
|
||||
nil,
|
||||
createmode,
|
||||
syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
0)
|
||||
fs.FileCreationDisposition(createmode),
|
||||
fs.FILE_FLAG_BACKUP_SEMANTICS|fs.FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
0,
|
||||
)
|
||||
if err != nil {
|
||||
err = &os.PathError{Op: "open", Path: path, Err: err}
|
||||
return nil, err
|
||||
|
||||
85
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
85
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
@@ -15,26 +15,11 @@ import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
|
||||
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
|
||||
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
|
||||
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
|
||||
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
|
||||
|
||||
type atomicBool int32
|
||||
|
||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
||||
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
||||
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
||||
|
||||
//revive:disable-next-line:predeclared Keep "new" to maintain consistency with "atomic" pkg
|
||||
func (b *atomicBool) swap(new bool) bool {
|
||||
var newInt int32
|
||||
if new {
|
||||
newInt = 1
|
||||
}
|
||||
return atomic.SwapInt32((*int32)(b), newInt) == 1
|
||||
}
|
||||
//sys cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) = CancelIoEx
|
||||
//sys createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) = CreateIoCompletionPort
|
||||
//sys getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
|
||||
//sys setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
|
||||
//sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
|
||||
|
||||
var (
|
||||
ErrFileClosed = errors.New("file has already been closed")
|
||||
@@ -50,7 +35,7 @@ func (*timeoutError) Temporary() bool { return true }
|
||||
type timeoutChan chan struct{}
|
||||
|
||||
var ioInitOnce sync.Once
|
||||
var ioCompletionPort syscall.Handle
|
||||
var ioCompletionPort windows.Handle
|
||||
|
||||
// ioResult contains the result of an asynchronous IO operation.
|
||||
type ioResult struct {
|
||||
@@ -60,12 +45,12 @@ type ioResult struct {
|
||||
|
||||
// ioOperation represents an outstanding asynchronous Win32 IO.
|
||||
type ioOperation struct {
|
||||
o syscall.Overlapped
|
||||
o windows.Overlapped
|
||||
ch chan ioResult
|
||||
}
|
||||
|
||||
func initIO() {
|
||||
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
|
||||
h, err := createIoCompletionPort(windows.InvalidHandle, 0, 0, 0xffffffff)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -76,10 +61,10 @@ func initIO() {
|
||||
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
|
||||
// It takes ownership of this handle and will close it if it is garbage collected.
|
||||
type win32File struct {
|
||||
handle syscall.Handle
|
||||
handle windows.Handle
|
||||
wg sync.WaitGroup
|
||||
wgLock sync.RWMutex
|
||||
closing atomicBool
|
||||
closing atomic.Bool
|
||||
socket bool
|
||||
readDeadline deadlineHandler
|
||||
writeDeadline deadlineHandler
|
||||
@@ -90,11 +75,11 @@ type deadlineHandler struct {
|
||||
channel timeoutChan
|
||||
channelLock sync.RWMutex
|
||||
timer *time.Timer
|
||||
timedout atomicBool
|
||||
timedout atomic.Bool
|
||||
}
|
||||
|
||||
// makeWin32File makes a new win32File from an existing file handle.
|
||||
func makeWin32File(h syscall.Handle) (*win32File, error) {
|
||||
func makeWin32File(h windows.Handle) (*win32File, error) {
|
||||
f := &win32File{handle: h}
|
||||
ioInitOnce.Do(initIO)
|
||||
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
|
||||
@@ -110,7 +95,12 @@ func makeWin32File(h syscall.Handle) (*win32File, error) {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Deprecated: use NewOpenFile instead.
|
||||
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
||||
return NewOpenFile(windows.Handle(h))
|
||||
}
|
||||
|
||||
func NewOpenFile(h windows.Handle) (io.ReadWriteCloser, error) {
|
||||
// If we return the result of makeWin32File directly, it can result in an
|
||||
// interface-wrapped nil, rather than a nil interface value.
|
||||
f, err := makeWin32File(h)
|
||||
@@ -124,13 +114,13 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
||||
func (f *win32File) closeHandle() {
|
||||
f.wgLock.Lock()
|
||||
// Atomically set that we are closing, releasing the resources only once.
|
||||
if !f.closing.swap(true) {
|
||||
if !f.closing.Swap(true) {
|
||||
f.wgLock.Unlock()
|
||||
// cancel all IO and wait for it to complete
|
||||
_ = cancelIoEx(f.handle, nil)
|
||||
f.wg.Wait()
|
||||
// at this point, no new IO can start
|
||||
syscall.Close(f.handle)
|
||||
windows.Close(f.handle)
|
||||
f.handle = 0
|
||||
} else {
|
||||
f.wgLock.Unlock()
|
||||
@@ -145,14 +135,14 @@ func (f *win32File) Close() error {
|
||||
|
||||
// IsClosed checks if the file has been closed.
|
||||
func (f *win32File) IsClosed() bool {
|
||||
return f.closing.isSet()
|
||||
return f.closing.Load()
|
||||
}
|
||||
|
||||
// prepareIO prepares for a new IO operation.
|
||||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
|
||||
func (f *win32File) prepareIO() (*ioOperation, error) {
|
||||
f.wgLock.RLock()
|
||||
if f.closing.isSet() {
|
||||
if f.closing.Load() {
|
||||
f.wgLock.RUnlock()
|
||||
return nil, ErrFileClosed
|
||||
}
|
||||
@@ -164,12 +154,12 @@ func (f *win32File) prepareIO() (*ioOperation, error) {
|
||||
}
|
||||
|
||||
// ioCompletionProcessor processes completed async IOs forever.
|
||||
func ioCompletionProcessor(h syscall.Handle) {
|
||||
func ioCompletionProcessor(h windows.Handle) {
|
||||
for {
|
||||
var bytes uint32
|
||||
var key uintptr
|
||||
var op *ioOperation
|
||||
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
|
||||
err := getQueuedCompletionStatus(h, &bytes, &key, &op, windows.INFINITE)
|
||||
if op == nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -182,11 +172,11 @@ func ioCompletionProcessor(h syscall.Handle) {
|
||||
// asyncIO processes the return value from ReadFile or WriteFile, blocking until
|
||||
// the operation has actually completed.
|
||||
func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
|
||||
if err != syscall.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
|
||||
if err != windows.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
|
||||
return int(bytes), err
|
||||
}
|
||||
|
||||
if f.closing.isSet() {
|
||||
if f.closing.Load() {
|
||||
_ = cancelIoEx(f.handle, &c.o)
|
||||
}
|
||||
|
||||
@@ -201,8 +191,8 @@ func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
||||
select {
|
||||
case r = <-c.ch:
|
||||
err = r.err
|
||||
if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||
if f.closing.isSet() {
|
||||
if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||
if f.closing.Load() {
|
||||
err = ErrFileClosed
|
||||
}
|
||||
} else if err != nil && f.socket {
|
||||
@@ -214,7 +204,7 @@ func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
||||
_ = cancelIoEx(f.handle, &c.o)
|
||||
r = <-c.ch
|
||||
err = r.err
|
||||
if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||
if err == windows.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||
err = ErrTimeout
|
||||
}
|
||||
}
|
||||
@@ -235,23 +225,22 @@ func (f *win32File) Read(b []byte) (int, error) {
|
||||
}
|
||||
defer f.wg.Done()
|
||||
|
||||
if f.readDeadline.timedout.isSet() {
|
||||
if f.readDeadline.timedout.Load() {
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
|
||||
var bytes uint32
|
||||
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
|
||||
err = windows.ReadFile(f.handle, b, &bytes, &c.o)
|
||||
n, err := f.asyncIO(c, &f.readDeadline, bytes, err)
|
||||
runtime.KeepAlive(b)
|
||||
|
||||
// Handle EOF conditions.
|
||||
if err == nil && n == 0 && len(b) != 0 {
|
||||
return 0, io.EOF
|
||||
} else if err == syscall.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno
|
||||
} else if err == windows.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno
|
||||
return 0, io.EOF
|
||||
} else {
|
||||
return n, err
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Write writes to a file handle.
|
||||
@@ -262,12 +251,12 @@ func (f *win32File) Write(b []byte) (int, error) {
|
||||
}
|
||||
defer f.wg.Done()
|
||||
|
||||
if f.writeDeadline.timedout.isSet() {
|
||||
if f.writeDeadline.timedout.Load() {
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
|
||||
var bytes uint32
|
||||
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
|
||||
err = windows.WriteFile(f.handle, b, &bytes, &c.o)
|
||||
n, err := f.asyncIO(c, &f.writeDeadline, bytes, err)
|
||||
runtime.KeepAlive(b)
|
||||
return n, err
|
||||
@@ -282,7 +271,7 @@ func (f *win32File) SetWriteDeadline(deadline time.Time) error {
|
||||
}
|
||||
|
||||
func (f *win32File) Flush() error {
|
||||
return syscall.FlushFileBuffers(f.handle)
|
||||
return windows.FlushFileBuffers(f.handle)
|
||||
}
|
||||
|
||||
func (f *win32File) Fd() uintptr {
|
||||
@@ -299,7 +288,7 @@ func (d *deadlineHandler) set(deadline time.Time) error {
|
||||
}
|
||||
d.timer = nil
|
||||
}
|
||||
d.timedout.setFalse()
|
||||
d.timedout.Store(false)
|
||||
|
||||
select {
|
||||
case <-d.channel:
|
||||
@@ -314,7 +303,7 @@ func (d *deadlineHandler) set(deadline time.Time) error {
|
||||
}
|
||||
|
||||
timeoutIO := func() {
|
||||
d.timedout.setTrue()
|
||||
d.timedout.Store(true)
|
||||
close(d.channel)
|
||||
}
|
||||
|
||||
|
||||
22
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
22
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
@@ -18,9 +18,18 @@ type FileBasicInfo struct {
|
||||
_ uint32 // padding
|
||||
}
|
||||
|
||||
// alignedFileBasicInfo is a FileBasicInfo, but aligned to uint64 by containing
|
||||
// uint64 rather than windows.Filetime. Filetime contains two uint32s. uint64
|
||||
// alignment is necessary to pass this as FILE_BASIC_INFO.
|
||||
type alignedFileBasicInfo struct {
|
||||
CreationTime, LastAccessTime, LastWriteTime, ChangeTime uint64
|
||||
FileAttributes uint32
|
||||
_ uint32 // padding
|
||||
}
|
||||
|
||||
// GetFileBasicInfo retrieves times and attributes for a file.
|
||||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
||||
bi := &FileBasicInfo{}
|
||||
bi := &alignedFileBasicInfo{}
|
||||
if err := windows.GetFileInformationByHandleEx(
|
||||
windows.Handle(f.Fd()),
|
||||
windows.FileBasicInfo,
|
||||
@@ -30,16 +39,21 @@ func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
||||
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||
}
|
||||
runtime.KeepAlive(f)
|
||||
return bi, nil
|
||||
// Reinterpret the alignedFileBasicInfo as a FileBasicInfo so it matches the
|
||||
// public API of this module. The data may be unnecessarily aligned.
|
||||
return (*FileBasicInfo)(unsafe.Pointer(bi)), nil
|
||||
}
|
||||
|
||||
// SetFileBasicInfo sets times and attributes for a file.
|
||||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
|
||||
// Create an alignedFileBasicInfo based on a FileBasicInfo. The copy is
|
||||
// suitable to pass to GetFileInformationByHandleEx.
|
||||
biAligned := *(*alignedFileBasicInfo)(unsafe.Pointer(bi))
|
||||
if err := windows.SetFileInformationByHandle(
|
||||
windows.Handle(f.Fd()),
|
||||
windows.FileBasicInfo,
|
||||
(*byte)(unsafe.Pointer(bi)),
|
||||
uint32(unsafe.Sizeof(*bi)),
|
||||
(*byte)(unsafe.Pointer(&biAligned)),
|
||||
uint32(unsafe.Sizeof(biAligned)),
|
||||
); err != nil {
|
||||
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
|
||||
}
|
||||
|
||||
51
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
51
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
@@ -10,7 +10,6 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
@@ -23,7 +22,7 @@ import (
|
||||
const afHVSock = 34 // AF_HYPERV
|
||||
|
||||
// Well known Service and VM IDs
|
||||
//https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
|
||||
// https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
|
||||
|
||||
// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
|
||||
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
|
||||
@@ -31,7 +30,7 @@ func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
|
||||
}
|
||||
|
||||
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
|
||||
func HvsockGUIDBroadcast() guid.GUID { //ffffffff-ffff-ffff-ffff-ffffffffffff
|
||||
func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffffffffff
|
||||
return guid.GUID{
|
||||
Data1: 0xffffffff,
|
||||
Data2: 0xffff,
|
||||
@@ -181,13 +180,13 @@ type HvsockConn struct {
|
||||
var _ net.Conn = &HvsockConn{}
|
||||
|
||||
func newHVSocket() (*win32File, error) {
|
||||
fd, err := syscall.Socket(afHVSock, syscall.SOCK_STREAM, 1)
|
||||
fd, err := windows.Socket(afHVSock, windows.SOCK_STREAM, 1)
|
||||
if err != nil {
|
||||
return nil, os.NewSyscallError("socket", err)
|
||||
}
|
||||
f, err := makeWin32File(fd)
|
||||
if err != nil {
|
||||
syscall.Close(fd)
|
||||
windows.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
f.socket = true
|
||||
@@ -197,16 +196,24 @@ func newHVSocket() (*win32File, error) {
|
||||
// ListenHvsock listens for connections on the specified hvsock address.
|
||||
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
|
||||
l := &HvsockListener{addr: *addr}
|
||||
sock, err := newHVSocket()
|
||||
|
||||
var sock *win32File
|
||||
sock, err = newHVSocket()
|
||||
if err != nil {
|
||||
return nil, l.opErr("listen", err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = sock.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
sa := addr.raw()
|
||||
err = socket.Bind(windows.Handle(sock.handle), &sa)
|
||||
err = socket.Bind(sock.handle, &sa)
|
||||
if err != nil {
|
||||
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
|
||||
}
|
||||
err = syscall.Listen(sock.handle, 16)
|
||||
err = windows.Listen(sock.handle, 16)
|
||||
if err != nil {
|
||||
return nil, l.opErr("listen", os.NewSyscallError("listen", err))
|
||||
}
|
||||
@@ -246,7 +253,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
||||
var addrbuf [addrlen * 2]byte
|
||||
|
||||
var bytes uint32
|
||||
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /*rxdatalen*/, addrlen, addrlen, &bytes, &c.o)
|
||||
err = windows.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o)
|
||||
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
|
||||
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
|
||||
}
|
||||
@@ -263,7 +270,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
||||
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
|
||||
|
||||
// initialize the accepted socket and update its properties with those of the listening socket
|
||||
if err = windows.Setsockopt(windows.Handle(sock.handle),
|
||||
if err = windows.Setsockopt(sock.handle,
|
||||
windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT,
|
||||
(*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil {
|
||||
return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err))
|
||||
@@ -334,7 +341,7 @@ func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *Hvsock
|
||||
}()
|
||||
|
||||
sa := addr.raw()
|
||||
err = socket.Bind(windows.Handle(sock.handle), &sa)
|
||||
err = socket.Bind(sock.handle, &sa)
|
||||
if err != nil {
|
||||
return nil, conn.opErr(op, os.NewSyscallError("bind", err))
|
||||
}
|
||||
@@ -347,7 +354,7 @@ func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *Hvsock
|
||||
var bytes uint32
|
||||
for i := uint(0); i <= d.Retries; i++ {
|
||||
err = socket.ConnectEx(
|
||||
windows.Handle(sock.handle),
|
||||
sock.handle,
|
||||
&sa,
|
||||
nil, // sendBuf
|
||||
0, // sendDataLen
|
||||
@@ -367,7 +374,7 @@ func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *Hvsock
|
||||
|
||||
// update the connection properties, so shutdown can be used
|
||||
if err = windows.Setsockopt(
|
||||
windows.Handle(sock.handle),
|
||||
sock.handle,
|
||||
windows.SOL_SOCKET,
|
||||
windows.SO_UPDATE_CONNECT_CONTEXT,
|
||||
nil, // optvalue
|
||||
@@ -378,7 +385,7 @@ func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *Hvsock
|
||||
|
||||
// get the local name
|
||||
var sal rawHvsockAddr
|
||||
err = socket.GetSockName(windows.Handle(sock.handle), &sal)
|
||||
err = socket.GetSockName(sock.handle, &sal)
|
||||
if err != nil {
|
||||
return nil, conn.opErr(op, os.NewSyscallError("getsockname", err))
|
||||
}
|
||||
@@ -421,7 +428,7 @@ func (d *HvsockDialer) redialWait(ctx context.Context) (err error) {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
// assumes error is a plain, unwrapped syscall.Errno provided by direct syscall.
|
||||
// assumes error is a plain, unwrapped windows.Errno provided by direct syscall.
|
||||
func canRedial(err error) bool {
|
||||
//nolint:errorlint // guaranteed to be an Errno
|
||||
switch err {
|
||||
@@ -447,9 +454,9 @@ func (conn *HvsockConn) Read(b []byte) (int, error) {
|
||||
return 0, conn.opErr("read", err)
|
||||
}
|
||||
defer conn.sock.wg.Done()
|
||||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||
buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||
var flags, bytes uint32
|
||||
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
|
||||
err = windows.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
|
||||
n, err := conn.sock.asyncIO(c, &conn.sock.readDeadline, bytes, err)
|
||||
if err != nil {
|
||||
var eno windows.Errno
|
||||
@@ -482,9 +489,9 @@ func (conn *HvsockConn) write(b []byte) (int, error) {
|
||||
return 0, conn.opErr("write", err)
|
||||
}
|
||||
defer conn.sock.wg.Done()
|
||||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||
buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||
var bytes uint32
|
||||
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
|
||||
err = windows.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
|
||||
n, err := conn.sock.asyncIO(c, &conn.sock.writeDeadline, bytes, err)
|
||||
if err != nil {
|
||||
var eno windows.Errno
|
||||
@@ -511,7 +518,7 @@ func (conn *HvsockConn) shutdown(how int) error {
|
||||
return socket.ErrSocketClosed
|
||||
}
|
||||
|
||||
err := syscall.Shutdown(conn.sock.handle, how)
|
||||
err := windows.Shutdown(conn.sock.handle, how)
|
||||
if err != nil {
|
||||
// If the connection was closed, shutdowns fail with "not connected"
|
||||
if errors.Is(err, windows.WSAENOTCONN) ||
|
||||
@@ -525,7 +532,7 @@ func (conn *HvsockConn) shutdown(how int) error {
|
||||
|
||||
// CloseRead shuts down the read end of the socket, preventing future read operations.
|
||||
func (conn *HvsockConn) CloseRead() error {
|
||||
err := conn.shutdown(syscall.SHUT_RD)
|
||||
err := conn.shutdown(windows.SHUT_RD)
|
||||
if err != nil {
|
||||
return conn.opErr("closeread", err)
|
||||
}
|
||||
@@ -535,7 +542,7 @@ func (conn *HvsockConn) CloseRead() error {
|
||||
// CloseWrite shuts down the write end of the socket, preventing future write operations and
|
||||
// notifying the other endpoint that no more data will be written.
|
||||
func (conn *HvsockConn) CloseWrite() error {
|
||||
err := conn.shutdown(syscall.SHUT_WR)
|
||||
err := conn.shutdown(windows.SHUT_WR)
|
||||
if err != nil {
|
||||
return conn.opErr("closewrite", err)
|
||||
}
|
||||
|
||||
2
vendor/github.com/Microsoft/go-winio/internal/fs/doc.go
generated
vendored
Normal file
2
vendor/github.com/Microsoft/go-winio/internal/fs/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// This package contains Win32 filesystem functionality.
|
||||
package fs
|
||||
262
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go
generated
vendored
Normal file
262
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
//go:build windows
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/stringbuffer"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
|
||||
//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
|
||||
|
||||
const NullHandle windows.Handle = 0
|
||||
|
||||
// AccessMask defines standard, specific, and generic rights.
|
||||
//
|
||||
// Used with CreateFile and NtCreateFile (and co.).
|
||||
//
|
||||
// Bitmask:
|
||||
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
|
||||
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
// +---------------+---------------+-------------------------------+
|
||||
// |G|G|G|G|Resvd|A| StandardRights| SpecificRights |
|
||||
// |R|W|E|A| |S| | |
|
||||
// +-+-------------+---------------+-------------------------------+
|
||||
//
|
||||
// GR Generic Read
|
||||
// GW Generic Write
|
||||
// GE Generic Exectue
|
||||
// GA Generic All
|
||||
// Resvd Reserved
|
||||
// AS Access Security System
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
|
||||
type AccessMask = windows.ACCESS_MASK
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// Not actually any.
|
||||
//
|
||||
// For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device"
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
|
||||
FILE_ANY_ACCESS AccessMask = 0
|
||||
|
||||
GENERIC_READ AccessMask = 0x8000_0000
|
||||
GENERIC_WRITE AccessMask = 0x4000_0000
|
||||
GENERIC_EXECUTE AccessMask = 0x2000_0000
|
||||
GENERIC_ALL AccessMask = 0x1000_0000
|
||||
ACCESS_SYSTEM_SECURITY AccessMask = 0x0100_0000
|
||||
|
||||
// Specific Object Access
|
||||
// from ntioapi.h
|
||||
|
||||
FILE_READ_DATA AccessMask = (0x0001) // file & pipe
|
||||
FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory
|
||||
|
||||
FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe
|
||||
FILE_ADD_FILE AccessMask = (0x0002) // directory
|
||||
|
||||
FILE_APPEND_DATA AccessMask = (0x0004) // file
|
||||
FILE_ADD_SUBDIRECTORY AccessMask = (0x0004) // directory
|
||||
FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe
|
||||
|
||||
FILE_READ_EA AccessMask = (0x0008) // file & directory
|
||||
FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
|
||||
|
||||
FILE_WRITE_EA AccessMask = (0x0010) // file & directory
|
||||
FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
|
||||
|
||||
FILE_EXECUTE AccessMask = (0x0020) // file
|
||||
FILE_TRAVERSE AccessMask = (0x0020) // directory
|
||||
|
||||
FILE_DELETE_CHILD AccessMask = (0x0040) // directory
|
||||
|
||||
FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all
|
||||
|
||||
FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all
|
||||
|
||||
FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
|
||||
FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
|
||||
FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
|
||||
FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
|
||||
|
||||
SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
|
||||
|
||||
// Standard Access
|
||||
// from ntseapi.h
|
||||
|
||||
DELETE AccessMask = 0x0001_0000
|
||||
READ_CONTROL AccessMask = 0x0002_0000
|
||||
WRITE_DAC AccessMask = 0x0004_0000
|
||||
WRITE_OWNER AccessMask = 0x0008_0000
|
||||
SYNCHRONIZE AccessMask = 0x0010_0000
|
||||
|
||||
STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
|
||||
|
||||
STANDARD_RIGHTS_READ AccessMask = READ_CONTROL
|
||||
STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL
|
||||
STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
|
||||
|
||||
STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
|
||||
)
|
||||
|
||||
type FileShareMode uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
FILE_SHARE_NONE FileShareMode = 0x00
|
||||
FILE_SHARE_READ FileShareMode = 0x01
|
||||
FILE_SHARE_WRITE FileShareMode = 0x02
|
||||
FILE_SHARE_DELETE FileShareMode = 0x04
|
||||
FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
|
||||
)
|
||||
|
||||
type FileCreationDisposition uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// from winbase.h
|
||||
|
||||
CREATE_NEW FileCreationDisposition = 0x01
|
||||
CREATE_ALWAYS FileCreationDisposition = 0x02
|
||||
OPEN_EXISTING FileCreationDisposition = 0x03
|
||||
OPEN_ALWAYS FileCreationDisposition = 0x04
|
||||
TRUNCATE_EXISTING FileCreationDisposition = 0x05
|
||||
)
|
||||
|
||||
// Create disposition values for NtCreate*
|
||||
type NTFileCreationDisposition uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// From ntioapi.h
|
||||
|
||||
FILE_SUPERSEDE NTFileCreationDisposition = 0x00
|
||||
FILE_OPEN NTFileCreationDisposition = 0x01
|
||||
FILE_CREATE NTFileCreationDisposition = 0x02
|
||||
FILE_OPEN_IF NTFileCreationDisposition = 0x03
|
||||
FILE_OVERWRITE NTFileCreationDisposition = 0x04
|
||||
FILE_OVERWRITE_IF NTFileCreationDisposition = 0x05
|
||||
FILE_MAXIMUM_DISPOSITION NTFileCreationDisposition = 0x05
|
||||
)
|
||||
|
||||
// CreateFile and co. take flags or attributes together as one parameter.
|
||||
// Define alias until we can use generics to allow both
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
|
||||
type FileFlagOrAttribute uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// from winnt.h
|
||||
|
||||
FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
|
||||
FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
|
||||
FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
|
||||
FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000
|
||||
FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000
|
||||
FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000
|
||||
FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000
|
||||
FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000
|
||||
FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000
|
||||
FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
|
||||
)
|
||||
|
||||
// NtCreate* functions take a dedicated CreateOptions parameter.
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/Winternl/nf-winternl-ntcreatefile
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-create-named-pipe-file
|
||||
type NTCreateOptions uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// From ntioapi.h
|
||||
|
||||
FILE_DIRECTORY_FILE NTCreateOptions = 0x0000_0001
|
||||
FILE_WRITE_THROUGH NTCreateOptions = 0x0000_0002
|
||||
FILE_SEQUENTIAL_ONLY NTCreateOptions = 0x0000_0004
|
||||
FILE_NO_INTERMEDIATE_BUFFERING NTCreateOptions = 0x0000_0008
|
||||
|
||||
FILE_SYNCHRONOUS_IO_ALERT NTCreateOptions = 0x0000_0010
|
||||
FILE_SYNCHRONOUS_IO_NONALERT NTCreateOptions = 0x0000_0020
|
||||
FILE_NON_DIRECTORY_FILE NTCreateOptions = 0x0000_0040
|
||||
FILE_CREATE_TREE_CONNECTION NTCreateOptions = 0x0000_0080
|
||||
|
||||
FILE_COMPLETE_IF_OPLOCKED NTCreateOptions = 0x0000_0100
|
||||
FILE_NO_EA_KNOWLEDGE NTCreateOptions = 0x0000_0200
|
||||
FILE_DISABLE_TUNNELING NTCreateOptions = 0x0000_0400
|
||||
FILE_RANDOM_ACCESS NTCreateOptions = 0x0000_0800
|
||||
|
||||
FILE_DELETE_ON_CLOSE NTCreateOptions = 0x0000_1000
|
||||
FILE_OPEN_BY_FILE_ID NTCreateOptions = 0x0000_2000
|
||||
FILE_OPEN_FOR_BACKUP_INTENT NTCreateOptions = 0x0000_4000
|
||||
FILE_NO_COMPRESSION NTCreateOptions = 0x0000_8000
|
||||
)
|
||||
|
||||
type FileSQSFlag = FileFlagOrAttribute
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
// from winbase.h
|
||||
|
||||
SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
|
||||
SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
|
||||
SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
|
||||
SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
|
||||
|
||||
SECURITY_SQOS_PRESENT FileSQSFlag = 0x0010_0000
|
||||
SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F_0000
|
||||
)
|
||||
|
||||
// GetFinalPathNameByHandle flags
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters
|
||||
type GetFinalPathFlag uint32
|
||||
|
||||
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
|
||||
const (
|
||||
GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
|
||||
|
||||
FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
|
||||
FILE_NAME_OPENED GetFinalPathFlag = 0x8
|
||||
|
||||
VOLUME_NAME_DOS GetFinalPathFlag = 0x0
|
||||
VOLUME_NAME_GUID GetFinalPathFlag = 0x1
|
||||
VOLUME_NAME_NT GetFinalPathFlag = 0x2
|
||||
VOLUME_NAME_NONE GetFinalPathFlag = 0x4
|
||||
)
|
||||
|
||||
// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
|
||||
// with the given handle and flags. It transparently takes care of creating a buffer of the
|
||||
// correct size for the call.
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
|
||||
func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) {
|
||||
b := stringbuffer.NewWString()
|
||||
//TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n?
|
||||
for {
|
||||
n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// If the buffer wasn't large enough, n will be the total size needed (including null terminator).
|
||||
// Resize and try again.
|
||||
if n > b.Cap() {
|
||||
b.ResizeTo(n)
|
||||
continue
|
||||
}
|
||||
// If the buffer is large enough, n will be the size not including the null terminator.
|
||||
// Convert to a Go string and return.
|
||||
return b.String(), nil
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/Microsoft/go-winio/internal/fs/security.go
generated
vendored
Normal file
12
vendor/github.com/Microsoft/go-winio/internal/fs/security.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package fs
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
|
||||
type SecurityImpersonationLevel int32 // C default enums underlying type is `int`, which is Go `int32`
|
||||
|
||||
// Impersonation levels
|
||||
const (
|
||||
SecurityAnonymous SecurityImpersonationLevel = 0
|
||||
SecurityIdentification SecurityImpersonationLevel = 1
|
||||
SecurityImpersonation SecurityImpersonationLevel = 2
|
||||
SecurityDelegation SecurityImpersonationLevel = 3
|
||||
)
|
||||
61
vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go
generated
vendored
Normal file
61
vendor/github.com/Microsoft/go-winio/internal/fs/zsyscall_windows.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
//go:build windows
|
||||
|
||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
errERROR_EINVAL error = syscall.EINVAL
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return errERROR_EINVAL
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
|
||||
procCreateFileW = modkernel32.NewProc("CreateFileW")
|
||||
)
|
||||
|
||||
func CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
|
||||
}
|
||||
|
||||
func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procCreateFileW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile))
|
||||
handle = windows.Handle(r0)
|
||||
if handle == windows.InvalidHandle {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
12
vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
generated
vendored
12
vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
generated
vendored
@@ -100,8 +100,8 @@ func (f *runtimeFunc) Load() error {
|
||||
(*byte)(unsafe.Pointer(&f.addr)),
|
||||
uint32(unsafe.Sizeof(f.addr)),
|
||||
&n,
|
||||
nil, //overlapped
|
||||
0, //completionRoutine
|
||||
nil, // overlapped
|
||||
0, // completionRoutine
|
||||
)
|
||||
})
|
||||
return f.err
|
||||
@@ -156,9 +156,7 @@ func connectEx(
|
||||
bytesSent *uint32,
|
||||
overlapped *windows.Overlapped,
|
||||
) (err error) {
|
||||
// todo: after upgrading to 1.18, switch from syscall.Syscall9 to syscall.SyscallN
|
||||
r1, _, e1 := syscall.Syscall9(connectExFunc.addr,
|
||||
7,
|
||||
r1, _, e1 := syscall.SyscallN(connectExFunc.addr,
|
||||
uintptr(s),
|
||||
uintptr(name),
|
||||
uintptr(namelen),
|
||||
@@ -166,8 +164,8 @@ func connectEx(
|
||||
uintptr(sendDataLen),
|
||||
uintptr(unsafe.Pointer(bytesSent)),
|
||||
uintptr(unsafe.Pointer(overlapped)),
|
||||
0,
|
||||
0)
|
||||
)
|
||||
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
|
||||
9
vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
generated
vendored
9
vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
generated
vendored
@@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -48,7 +45,7 @@ var (
|
||||
)
|
||||
|
||||
func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
|
||||
r1, _, e1 := syscall.SyscallN(procbind.Addr(), uintptr(s), uintptr(name), uintptr(namelen))
|
||||
if r1 == socketError {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -56,7 +53,7 @@ func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
|
||||
}
|
||||
|
||||
func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
|
||||
r1, _, e1 := syscall.SyscallN(procgetpeername.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
|
||||
if r1 == socketError {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -64,7 +61,7 @@ func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err err
|
||||
}
|
||||
|
||||
func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
|
||||
r1, _, e1 := syscall.SyscallN(procgetsockname.Addr(), uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
|
||||
if r1 == socketError {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
|
||||
132
vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go
generated
vendored
Normal file
132
vendor/github.com/Microsoft/go-winio/internal/stringbuffer/wstring.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package stringbuffer
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
// TODO: worth exporting and using in mkwinsyscall?
|
||||
|
||||
// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate
|
||||
// large path strings:
|
||||
// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
|
||||
const MinWStringCap = 310
|
||||
|
||||
// use *[]uint16 since []uint16 creates an extra allocation where the slice header
|
||||
// is copied to heap and then referenced via pointer in the interface header that sync.Pool
|
||||
// stores.
|
||||
var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly
|
||||
New: func() interface{} {
|
||||
b := make([]uint16, MinWStringCap)
|
||||
return &b
|
||||
},
|
||||
}
|
||||
|
||||
func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) }
|
||||
|
||||
// freeBuffer copies the slice header data, and puts a pointer to that in the pool.
|
||||
// This avoids taking a pointer to the slice header in WString, which can be set to nil.
|
||||
func freeBuffer(b []uint16) { pathPool.Put(&b) }
|
||||
|
||||
// WString is a wide string buffer ([]uint16) meant for storing UTF-16 encoded strings
|
||||
// for interacting with Win32 APIs.
|
||||
// Sizes are specified as uint32 and not int.
|
||||
//
|
||||
// It is not thread safe.
|
||||
type WString struct {
|
||||
// type-def allows casting to []uint16 directly, use struct to prevent that and allow adding fields in the future.
|
||||
|
||||
// raw buffer
|
||||
b []uint16
|
||||
}
|
||||
|
||||
// NewWString returns a [WString] allocated from a shared pool with an
|
||||
// initial capacity of at least [MinWStringCap].
|
||||
// Since the buffer may have been previously used, its contents are not guaranteed to be empty.
|
||||
//
|
||||
// The buffer should be freed via [WString.Free]
|
||||
func NewWString() *WString {
|
||||
return &WString{
|
||||
b: newBuffer(),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *WString) Free() {
|
||||
if b.empty() {
|
||||
return
|
||||
}
|
||||
freeBuffer(b.b)
|
||||
b.b = nil
|
||||
}
|
||||
|
||||
// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the
|
||||
// previous buffer back into pool.
|
||||
func (b *WString) ResizeTo(c uint32) uint32 {
|
||||
// already sufficient (or n is 0)
|
||||
if c <= b.Cap() {
|
||||
return b.Cap()
|
||||
}
|
||||
|
||||
if c <= MinWStringCap {
|
||||
c = MinWStringCap
|
||||
}
|
||||
// allocate at-least double buffer size, as is done in [bytes.Buffer] and other places
|
||||
if c <= 2*b.Cap() {
|
||||
c = 2 * b.Cap()
|
||||
}
|
||||
|
||||
b2 := make([]uint16, c)
|
||||
if !b.empty() {
|
||||
copy(b2, b.b)
|
||||
freeBuffer(b.b)
|
||||
}
|
||||
b.b = b2
|
||||
return c
|
||||
}
|
||||
|
||||
// Buffer returns the underlying []uint16 buffer.
|
||||
func (b *WString) Buffer() []uint16 {
|
||||
if b.empty() {
|
||||
return nil
|
||||
}
|
||||
return b.b
|
||||
}
|
||||
|
||||
// Pointer returns a pointer to the first uint16 in the buffer.
|
||||
// If the [WString.Free] has already been called, the pointer will be nil.
|
||||
func (b *WString) Pointer() *uint16 {
|
||||
if b.empty() {
|
||||
return nil
|
||||
}
|
||||
return &b.b[0]
|
||||
}
|
||||
|
||||
// String returns the returns the UTF-8 encoding of the UTF-16 string in the buffer.
|
||||
//
|
||||
// It assumes that the data is null-terminated.
|
||||
func (b *WString) String() string {
|
||||
// Using [windows.UTF16ToString] would require importing "golang.org/x/sys/windows"
|
||||
// and would make this code Windows-only, which makes no sense.
|
||||
// So copy UTF16ToString code into here.
|
||||
// If other windows-specific code is added, switch to [windows.UTF16ToString]
|
||||
|
||||
s := b.b
|
||||
for i, v := range s {
|
||||
if v == 0 {
|
||||
s = s[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
return string(utf16.Decode(s))
|
||||
}
|
||||
|
||||
// Cap returns the underlying buffer capacity.
|
||||
func (b *WString) Cap() uint32 {
|
||||
if b.empty() {
|
||||
return 0
|
||||
}
|
||||
return b.cap()
|
||||
}
|
||||
|
||||
func (b *WString) cap() uint32 { return uint32(cap(b.b)) }
|
||||
func (b *WString) empty() bool { return b == nil || b.cap() == 0 }
|
||||
137
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
137
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
@@ -11,28 +11,52 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/fs"
|
||||
)
|
||||
|
||||
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
|
||||
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
|
||||
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
|
||||
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
|
||||
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
||||
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
|
||||
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile
|
||||
//sys connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) = ConnectNamedPipe
|
||||
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateNamedPipeW
|
||||
//sys disconnectNamedPipe(pipe windows.Handle) (err error) = DisconnectNamedPipe
|
||||
//sys getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
|
||||
//sys getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
||||
//sys ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile
|
||||
//sys rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
|
||||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U
|
||||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl
|
||||
|
||||
type PipeConn interface {
|
||||
net.Conn
|
||||
Disconnect() error
|
||||
Flush() error
|
||||
}
|
||||
|
||||
// type aliases for mkwinsyscall code
|
||||
type (
|
||||
ntAccessMask = fs.AccessMask
|
||||
ntFileShareMode = fs.FileShareMode
|
||||
ntFileCreationDisposition = fs.NTFileCreationDisposition
|
||||
ntFileOptions = fs.NTCreateOptions
|
||||
)
|
||||
|
||||
type ioStatusBlock struct {
|
||||
Status, Information uintptr
|
||||
}
|
||||
|
||||
// typedef struct _OBJECT_ATTRIBUTES {
|
||||
// ULONG Length;
|
||||
// HANDLE RootDirectory;
|
||||
// PUNICODE_STRING ObjectName;
|
||||
// ULONG Attributes;
|
||||
// PVOID SecurityDescriptor;
|
||||
// PVOID SecurityQualityOfService;
|
||||
// } OBJECT_ATTRIBUTES;
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes
|
||||
type objectAttributes struct {
|
||||
Length uintptr
|
||||
RootDirectory uintptr
|
||||
@@ -48,6 +72,17 @@ type unicodeString struct {
|
||||
Buffer uintptr
|
||||
}
|
||||
|
||||
// typedef struct _SECURITY_DESCRIPTOR {
|
||||
// BYTE Revision;
|
||||
// BYTE Sbz1;
|
||||
// SECURITY_DESCRIPTOR_CONTROL Control;
|
||||
// PSID Owner;
|
||||
// PSID Group;
|
||||
// PACL Sacl;
|
||||
// PACL Dacl;
|
||||
// } SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-security_descriptor
|
||||
type securityDescriptor struct {
|
||||
Revision byte
|
||||
Sbz1 byte
|
||||
@@ -79,6 +114,8 @@ type win32Pipe struct {
|
||||
path string
|
||||
}
|
||||
|
||||
var _ PipeConn = (*win32Pipe)(nil)
|
||||
|
||||
type win32MessageBytePipe struct {
|
||||
win32Pipe
|
||||
writeClosed bool
|
||||
@@ -102,6 +139,10 @@ func (f *win32Pipe) SetDeadline(t time.Time) error {
|
||||
return f.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (f *win32Pipe) Disconnect() error {
|
||||
return disconnectNamedPipe(f.win32File.handle)
|
||||
}
|
||||
|
||||
// CloseWrite closes the write side of a message pipe in byte mode.
|
||||
func (f *win32MessageBytePipe) CloseWrite() error {
|
||||
if f.writeClosed {
|
||||
@@ -145,7 +186,7 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
|
||||
// zero-byte message, ensure that all future Read() calls
|
||||
// also return EOF.
|
||||
f.readEOF = true
|
||||
} else if err == syscall.ERROR_MORE_DATA { //nolint:errorlint // err is Errno
|
||||
} else if err == windows.ERROR_MORE_DATA { //nolint:errorlint // err is Errno
|
||||
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
|
||||
// and the message still has more bytes. Treat this as a success, since
|
||||
// this package presents all named pipes as byte streams.
|
||||
@@ -163,19 +204,20 @@ func (s pipeAddress) String() string {
|
||||
}
|
||||
|
||||
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
|
||||
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
|
||||
func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask, impLevel PipeImpLevel) (windows.Handle, error) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return syscall.Handle(0), ctx.Err()
|
||||
return windows.Handle(0), ctx.Err()
|
||||
default:
|
||||
h, err := createFile(*path,
|
||||
h, err := fs.CreateFile(*path,
|
||||
access,
|
||||
0,
|
||||
nil,
|
||||
syscall.OPEN_EXISTING,
|
||||
windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS,
|
||||
0)
|
||||
0, // mode
|
||||
nil, // security attributes
|
||||
fs.OPEN_EXISTING,
|
||||
fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.FileSQSFlag(impLevel),
|
||||
0, // template file handle
|
||||
)
|
||||
if err == nil {
|
||||
return h, nil
|
||||
}
|
||||
@@ -211,15 +253,33 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
||||
// DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
|
||||
// cancellation or timeout.
|
||||
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
|
||||
return DialPipeAccess(ctx, path, syscall.GENERIC_READ|syscall.GENERIC_WRITE)
|
||||
return DialPipeAccess(ctx, path, uint32(fs.GENERIC_READ|fs.GENERIC_WRITE))
|
||||
}
|
||||
|
||||
// PipeImpLevel is an enumeration of impersonation levels that may be set
|
||||
// when calling DialPipeAccessImpersonation.
|
||||
type PipeImpLevel uint32
|
||||
|
||||
const (
|
||||
PipeImpLevelAnonymous = PipeImpLevel(fs.SECURITY_ANONYMOUS)
|
||||
PipeImpLevelIdentification = PipeImpLevel(fs.SECURITY_IDENTIFICATION)
|
||||
PipeImpLevelImpersonation = PipeImpLevel(fs.SECURITY_IMPERSONATION)
|
||||
PipeImpLevelDelegation = PipeImpLevel(fs.SECURITY_DELEGATION)
|
||||
)
|
||||
|
||||
// DialPipeAccess attempts to connect to a named pipe by `path` with `access` until `ctx`
|
||||
// cancellation or timeout.
|
||||
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
|
||||
return DialPipeAccessImpLevel(ctx, path, access, PipeImpLevelAnonymous)
|
||||
}
|
||||
|
||||
// DialPipeAccessImpLevel attempts to connect to a named pipe by `path` with
|
||||
// `access` at `impLevel` until `ctx` cancellation or timeout. The other
|
||||
// DialPipe* implementations use PipeImpLevelAnonymous.
|
||||
func DialPipeAccessImpLevel(ctx context.Context, path string, access uint32, impLevel PipeImpLevel) (net.Conn, error) {
|
||||
var err error
|
||||
var h syscall.Handle
|
||||
h, err = tryDialPipe(ctx, &path, access)
|
||||
var h windows.Handle
|
||||
h, err = tryDialPipe(ctx, &path, fs.AccessMask(access), impLevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -232,7 +292,7 @@ func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn,
|
||||
|
||||
f, err := makeWin32File(h)
|
||||
if err != nil {
|
||||
syscall.Close(h)
|
||||
windows.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -252,7 +312,7 @@ type acceptResponse struct {
|
||||
}
|
||||
|
||||
type win32PipeListener struct {
|
||||
firstHandle syscall.Handle
|
||||
firstHandle windows.Handle
|
||||
path string
|
||||
config PipeConfig
|
||||
acceptCh chan (chan acceptResponse)
|
||||
@@ -260,8 +320,8 @@ type win32PipeListener struct {
|
||||
doneCh chan int
|
||||
}
|
||||
|
||||
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
|
||||
path16, err := syscall.UTF16FromString(path)
|
||||
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (windows.Handle, error) {
|
||||
path16, err := windows.UTF16FromString(path)
|
||||
if err != nil {
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
@@ -277,15 +337,20 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
|
||||
).Err(); err != nil {
|
||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||
}
|
||||
defer localFree(ntPath.Buffer)
|
||||
defer windows.LocalFree(windows.Handle(ntPath.Buffer)) //nolint:errcheck
|
||||
oa.ObjectName = &ntPath
|
||||
oa.Attributes = windows.OBJ_CASE_INSENSITIVE
|
||||
|
||||
// The security descriptor is only needed for the first pipe.
|
||||
if first {
|
||||
if sd != nil {
|
||||
//todo: does `sdb` need to be allocated on the heap, or can go allocate it?
|
||||
l := uint32(len(sd))
|
||||
sdb := localAlloc(0, l)
|
||||
defer localFree(sdb)
|
||||
sdb, err := windows.LocalAlloc(0, l)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("LocalAlloc for security descriptor with of length %d: %w", l, err)
|
||||
}
|
||||
defer windows.LocalFree(windows.Handle(sdb)) //nolint:errcheck
|
||||
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
|
||||
oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
|
||||
} else {
|
||||
@@ -294,7 +359,7 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
|
||||
if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
|
||||
return 0, fmt.Errorf("getting default named pipe ACL: %w", err)
|
||||
}
|
||||
defer localFree(dacl)
|
||||
defer windows.LocalFree(windows.Handle(dacl)) //nolint:errcheck
|
||||
|
||||
sdb := &securityDescriptor{
|
||||
Revision: 1,
|
||||
@@ -310,27 +375,27 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
|
||||
typ |= windows.FILE_PIPE_MESSAGE_TYPE
|
||||
}
|
||||
|
||||
disposition := uint32(windows.FILE_OPEN)
|
||||
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
|
||||
disposition := fs.FILE_OPEN
|
||||
access := fs.GENERIC_READ | fs.GENERIC_WRITE | fs.SYNCHRONIZE
|
||||
if first {
|
||||
disposition = windows.FILE_CREATE
|
||||
disposition = fs.FILE_CREATE
|
||||
// By not asking for read or write access, the named pipe file system
|
||||
// will put this pipe into an initially disconnected state, blocking
|
||||
// client connections until the next call with first == false.
|
||||
access = syscall.SYNCHRONIZE
|
||||
access = fs.SYNCHRONIZE
|
||||
}
|
||||
|
||||
timeout := int64(-50 * 10000) // 50ms
|
||||
|
||||
var (
|
||||
h syscall.Handle
|
||||
h windows.Handle
|
||||
iosb ioStatusBlock
|
||||
)
|
||||
err = ntCreateNamedPipeFile(&h,
|
||||
access,
|
||||
&oa,
|
||||
&iosb,
|
||||
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
|
||||
fs.FILE_SHARE_READ|fs.FILE_SHARE_WRITE,
|
||||
disposition,
|
||||
0,
|
||||
typ,
|
||||
@@ -355,7 +420,7 @@ func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
|
||||
}
|
||||
f, err := makeWin32File(h)
|
||||
if err != nil {
|
||||
syscall.Close(h)
|
||||
windows.Close(h)
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
@@ -414,7 +479,7 @@ func (l *win32PipeListener) listenerRoutine() {
|
||||
closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
|
||||
}
|
||||
}
|
||||
syscall.Close(l.firstHandle)
|
||||
windows.Close(l.firstHandle)
|
||||
l.firstHandle = 0
|
||||
// Notify Close() and Accept() callers that the handle has been closed.
|
||||
close(l.doneCh)
|
||||
|
||||
9
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
9
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
@@ -9,7 +9,6 @@ import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@@ -18,8 +17,8 @@ import (
|
||||
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
|
||||
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
|
||||
//sys revertToSelf() (err error) = advapi32.RevertToSelf
|
||||
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
|
||||
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
|
||||
//sys openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
|
||||
//sys getCurrentThread() (h windows.Handle) = GetCurrentThread
|
||||
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
|
||||
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
|
||||
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
||||
@@ -29,7 +28,7 @@ const (
|
||||
SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED
|
||||
|
||||
//revive:disable-next-line:var-naming ALL_CAPS
|
||||
ERROR_NOT_ALL_ASSIGNED syscall.Errno = windows.ERROR_NOT_ALL_ASSIGNED
|
||||
ERROR_NOT_ALL_ASSIGNED windows.Errno = windows.ERROR_NOT_ALL_ASSIGNED
|
||||
|
||||
SeBackupPrivilege = "SeBackupPrivilege"
|
||||
SeRestorePrivilege = "SeRestorePrivilege"
|
||||
@@ -177,7 +176,7 @@ func newThreadToken() (windows.Token, error) {
|
||||
}
|
||||
|
||||
var token windows.Token
|
||||
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
|
||||
err = openThreadToken(getCurrentThread(), windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, false, &token)
|
||||
if err != nil {
|
||||
rerr := revertToSelf()
|
||||
if rerr != nil {
|
||||
|
||||
37
vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
37
vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
@@ -5,7 +5,7 @@ package winio
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@@ -15,10 +15,6 @@ import (
|
||||
//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW
|
||||
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
||||
//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW
|
||||
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
|
||||
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
|
||||
//sys localFree(mem uintptr) = LocalFree
|
||||
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
|
||||
|
||||
type AccountLookupError struct {
|
||||
Name string
|
||||
@@ -64,7 +60,7 @@ func LookupSidByName(name string) (sid string, err error) {
|
||||
|
||||
var sidSize, sidNameUse, refDomainSize uint32
|
||||
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
|
||||
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
|
||||
if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
|
||||
return "", &AccountLookupError{name, err}
|
||||
}
|
||||
sidBuffer := make([]byte, sidSize)
|
||||
@@ -78,8 +74,8 @@ func LookupSidByName(name string) (sid string, err error) {
|
||||
if err != nil {
|
||||
return "", &AccountLookupError{name, err}
|
||||
}
|
||||
sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
|
||||
localFree(uintptr(unsafe.Pointer(strBuffer)))
|
||||
sid = windows.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
|
||||
_, _ = windows.LocalFree(windows.Handle(unsafe.Pointer(strBuffer)))
|
||||
return sid, nil
|
||||
}
|
||||
|
||||
@@ -100,7 +96,7 @@ func LookupNameBySid(sid string) (name string, err error) {
|
||||
if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil {
|
||||
return "", &AccountLookupError{sid, err}
|
||||
}
|
||||
defer localFree(uintptr(unsafe.Pointer(sidPtr)))
|
||||
defer windows.LocalFree(windows.Handle(unsafe.Pointer(sidPtr))) //nolint:errcheck
|
||||
|
||||
var nameSize, refDomainSize, sidNameUse uint32
|
||||
err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse)
|
||||
@@ -120,25 +116,18 @@ func LookupNameBySid(sid string) (name string, err error) {
|
||||
}
|
||||
|
||||
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
||||
var sdBuffer uintptr
|
||||
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
|
||||
sd, err := windows.SecurityDescriptorFromString(sddl)
|
||||
if err != nil {
|
||||
return nil, &SddlConversionError{sddl, err}
|
||||
return nil, &SddlConversionError{Sddl: sddl, Err: err}
|
||||
}
|
||||
defer localFree(sdBuffer)
|
||||
sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
|
||||
copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
|
||||
return sd, nil
|
||||
b := unsafe.Slice((*byte)(unsafe.Pointer(sd)), sd.Length())
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func SecurityDescriptorToSddl(sd []byte) (string, error) {
|
||||
var sddl *uint16
|
||||
// The returned string length seems to include an arbitrary number of terminating NULs.
|
||||
// Don't use it.
|
||||
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
if l := int(unsafe.Sizeof(windows.SECURITY_DESCRIPTOR{})); len(sd) < l {
|
||||
return "", fmt.Errorf("SecurityDescriptor (%d) smaller than expected (%d): %w", len(sd), l, windows.ERROR_INCORRECT_SIZE)
|
||||
}
|
||||
defer localFree(uintptr(unsafe.Pointer(sddl)))
|
||||
return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
|
||||
s := (*windows.SECURITY_DESCRIPTOR)(unsafe.Pointer(&sd[0]))
|
||||
return s.String(), nil
|
||||
}
|
||||
|
||||
5
vendor/github.com/Microsoft/go-winio/tools.go
generated
vendored
5
vendor/github.com/Microsoft/go-winio/tools.go
generated
vendored
@@ -1,5 +0,0 @@
|
||||
//go:build tools
|
||||
|
||||
package winio
|
||||
|
||||
import _ "golang.org/x/tools/cmd/stringer"
|
||||
13
vendor/github.com/Microsoft/go-winio/vhd/zvhd_windows.go
generated
vendored
13
vendor/github.com/Microsoft/go-winio/vhd/zvhd_windows.go
generated
vendored
@@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -50,7 +47,7 @@ var (
|
||||
)
|
||||
|
||||
func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
|
||||
r0, _, _ := syscall.SyscallN(procAttachVirtualDisk.Addr(), uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
@@ -67,7 +64,7 @@ func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virt
|
||||
}
|
||||
|
||||
func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
|
||||
r0, _, _ := syscall.SyscallN(procCreateVirtualDisk.Addr(), uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
@@ -75,7 +72,7 @@ func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, vi
|
||||
}
|
||||
|
||||
func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
|
||||
r0, _, _ := syscall.SyscallN(procDetachVirtualDisk.Addr(), uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
@@ -83,7 +80,7 @@ func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, pro
|
||||
}
|
||||
|
||||
func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
|
||||
r0, _, _ := syscall.SyscallN(procGetVirtualDiskPhysicalPath.Addr(), uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
@@ -100,7 +97,7 @@ func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtua
|
||||
}
|
||||
|
||||
func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) {
|
||||
r0, _, _ := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
|
||||
r0, _, _ := syscall.SyscallN(procOpenVirtualDisk.Addr(), uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
|
||||
if r0 != 0 {
|
||||
win32err = syscall.Errno(r0)
|
||||
}
|
||||
|
||||
230
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
230
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
@@ -33,9 +33,6 @@ func errnoErr(e syscall.Errno) error {
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -45,39 +42,34 @@ var (
|
||||
modntdll = windows.NewLazySystemDLL("ntdll.dll")
|
||||
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
|
||||
|
||||
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
|
||||
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
|
||||
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
||||
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
||||
procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
|
||||
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
|
||||
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
||||
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
||||
procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
|
||||
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
||||
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
||||
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
|
||||
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
|
||||
procBackupRead = modkernel32.NewProc("BackupRead")
|
||||
procBackupWrite = modkernel32.NewProc("BackupWrite")
|
||||
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
|
||||
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
|
||||
procCreateFileW = modkernel32.NewProc("CreateFileW")
|
||||
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
|
||||
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
|
||||
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
|
||||
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
|
||||
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
|
||||
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
|
||||
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
|
||||
procLocalFree = modkernel32.NewProc("LocalFree")
|
||||
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
|
||||
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
|
||||
procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl")
|
||||
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
|
||||
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
|
||||
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
|
||||
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
|
||||
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
||||
procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
|
||||
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
||||
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
||||
procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
|
||||
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
||||
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
||||
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
|
||||
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
|
||||
procBackupRead = modkernel32.NewProc("BackupRead")
|
||||
procBackupWrite = modkernel32.NewProc("BackupWrite")
|
||||
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
|
||||
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
|
||||
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
|
||||
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
|
||||
procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
|
||||
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
|
||||
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
|
||||
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
|
||||
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
|
||||
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
|
||||
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
|
||||
procRtlDefaultNpAcl = modntdll.NewProc("RtlDefaultNpAcl")
|
||||
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
|
||||
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
|
||||
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
|
||||
)
|
||||
|
||||
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
|
||||
@@ -85,7 +77,7 @@ func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, ou
|
||||
if releaseAll {
|
||||
_p0 = 1
|
||||
}
|
||||
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
|
||||
r0, _, e1 := syscall.SyscallN(procAdjustTokenPrivileges.Addr(), uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
|
||||
success = r0 != 0
|
||||
if true {
|
||||
err = errnoErr(e1)
|
||||
@@ -93,33 +85,8 @@ func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, ou
|
||||
return
|
||||
}
|
||||
|
||||
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(str)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
|
||||
}
|
||||
|
||||
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procConvertSidToStringSidW.Addr(), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -127,21 +94,15 @@ func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision
|
||||
}
|
||||
|
||||
func convertStringSidToSid(str *uint16, sid **byte) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procConvertStringSidToSidW.Addr(), uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
|
||||
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
|
||||
len = uint32(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func impersonateSelf(level uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procImpersonateSelf.Addr(), uintptr(level))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -158,7 +119,7 @@ func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSiz
|
||||
}
|
||||
|
||||
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procLookupAccountNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -166,7 +127,7 @@ func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidS
|
||||
}
|
||||
|
||||
func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procLookupAccountSidW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -183,7 +144,7 @@ func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16,
|
||||
}
|
||||
|
||||
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeDisplayNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -200,7 +161,7 @@ func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *
|
||||
}
|
||||
|
||||
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeNameW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -222,19 +183,19 @@ func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err err
|
||||
}
|
||||
|
||||
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
|
||||
r1, _, e1 := syscall.SyscallN(procLookupPrivilegeValueW.Addr(), uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
|
||||
func openThreadToken(thread windows.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
|
||||
var _p0 uint32
|
||||
if openAsSelf {
|
||||
_p0 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procOpenThreadToken.Addr(), uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -242,14 +203,14 @@ func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool,
|
||||
}
|
||||
|
||||
func revertToSelf() (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procRevertToSelf.Addr())
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
|
||||
func backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
|
||||
var _p0 *byte
|
||||
if len(b) > 0 {
|
||||
_p0 = &b[0]
|
||||
@@ -262,14 +223,14 @@ func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, proce
|
||||
if processSecurity {
|
||||
_p2 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procBackupRead.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
|
||||
func backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
|
||||
var _p0 *byte
|
||||
if len(b) > 0 {
|
||||
_p0 = &b[0]
|
||||
@@ -282,57 +243,39 @@ func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, p
|
||||
if processSecurity {
|
||||
_p2 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
|
||||
r1, _, e1 := syscall.SyscallN(procBackupWrite.Addr(), uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
|
||||
func cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procCancelIoEx.Addr(), uintptr(file), uintptr(unsafe.Pointer(o)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
|
||||
func connectNamedPipe(pipe windows.Handle, o *windows.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procConnectNamedPipe.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(o)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
|
||||
}
|
||||
|
||||
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
|
||||
handle = syscall.Handle(r0)
|
||||
if handle == syscall.InvalidHandle {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
|
||||
newport = syscall.Handle(r0)
|
||||
func createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procCreateIoCompletionPort.Addr(), uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount))
|
||||
newport = windows.Handle(r0)
|
||||
if newport == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
|
||||
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) {
|
||||
var _p0 *uint16
|
||||
_p0, err = syscall.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
@@ -341,96 +284,93 @@ func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances ui
|
||||
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
|
||||
}
|
||||
|
||||
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
|
||||
handle = syscall.Handle(r0)
|
||||
if handle == syscall.InvalidHandle {
|
||||
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *windows.SecurityAttributes) (handle windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.SyscallN(procCreateNamedPipeW.Addr(), uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)))
|
||||
handle = windows.Handle(r0)
|
||||
if handle == windows.InvalidHandle {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getCurrentThread() (h syscall.Handle) {
|
||||
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
|
||||
h = syscall.Handle(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
|
||||
func disconnectNamedPipe(pipe windows.Handle) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procDisconnectNamedPipe.Addr(), uintptr(pipe))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
|
||||
func getCurrentThread() (h windows.Handle) {
|
||||
r0, _, _ := syscall.SyscallN(procGetCurrentThread.Addr())
|
||||
h = windows.Handle(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func getNamedPipeHandleState(pipe windows.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procGetNamedPipeHandleStateW.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
|
||||
func getNamedPipeInfo(pipe windows.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procGetNamedPipeInfo.Addr(), uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func localAlloc(uFlags uint32, length uint32) (ptr uintptr) {
|
||||
r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0)
|
||||
ptr = uintptr(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func localFree(mem uintptr) {
|
||||
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
|
||||
func getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procGetQueuedCompletionStatus.Addr(), uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) {
|
||||
r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
|
||||
func setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procSetFileCompletionNotificationModes.Addr(), uintptr(h), uintptr(flags))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ntCreateNamedPipeFile(pipe *windows.Handle, access ntAccessMask, oa *objectAttributes, iosb *ioStatusBlock, share ntFileShareMode, disposition ntFileCreationDisposition, options ntFileOptions, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) {
|
||||
r0, _, _ := syscall.SyscallN(procNtCreateNamedPipeFile.Addr(), uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)))
|
||||
status = ntStatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) {
|
||||
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procRtlDefaultNpAcl.Addr(), uintptr(unsafe.Pointer(dacl)))
|
||||
status = ntStatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) {
|
||||
r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procRtlDosPathNameToNtPathName_U.Addr(), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved))
|
||||
status = ntStatus(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func rtlNtStatusToDosError(status ntStatus) (winerr error) {
|
||||
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procRtlNtStatusToDosErrorNoTeb.Addr(), uintptr(status))
|
||||
if r0 != 0 {
|
||||
winerr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
|
||||
func wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
|
||||
var _p0 uint32
|
||||
if wait {
|
||||
_p0 = 1
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
|
||||
r1, _, e1 := syscall.SyscallN(procWSAGetOverlappedResult.Addr(), uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
|
||||
4
vendor/github.com/Microsoft/hcsshim/.gitattributes
generated
vendored
4
vendor/github.com/Microsoft/hcsshim/.gitattributes
generated
vendored
@@ -1 +1,3 @@
|
||||
* text=auto eol=lf
|
||||
* text=auto eol=lf
|
||||
vendor/** -text
|
||||
test/vendor/** -text
|
||||
19
vendor/github.com/Microsoft/hcsshim/.gitignore
generated
vendored
19
vendor/github.com/Microsoft/hcsshim/.gitignore
generated
vendored
@@ -6,6 +6,7 @@
|
||||
|
||||
# Ignore vscode setting files
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
@@ -23,16 +24,30 @@ service/pkg/
|
||||
*.img
|
||||
*.vhd
|
||||
*.tar.gz
|
||||
*.tar
|
||||
|
||||
# Make stuff
|
||||
.rootfs-done
|
||||
bin/*
|
||||
rootfs/*
|
||||
rootfs-conv/*
|
||||
*.o
|
||||
/build/
|
||||
|
||||
deps/*
|
||||
out/*
|
||||
|
||||
.idea/
|
||||
.vscode/
|
||||
# protobuf files
|
||||
# only files at root of the repo, otherwise this will cause issues with vendoring
|
||||
/protobuf/*
|
||||
|
||||
# test results
|
||||
test/results
|
||||
|
||||
# go workspace files
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
# keys and related artifacts
|
||||
*.pem
|
||||
*.cose
|
||||
|
||||
93
vendor/github.com/Microsoft/hcsshim/.golangci.yml
generated
vendored
93
vendor/github.com/Microsoft/hcsshim/.golangci.yml
generated
vendored
@@ -1,23 +1,72 @@
|
||||
run:
|
||||
timeout: 8m
|
||||
tests: true
|
||||
build-tags:
|
||||
- admin
|
||||
- functional
|
||||
- integration
|
||||
skip-dirs:
|
||||
# paths are relative to module root
|
||||
- cri-containerd/test-images
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- stylecheck
|
||||
# defaults:
|
||||
# - errcheck
|
||||
# - gosimple
|
||||
# - govet
|
||||
# - ineffassign
|
||||
# - staticcheck
|
||||
# - typecheck
|
||||
# - unused
|
||||
|
||||
- errorlint # error wrapping (eg, not using `errors.Is`, using `%s` instead of `%w` in `fmt.Errorf`)
|
||||
- gofmt # whether code was gofmt-ed
|
||||
- govet # enabled by default, but just to be sure
|
||||
- nolintlint # ill-formed or insufficient nolint directives
|
||||
- stylecheck # golint replacement
|
||||
- thelper # test helpers without t.Helper()
|
||||
|
||||
linters-settings:
|
||||
govet:
|
||||
enable-all: true
|
||||
disable:
|
||||
# struct order is often for Win32 compat
|
||||
# also, ignore pointer bytes/GC issues for now until performance becomes an issue
|
||||
- fieldalignment
|
||||
check-shadowing: true
|
||||
|
||||
stylecheck:
|
||||
# https://staticcheck.io/docs/checks
|
||||
checks: ["all"]
|
||||
|
||||
|
||||
issues:
|
||||
# This repo has a LOT of generated schema files, operating system bindings, and other things that ST1003 from stylecheck won't like
|
||||
# (screaming case Windows api constants for example). There's also some structs that we *could* change the initialisms to be Go
|
||||
# friendly (Id -> ID) but they're exported and it would be a breaking change. This makes it so that most new code, code that isn't
|
||||
# supposed to be a pretty faithful mapping to an OS call/constants, or non-generated code still checks if we're following idioms,
|
||||
# while ignoring the things that are just noise or would be more of a hassle than it'd be worth to change.
|
||||
exclude-rules:
|
||||
# err is very often shadowed in nested scopes
|
||||
- linters:
|
||||
- govet
|
||||
text: '^shadow: declaration of "err" shadows declaration'
|
||||
|
||||
# path is relative to module root, which is ./test/
|
||||
- path: cri-containerd
|
||||
linters:
|
||||
- stylecheck
|
||||
text: "^ST1003: should not use underscores in package names$"
|
||||
source: "^package cri_containerd$"
|
||||
|
||||
# don't bother with propper error wrapping in test code
|
||||
- path: cri-containerd
|
||||
linters:
|
||||
- errorlint
|
||||
text: "non-wrapping format verb for fmt.Errorf"
|
||||
|
||||
# This repo has a LOT of generated schema files, operating system bindings, and other
|
||||
# things that ST1003 from stylecheck won't like (screaming case Windows api constants for example).
|
||||
# There's also some structs that we *could* change the initialisms to be Go friendly
|
||||
# (Id -> ID) but they're exported and it would be a breaking change.
|
||||
# This makes it so that most new code, code that isn't supposed to be a pretty faithful
|
||||
# mapping to an OS call/constants, or non-generated code still checks if we're following idioms,
|
||||
# while ignoring the things that are just noise or would be more of a hassle than it'd be worth to change.
|
||||
- path: layer.go
|
||||
linters:
|
||||
- stylecheck
|
||||
@@ -28,11 +77,21 @@ issues:
|
||||
- stylecheck
|
||||
Text: "ST1003:"
|
||||
|
||||
- path: internal\\hcs\\schema2\\
|
||||
- path: cmd\\ncproxy\\nodenetsvc\\
|
||||
linters:
|
||||
- stylecheck
|
||||
Text: "ST1003:"
|
||||
|
||||
- path: cmd\\ncproxy_mock\\
|
||||
linters:
|
||||
- stylecheck
|
||||
Text: "ST1003:"
|
||||
|
||||
- path: internal\\hcs\\schema2\\
|
||||
linters:
|
||||
- stylecheck
|
||||
- gofmt
|
||||
|
||||
- path: internal\\wclayer\\
|
||||
linters:
|
||||
- stylecheck
|
||||
@@ -96,4 +155,20 @@ issues:
|
||||
- path: internal\\hcserror\\
|
||||
linters:
|
||||
- stylecheck
|
||||
Text: "ST1003:"
|
||||
Text: "ST1003:"
|
||||
|
||||
# v0 APIs are deprecated, but still retained for backwards compatability
|
||||
- path: cmd\\ncproxy\\
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "^SA1019: .*(ncproxygrpc|nodenetsvc)[/]?v0"
|
||||
|
||||
- path: internal\\tools\\networkagent
|
||||
linters:
|
||||
- staticcheck
|
||||
text: "^SA1019: .*nodenetsvc[/]?v0"
|
||||
|
||||
- path: internal\\vhdx\\info
|
||||
linters:
|
||||
- stylecheck
|
||||
Text: "ST1003:"
|
||||
|
||||
167
vendor/github.com/Microsoft/hcsshim/Makefile
generated
vendored
167
vendor/github.com/Microsoft/hcsshim/Makefile
generated
vendored
@@ -1,4 +1,5 @@
|
||||
BASE:=base.tar.gz
|
||||
DEV_BUILD:=0
|
||||
|
||||
GO:=go
|
||||
GO_FLAGS:=-ldflags "-s -w" # strip Go binaries
|
||||
@@ -12,15 +13,41 @@ GO_FLAGS_EXTRA:=
|
||||
ifeq "$(GOMODVENDOR)" "1"
|
||||
GO_FLAGS_EXTRA += -mod=vendor
|
||||
endif
|
||||
GO_BUILD_TAGS:=
|
||||
ifneq ($(strip $(GO_BUILD_TAGS)),)
|
||||
GO_FLAGS_EXTRA += -tags="$(GO_BUILD_TAGS)"
|
||||
endif
|
||||
GO_BUILD:=CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(GO_FLAGS) $(GO_FLAGS_EXTRA)
|
||||
|
||||
SRCROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST))))
|
||||
# additional directories to search for rule prerequisites and targets
|
||||
VPATH=$(SRCROOT)
|
||||
|
||||
DELTA_TARGET=out/delta.tar.gz
|
||||
|
||||
ifeq "$(DEV_BUILD)" "1"
|
||||
DELTA_TARGET=out/delta-dev.tar.gz
|
||||
endif
|
||||
|
||||
ifeq "$(SNP_BUILD)" "1"
|
||||
DELTA_TARGET=out/delta-snp.tar.gz
|
||||
endif
|
||||
|
||||
# The link aliases for gcstools
|
||||
GCS_TOOLS=\
|
||||
generichook
|
||||
generichook \
|
||||
install-drivers
|
||||
|
||||
.PHONY: all always rootfs test
|
||||
# Common path prefix.
|
||||
PATH_PREFIX:=
|
||||
# These have PATH_PREFIX prepended to obtain the full path in recipies e.g. $(PATH_PREFIX)/$(VMGS_TOOL)
|
||||
VMGS_TOOL:=
|
||||
IGVM_TOOL:=
|
||||
KERNEL_PATH:=
|
||||
|
||||
.PHONY: all always rootfs test snp simple
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
all: out/initrd.img out/rootfs.tar.gz
|
||||
|
||||
@@ -29,21 +56,62 @@ clean:
|
||||
rm -rf bin deps rootfs out
|
||||
|
||||
test:
|
||||
cd $(SRCROOT) && go test -v ./internal/guest/...
|
||||
cd $(SRCROOT) && $(GO) test -v ./internal/guest/...
|
||||
|
||||
out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools Makefile
|
||||
@mkdir -p out
|
||||
rm -rf rootfs
|
||||
mkdir -p rootfs/bin/
|
||||
cp bin/init rootfs/
|
||||
cp bin/vsockexec rootfs/bin/
|
||||
cp bin/cmd/gcs rootfs/bin/
|
||||
cp bin/cmd/gcstools rootfs/bin/
|
||||
for tool in $(GCS_TOOLS); do ln -s gcstools rootfs/bin/$$tool; done
|
||||
git -C $(SRCROOT) rev-parse HEAD > rootfs/gcs.commit && \
|
||||
git -C $(SRCROOT) rev-parse --abbrev-ref HEAD > rootfs/gcs.branch
|
||||
tar -zcf $@ -C rootfs .
|
||||
rm -rf rootfs
|
||||
rootfs: out/rootfs.vhd
|
||||
|
||||
snp: out/kernelinitrd.vmgs out/rootfs.hash.vhd out/rootfs.vhd out/v2056.vmgs
|
||||
|
||||
simple: out/simple.vmgs snp
|
||||
|
||||
%.vmgs: %.bin
|
||||
rm -f $@
|
||||
# du -BM returns the size of the bin file in M, eg 7M. The sed command replaces the M with *1024*1024 and then bc does the math to convert to bytes
|
||||
$(PATH_PREFIX)/$(VMGS_TOOL) create --filepath $@ --filesize `du -BM $< | sed "s/M.*/*1024*1024/" | bc`
|
||||
$(PATH_PREFIX)/$(VMGS_TOOL) write --filepath $@ --datapath $< -i=8
|
||||
|
||||
# Simplest debug UVM used to test changes to the linux kernel. No dmverity protection. Boots an initramdisk rather than directly booting a vhd disk.
|
||||
out/simple.bin: out/initrd.img $(PATH_PREFIX)/$(KERNEL_PATH) boot/startup_simple.sh
|
||||
rm -f $@
|
||||
python3 $(PATH_PREFIX)/$(IGVM_TOOL) -o $@ -kernel $(PATH_PREFIX)/$(KERNEL_PATH) -append "8250_core.nr_uarts=0 panic=-1 debug loglevel=7 rdinit=/startup_simple.sh" -rdinit out/initrd.img -vtl 0
|
||||
|
||||
ROOTFS_DEVICE:=/dev/sda
|
||||
VERITY_DEVICE:=/dev/sdb
|
||||
# Debug build for use with uvmtester. UVM with dm-verity protected vhd disk mounted directly via the kernel command line. Ignores corruption in dm-verity protected disk. (Use dmesg to see if dm-verity is ignoring data corruption.)
|
||||
out/v2056.bin: out/rootfs.vhd out/rootfs.hash.vhd $(PATH_PREFIX)/$(KERNEL_PATH) out/rootfs.hash.datasectors out/rootfs.hash.datablocksize out/rootfs.hash.hashblocksize out/rootfs.hash.datablocks out/rootfs.hash.rootdigest out/rootfs.hash.salt boot/startup_v2056.sh
|
||||
rm -f $@
|
||||
python3 $(PATH_PREFIX)/$(IGVM_TOOL) -o $@ -kernel $(PATH_PREFIX)/$(KERNEL_PATH) -append "8250_core.nr_uarts=0 panic=-1 debug loglevel=7 root=/dev/dm-0 dm-mod.create=\"dmverity,,,ro,0 $(shell cat out/rootfs.hash.datasectors) verity 1 $(ROOTFS_DEVICE) $(VERITY_DEVICE) $(shell cat out/rootfs.hash.datablocksize) $(shell cat out/rootfs.hash.hashblocksize) $(shell cat out/rootfs.hash.datablocks) 0 sha256 $(shell cat out/rootfs.hash.rootdigest) $(shell cat out/rootfs.hash.salt) 1 ignore_corruption\" init=/startup_v2056.sh" -vtl 0
|
||||
|
||||
# Full UVM with dm-verity protected vhd disk mounted directly via the kernel command line.
|
||||
out/kernelinitrd.bin: out/rootfs.vhd out/rootfs.hash.vhd out/rootfs.hash.datasectors out/rootfs.hash.datablocksize out/rootfs.hash.hashblocksize out/rootfs.hash.datablocks out/rootfs.hash.rootdigest out/rootfs.hash.salt $(PATH_PREFIX)/$(KERNEL_PATH) boot/startup.sh
|
||||
rm -f $@
|
||||
python3 $(PATH_PREFIX)/$(IGVM_TOOL) -o $@ -kernel $(PATH_PREFIX)/$(KERNEL_PATH) -append "8250_core.nr_uarts=0 panic=-1 debug loglevel=7 root=/dev/dm-0 dm-mod.create=\"dmverity,,,ro,0 $(shell cat out/rootfs.hash.datasectors) verity 1 $(ROOTFS_DEVICE) $(VERITY_DEVICE) $(shell cat out/rootfs.hash.datablocksize) $(shell cat out/rootfs.hash.hashblocksize) $(shell cat out/rootfs.hash.datablocks) 0 sha256 $(shell cat out/rootfs.hash.rootdigest) $(shell cat out/rootfs.hash.salt)\" init=/startup.sh" -vtl 0
|
||||
|
||||
# Rule to make a vhd from a file. This is used to create the rootfs.hash.vhd from rootfs.hash.
|
||||
%.vhd: % bin/cmd/tar2ext4
|
||||
./bin/cmd/tar2ext4 -only-vhd -i $< -o $@
|
||||
|
||||
# Rule to make a vhd from an ext4 file. This is used to create the rootfs.vhd from rootfs.ext4.
|
||||
%.vhd: %.ext4 bin/cmd/tar2ext4
|
||||
./bin/cmd/tar2ext4 -only-vhd -i $< -o $@
|
||||
|
||||
%.hash %.hash.info %.hash.datablocks %.hash.rootdigest %hash.datablocksize %.hash.datasectors %.hash.hashblocksize: %.ext4 %.hash.salt
|
||||
veritysetup format --no-superblock --salt $(shell cat out/rootfs.hash.salt) $< $*.hash > $*.hash.info
|
||||
# Retrieve info required by dm-verity at boot time
|
||||
# Get the blocksize of rootfs
|
||||
cat $*.hash.info | awk '/^Root hash:/{ print $$3 }' > $*.hash.rootdigest
|
||||
cat $*.hash.info | awk '/^Salt:/{ print $$2 }' > $*.hash.salt
|
||||
cat $*.hash.info | awk '/^Data block size:/{ print $$4 }' > $*.hash.datablocksize
|
||||
cat $*.hash.info | awk '/^Hash block size:/{ print $$4 }' > $*.hash.hashblocksize
|
||||
cat $*.hash.info | awk '/^Data blocks:/{ print $$3 }' > $*.hash.datablocks
|
||||
echo $$(( $$(cat $*.hash.datablocks) * $$(cat $*.hash.datablocksize) / 512 )) > $*.hash.datasectors
|
||||
|
||||
out/rootfs.hash.salt:
|
||||
hexdump -vn32 -e'8/4 "%08X" 1 "\n"' /dev/random > $@
|
||||
|
||||
out/rootfs.ext4: out/rootfs.tar.gz bin/cmd/tar2ext4
|
||||
gzip -f -d ./out/rootfs.tar.gz
|
||||
./bin/cmd/tar2ext4 -i ./out/rootfs.tar -o $@
|
||||
|
||||
out/rootfs.tar.gz: out/initrd.img
|
||||
rm -rf rootfs-conv
|
||||
@@ -52,27 +120,60 @@ out/rootfs.tar.gz: out/initrd.img
|
||||
tar -zcf $@ -C rootfs-conv .
|
||||
rm -rf rootfs-conv
|
||||
|
||||
out/initrd.img: $(BASE) out/delta.tar.gz $(SRCROOT)/hack/catcpio.sh
|
||||
$(SRCROOT)/hack/catcpio.sh "$(BASE)" out/delta.tar.gz > out/initrd.img.uncompressed
|
||||
out/initrd.img: $(BASE) $(DELTA_TARGET) $(SRCROOT)/hack/catcpio.sh
|
||||
$(SRCROOT)/hack/catcpio.sh "$(BASE)" $(DELTA_TARGET) > out/initrd.img.uncompressed
|
||||
gzip -c out/initrd.img.uncompressed > $@
|
||||
rm out/initrd.img.uncompressed
|
||||
|
||||
-include deps/cmd/gcs.gomake
|
||||
-include deps/cmd/gcstools.gomake
|
||||
# This target includes utilities which may be useful for testing purposes.
|
||||
out/delta-dev.tar.gz: out/delta.tar.gz bin/internal/tools/snp-report
|
||||
rm -rf rootfs-dev
|
||||
mkdir rootfs-dev
|
||||
tar -xzf out/delta.tar.gz -C rootfs-dev
|
||||
cp bin/internal/tools/snp-report rootfs-dev/bin/
|
||||
tar -zcf $@ -C rootfs-dev .
|
||||
rm -rf rootfs-dev
|
||||
|
||||
# Implicit rule for includes that define Go targets.
|
||||
%.gomake: $(SRCROOT)/Makefile
|
||||
out/delta-snp.tar.gz: out/delta.tar.gz bin/internal/tools/snp-report boot/startup_v2056.sh boot/startup_simple.sh boot/startup.sh
|
||||
rm -rf rootfs-snp
|
||||
mkdir rootfs-snp
|
||||
tar -xzf out/delta.tar.gz -C rootfs-snp
|
||||
cp boot/startup_v2056.sh rootfs-snp/startup_v2056.sh
|
||||
cp boot/startup_simple.sh rootfs-snp/startup_simple.sh
|
||||
cp boot/startup.sh rootfs-snp/startup.sh
|
||||
cp bin/internal/tools/snp-report rootfs-snp/bin/
|
||||
chmod a+x rootfs-snp/startup_v2056.sh
|
||||
chmod a+x rootfs-snp/startup_simple.sh
|
||||
chmod a+x rootfs-snp/startup.sh
|
||||
tar -zcf $@ -C rootfs-snp .
|
||||
rm -rf rootfs-snp
|
||||
|
||||
out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools bin/cmd/hooks/wait-paths Makefile
|
||||
@mkdir -p out
|
||||
rm -rf rootfs
|
||||
mkdir -p rootfs/bin/
|
||||
mkdir -p rootfs/info/
|
||||
cp bin/init rootfs/
|
||||
cp bin/vsockexec rootfs/bin/
|
||||
cp bin/cmd/gcs rootfs/bin/
|
||||
cp bin/cmd/gcstools rootfs/bin/
|
||||
cp bin/cmd/hooks/wait-paths rootfs/bin/
|
||||
for tool in $(GCS_TOOLS); do ln -s gcstools rootfs/bin/$$tool; done
|
||||
git -C $(SRCROOT) rev-parse HEAD > rootfs/info/gcs.commit && \
|
||||
git -C $(SRCROOT) rev-parse --abbrev-ref HEAD > rootfs/info/gcs.branch && \
|
||||
date --iso-8601=minute --utc > rootfs/info/tar.date
|
||||
$(if $(and $(realpath $(subst .tar,.testdata.json,$(BASE))), $(shell which jq)), \
|
||||
jq -r '.IMAGE_NAME' $(subst .tar,.testdata.json,$(BASE)) 2>/dev/null > rootfs/info/image.name && \
|
||||
jq -r '.DATETIME' $(subst .tar,.testdata.json,$(BASE)) 2>/dev/null > rootfs/info/build.date)
|
||||
tar -zcf $@ -C rootfs .
|
||||
rm -rf rootfs
|
||||
|
||||
out/containerd-shim-runhcs-v1.exe:
|
||||
GOOS=windows $(GO_BUILD) -o $@ $(SRCROOT)/cmd/containerd-shim-runhcs-v1
|
||||
|
||||
bin/cmd/gcs bin/cmd/gcstools bin/cmd/hooks/wait-paths bin/cmd/tar2ext4 bin/internal/tools/snp-report bin/cmd/dmverity-vhd:
|
||||
@mkdir -p $(dir $@)
|
||||
@/bin/echo $(@:deps/%.gomake=bin/%): $(SRCROOT)/hack/gomakedeps.sh > $@.new
|
||||
@/bin/echo -e '\t@mkdir -p $$(dir $$@) $(dir $@)' >> $@.new
|
||||
@/bin/echo -e '\t$$(GO_BUILD) -o $$@.new $$(SRCROOT)/$$(@:bin/%=%)' >> $@.new
|
||||
@/bin/echo -e '\tGO="$(GO)" $$(SRCROOT)/hack/gomakedeps.sh $$@ $$(SRCROOT)/$$(@:bin/%=%) $$(GO_FLAGS) $$(GO_FLAGS_EXTRA) > $(@:%.gomake=%.godeps).new' >> $@.new
|
||||
@/bin/echo -e '\tmv $(@:%.gomake=%.godeps).new $(@:%.gomake=%.godeps)' >> $@.new
|
||||
@/bin/echo -e '\tmv $$@.new $$@' >> $@.new
|
||||
@/bin/echo -e '-include $(@:%.gomake=%.godeps)' >> $@.new
|
||||
mv $@.new $@
|
||||
|
||||
VPATH=$(SRCROOT)
|
||||
GOOS=linux $(GO_BUILD) -o $@ $(SRCROOT)/$(@:bin/%=%)
|
||||
|
||||
bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o
|
||||
@mkdir -p bin
|
||||
@@ -84,4 +185,4 @@ bin/init: init/init.o vsockexec/vsock.o
|
||||
|
||||
%.o: %.c
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
58
vendor/github.com/Microsoft/hcsshim/Protobuild.toml
generated
vendored
58
vendor/github.com/Microsoft/hcsshim/Protobuild.toml
generated
vendored
@@ -1,49 +1,25 @@
|
||||
version = "unstable"
|
||||
generator = "gogoctrd"
|
||||
plugins = ["grpc", "fieldpath"]
|
||||
version = "2"
|
||||
generators = ["go", "go-grpc"]
|
||||
|
||||
# Control protoc include paths. Below are usually some good defaults, but feel
|
||||
# free to try it without them if it works for your project.
|
||||
# Control protoc include paths.
|
||||
[includes]
|
||||
# Include paths that will be added before all others. Typically, you want to
|
||||
# treat the root of the project as an include, but this may not be necessary.
|
||||
before = ["./protobuf"]
|
||||
|
||||
# Paths that should be treated as include roots in relation to the vendor
|
||||
# directory. These will be calculated with the vendor directory nearest the
|
||||
# target package.
|
||||
packages = ["github.com/gogo/protobuf"]
|
||||
# defaults are "/usr/local/include" and "/usr/include", which don't exist on Windows.
|
||||
# override defaults to supress errors about non-existant directories.
|
||||
after = []
|
||||
|
||||
# Paths that will be added untouched to the end of the includes. We use
|
||||
# `/usr/local/include` to pickup the common install location of protobuf.
|
||||
# This is the default.
|
||||
after = ["/usr/local/include"]
|
||||
|
||||
# This section maps protobuf imports to Go packages. These will become
|
||||
# `-M` directives in the call to the go protobuf generator.
|
||||
# This section maps protobuf imports to Go packages.
|
||||
[packages]
|
||||
"gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto"
|
||||
"google/protobuf/any.proto" = "github.com/gogo/protobuf/types"
|
||||
"google/protobuf/empty.proto" = "github.com/gogo/protobuf/types"
|
||||
"google/protobuf/struct.proto" = "github.com/gogo/protobuf/types"
|
||||
"google/protobuf/descriptor.proto" = "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
|
||||
"google/protobuf/field_mask.proto" = "github.com/gogo/protobuf/types"
|
||||
"google/protobuf/timestamp.proto" = "github.com/gogo/protobuf/types"
|
||||
"google/protobuf/duration.proto" = "github.com/gogo/protobuf/types"
|
||||
"github/containerd/cgroups/stats/v1/metrics.proto" = "github.com/containerd/cgroups/stats/v1"
|
||||
# github.com/containerd/cgroups protofiles still list their go path as "github.com/containerd/cgroups/cgroup1/stats"
|
||||
"github.com/containerd/cgroups/v3/cgroup1/stats/metrics.proto" = "github.com/containerd/cgroups/v3/cgroup1/stats"
|
||||
|
||||
[[overrides]]
|
||||
prefixes = ["github.com/Microsoft/hcsshim/internal/shimdiag"]
|
||||
plugins = ["ttrpc"]
|
||||
|
||||
[[overrides]]
|
||||
prefixes = ["github.com/Microsoft/hcsshim/internal/computeagent"]
|
||||
plugins = ["ttrpc"]
|
||||
|
||||
[[overrides]]
|
||||
prefixes = ["github.com/Microsoft/hcsshim/internal/ncproxyttrpc"]
|
||||
plugins = ["ttrpc"]
|
||||
|
||||
[[overrides]]
|
||||
prefixes = ["github.com/Microsoft/hcsshim/internal/vmservice"]
|
||||
plugins = ["ttrpc"]
|
||||
prefixes = [
|
||||
"github.com/Microsoft/hcsshim/internal/shimdiag",
|
||||
"github.com/Microsoft/hcsshim/internal/extendedtask",
|
||||
"github.com/Microsoft/hcsshim/internal/computeagent",
|
||||
"github.com/Microsoft/hcsshim/internal/ncproxyttrpc",
|
||||
"github.com/Microsoft/hcsshim/internal/vmservice",
|
||||
]
|
||||
generators = ["go", "go-ttrpc"]
|
||||
|
||||
90
vendor/github.com/Microsoft/hcsshim/README.md
generated
vendored
90
vendor/github.com/Microsoft/hcsshim/README.md
generated
vendored
@@ -9,15 +9,18 @@ It is primarily used in the [Moby](https://github.com/moby/moby) and [Containerd
|
||||
## Building
|
||||
|
||||
While this repository can be used as a library of sorts to call the HCS apis, there are a couple binaries built out of the repository as well. The main ones being the Linux guest agent, and an implementation of the [runtime v2 containerd shim api](https://github.com/containerd/containerd/blob/master/runtime/v2/README.md).
|
||||
|
||||
### Linux Hyper-V Container Guest Agent
|
||||
|
||||
To build the Linux guest agent itself all that's needed is to set your GOOS to "Linux" and build out of ./cmd/gcs.
|
||||
|
||||
```powershell
|
||||
C:\> $env:GOOS="linux"
|
||||
C:\> go build .\cmd\gcs\
|
||||
```
|
||||
|
||||
or on a Linux machine
|
||||
|
||||
```sh
|
||||
> go build ./cmd/gcs
|
||||
```
|
||||
@@ -33,13 +36,15 @@ make all
|
||||
```
|
||||
|
||||
If the build is successful, in the `./out` folder you should see:
|
||||
|
||||
```sh
|
||||
> ls ./out/
|
||||
delta.tar.gz initrd.img rootfs.tar.gz
|
||||
```
|
||||
|
||||
### Containerd Shim
|
||||
For info on the Runtime V2 API: https://github.com/containerd/containerd/blob/master/runtime/v2/README.md.
|
||||
|
||||
For info on the [Runtime V2 API](https://github.com/containerd/containerd/blob/master/runtime/v2/README.md).
|
||||
|
||||
Contrary to the typical Linux architecture of shim -> runc, the runhcs shim is used both to launch and manage the lifetime of containers.
|
||||
|
||||
@@ -48,7 +53,9 @@ C:\> $env:GOOS="windows"
|
||||
C:\> go build .\cmd\containerd-shim-runhcs-v1
|
||||
```
|
||||
|
||||
Then place the binary in the same directory that Containerd is located at in your environment. A default Containerd configuration file can be generated by running:
|
||||
Then place the binary in the same directory that Containerd is located at in your environment.
|
||||
A default Containerd configuration file can be generated by running:
|
||||
|
||||
```powershell
|
||||
.\containerd.exe config default | Out-File "C:\Program Files\containerd\config.toml" -Encoding ascii
|
||||
```
|
||||
@@ -56,6 +63,7 @@ Then place the binary in the same directory that Containerd is located at in you
|
||||
This config file will already have the shim set as the default runtime for cri interactions.
|
||||
|
||||
To trial using the shim out with ctr.exe:
|
||||
|
||||
```powershell
|
||||
C:\> ctr.exe run --runtime io.containerd.runhcs.v1 --rm mcr.microsoft.com/windows/nanoserver:2004 windows-test cmd /c "echo Hello World!"
|
||||
```
|
||||
@@ -64,34 +72,69 @@ C:\> ctr.exe run --runtime io.containerd.runhcs.v1 --rm mcr.microsoft.com/window
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
||||
the rights to use your contribution. For details, visit [Microsoft CLA](https://cla.microsoft.com).
|
||||
|
||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
We also require that contributors [sign their commits](https://git-scm.com/docs/git-commit) using `git commit -s` or `git commit --signoff` to
|
||||
certify they either authored the work themselves or otherwise have permission to use it in this project. Please see https://developercertificate.org/ for
|
||||
more info, as well as to make sure that you can attest to the rules listed. Our CI uses the [DCO Github app](https://github.com/apps/dco) to ensure
|
||||
that all commits in a given PR are signed-off.
|
||||
We require that contributors sign their commits
|
||||
to certify they either authored the work themselves or otherwise have permission to use it in this project.
|
||||
|
||||
### Test Directory (Important to note)
|
||||
We also require that contributors sign their commits using using [`git commit --signoff`][git-commit-s]
|
||||
to certify they either authored the work themselves or otherwise have permission to use it in this project.
|
||||
A range of commits can be signed off using [`git rebase --signoff`][git-rebase-s].
|
||||
|
||||
This project has tried to trim some dependencies from the root Go modules file that would be cumbersome to get transitively included if this
|
||||
project is being vendored/used as a library. Some of these dependencies were only being used for tests, so the /test directory in this project also has
|
||||
its own go.mod file where these are now included to get around this issue. Our tests rely on the code in this project to run, so the test Go modules file
|
||||
has a relative path replace directive to pull in the latest hcsshim code that the tests actually touch from this project
|
||||
(which is the repo itself on your disk).
|
||||
Please see [the developer certificate](https://developercertificate.org) for more info,
|
||||
as well as to make sure that you can attest to the rules listed.
|
||||
Our CI uses the [DCO Github app](https://github.com/apps/dco) to ensure that all commits in a given PR are signed-off.
|
||||
|
||||
```
|
||||
replace (
|
||||
github.com/Microsoft/hcsshim => ../
|
||||
)
|
||||
### Linting
|
||||
|
||||
Code must pass a linting stage, which uses [`golangci-lint`][lint].
|
||||
Since `./test` is a separate Go module, the linter is run from both the root and the
|
||||
`test` directories. Additionally, the linter is run with `GOOS` set to both `windows` and
|
||||
`linux`.
|
||||
|
||||
The linting settings are stored in [`.golangci.yaml`](./.golangci.yaml), and can be run
|
||||
automatically with VSCode by adding the following to your workspace or folder settings:
|
||||
|
||||
```json
|
||||
"go.lintTool": "golangci-lint",
|
||||
"go.lintOnSave": "package",
|
||||
```
|
||||
|
||||
Because of this, for most code changes you may need to run `go mod vendor` + `go mod tidy` in the /test directory in this repository, as the
|
||||
CI in this project will check if the files are out of date and will fail if this is true.
|
||||
Additional editor [integrations options are also available][lint-ide].
|
||||
|
||||
Alternatively, `golangci-lint` can be [installed][lint-install] and run locally:
|
||||
|
||||
```shell
|
||||
# use . or specify a path to only lint a package
|
||||
# to show all lint errors, use flags "--max-issues-per-linter=0 --max-same-issues=0"
|
||||
> golangci-lint run
|
||||
```
|
||||
|
||||
To run across the entire repo for both `GOOS=windows` and `linux`:
|
||||
|
||||
```powershell
|
||||
> foreach ( $goos in ('windows', 'linux') ) {
|
||||
foreach ( $repo in ('.', 'test') ) {
|
||||
pwsh -Command "cd $repo && go env -w GOOS=$goos && golangci-lint.exe run --verbose"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Go Generate
|
||||
|
||||
The pipeline checks that auto-generated code, via `go generate`, are up to date.
|
||||
Similar to the [linting stage](#linting), `go generate` is run in both the root and test Go modules.
|
||||
|
||||
This can be done via:
|
||||
|
||||
```shell
|
||||
> go generate ./...
|
||||
> cd test && go generate ./...
|
||||
```
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
@@ -101,7 +144,7 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio
|
||||
|
||||
## Dependencies
|
||||
|
||||
This project requires Golang 1.9 or newer to build.
|
||||
This project requires Golang 1.18 or newer to build.
|
||||
|
||||
For system requirements to run this project, see the Microsoft docs on [Windows Container requirements](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/system-requirements).
|
||||
|
||||
@@ -118,3 +161,10 @@ For additional details, see [Report a Computer Security Vulnerability](https://t
|
||||
|
||||
---------------
|
||||
Copyright (c) 2018 Microsoft Corp. All rights reserved.
|
||||
|
||||
[lint]: https://golangci-lint.run/
|
||||
[lint-ide]: https://golangci-lint.run/usage/integrations/#editor-integration
|
||||
[lint-install]: https://golangci-lint.run/usage/install/#local-installation
|
||||
|
||||
[git-commit-s]: https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s
|
||||
[git-rebase-s]: https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---signoff
|
||||
|
||||
41
vendor/github.com/Microsoft/hcsshim/SECURITY.md
generated
vendored
Normal file
41
vendor/github.com/Microsoft/hcsshim/SECURITY.md
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
||||
34
vendor/github.com/Microsoft/hcsshim/computestorage/attach.go
generated
vendored
34
vendor/github.com/Microsoft/hcsshim/computestorage/attach.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -17,8 +19,8 @@ import (
|
||||
//
|
||||
// `layerData` is the parent read-only layer data.
|
||||
func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) {
|
||||
title := "hcsshim.AttachLayerStorageFilter"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::AttachLayerStorageFilter"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(
|
||||
@@ -36,3 +38,31 @@ func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData L
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AttachOverlayFilter sets up a filter of the given type on a writable container layer. Currently the only
|
||||
// supported filter types are WCIFS & UnionFS (defined in internal/hcs/schema2/layer.go)
|
||||
//
|
||||
// `volumePath` is volume path at which writable layer is mounted. If the
|
||||
// path does not end in a `\` the platform will append it automatically.
|
||||
//
|
||||
// `layerData` is the parent read-only layer data.
|
||||
func AttachOverlayFilter(ctx context.Context, volumePath string, layerData LayerData) (err error) {
|
||||
title := "hcsshim::AttachOverlayFilter"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(
|
||||
trace.StringAttribute("volumePath", volumePath),
|
||||
)
|
||||
|
||||
bytes, err := json.Marshal(layerData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = hcsAttachOverlayFilter(volumePath, string(bytes))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to attach overlay filter")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
6
vendor/github.com/Microsoft/hcsshim/computestorage/destroy.go
generated
vendored
6
vendor/github.com/Microsoft/hcsshim/computestorage/destroy.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -12,8 +14,8 @@ import (
|
||||
//
|
||||
// `layerPath` is a path to a directory containing the layer to export.
|
||||
func DestroyLayer(ctx context.Context, layerPath string) (err error) {
|
||||
title := "hcsshim.DestroyLayer"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::DestroyLayer"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
|
||||
|
||||
32
vendor/github.com/Microsoft/hcsshim/computestorage/detach.go
generated
vendored
32
vendor/github.com/Microsoft/hcsshim/computestorage/detach.go
generated
vendored
@@ -1,8 +1,12 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
|
||||
"github.com/Microsoft/hcsshim/internal/oc"
|
||||
"github.com/pkg/errors"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -12,8 +16,8 @@ import (
|
||||
//
|
||||
// `layerPath` is a path to a directory containing the layer to export.
|
||||
func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) {
|
||||
title := "hcsshim.DetachLayerStorageFilter"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::DetachLayerStorageFilter"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
|
||||
@@ -24,3 +28,27 @@ func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DetachOverlayFilter detaches the filter on a writable container layer.
|
||||
//
|
||||
// `volumePath` is a path to writable container volume.
|
||||
func DetachOverlayFilter(ctx context.Context, volumePath string, filterType hcsschema.FileSystemFilterType) (err error) {
|
||||
title := "hcsshim::DetachOverlayFilter"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(trace.StringAttribute("volumePath", volumePath))
|
||||
|
||||
layerData := LayerData{}
|
||||
layerData.FilterType = filterType
|
||||
bytes, err := json.Marshal(layerData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = hcsDetachOverlayFilter(volumePath, string(bytes))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to detach overlay filter")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
12
vendor/github.com/Microsoft/hcsshim/computestorage/export.go
generated
vendored
12
vendor/github.com/Microsoft/hcsshim/computestorage/export.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -19,8 +21,8 @@ import (
|
||||
//
|
||||
// `options` are the export options applied to the exported layer.
|
||||
func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) {
|
||||
title := "hcsshim.ExportLayer"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::ExportLayer"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(
|
||||
@@ -28,17 +30,17 @@ func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerD
|
||||
trace.StringAttribute("exportFolderPath", exportFolderPath),
|
||||
)
|
||||
|
||||
ldbytes, err := json.Marshal(layerData)
|
||||
ldBytes, err := json.Marshal(layerData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
obytes, err := json.Marshal(options)
|
||||
oBytes, err := json.Marshal(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = hcsExportLayer(layerPath, exportFolderPath, string(ldbytes), string(obytes))
|
||||
err = hcsExportLayer(layerPath, exportFolderPath, string(ldBytes), string(oBytes))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to export layer")
|
||||
}
|
||||
|
||||
12
vendor/github.com/Microsoft/hcsshim/computestorage/format.go
generated
vendored
12
vendor/github.com/Microsoft/hcsshim/computestorage/format.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -5,16 +7,20 @@ import (
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/oc"
|
||||
"github.com/pkg/errors"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// FormatWritableLayerVhd formats a virtual disk for use as a writable container layer.
|
||||
//
|
||||
// If the VHD is not mounted it will be temporarily mounted.
|
||||
//
|
||||
// NOTE: This API had a breaking change in the operating system after Windows Server 2019.
|
||||
// On ws2019 the API expects to get passed a file handle from CreateFile for the vhd that
|
||||
// the caller wants to format. On > ws2019, its expected that the caller passes a vhd handle
|
||||
// that can be obtained from the virtdisk APIs.
|
||||
func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) {
|
||||
title := "hcsshim.FormatWritableLayerVhd"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::FormatWritableLayerVhd"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
|
||||
|
||||
18
vendor/github.com/Microsoft/hcsshim/computestorage/helpers.go
generated
vendored
18
vendor/github.com/Microsoft/hcsshim/computestorage/helpers.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -6,13 +8,17 @@ import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/Microsoft/go-winio/pkg/security"
|
||||
"github.com/Microsoft/go-winio/vhd"
|
||||
"github.com/Microsoft/hcsshim/internal/memory"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/security"
|
||||
)
|
||||
|
||||
const defaultVHDXBlockSizeInMB = 1
|
||||
const (
|
||||
defaultVHDXBlockSizeInMB = 1
|
||||
)
|
||||
|
||||
// SetupContainerBaseLayer is a helper to setup a containers scratch. It
|
||||
// will create and format the vhdx's inside and the size is configurable with the sizeInGB
|
||||
@@ -59,8 +65,8 @@ func SetupContainerBaseLayer(ctx context.Context, layerPath, baseVhdPath, diffVh
|
||||
createParams := &vhd.CreateVirtualDiskParameters{
|
||||
Version: 2,
|
||||
Version2: vhd.CreateVersion2{
|
||||
MaximumSize: sizeInGB * 1024 * 1024 * 1024,
|
||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
|
||||
MaximumSize: sizeInGB * memory.GiB,
|
||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
|
||||
},
|
||||
}
|
||||
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
|
||||
@@ -135,8 +141,8 @@ func SetupUtilityVMBaseLayer(ctx context.Context, uvmPath, baseVhdPath, diffVhdP
|
||||
createParams := &vhd.CreateVirtualDiskParameters{
|
||||
Version: 2,
|
||||
Version2: vhd.CreateVersion2{
|
||||
MaximumSize: sizeInGB * 1024 * 1024 * 1024,
|
||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024,
|
||||
MaximumSize: sizeInGB * memory.GiB,
|
||||
BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
|
||||
},
|
||||
}
|
||||
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
|
||||
|
||||
6
vendor/github.com/Microsoft/hcsshim/computestorage/import.go
generated
vendored
6
vendor/github.com/Microsoft/hcsshim/computestorage/import.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -19,8 +21,8 @@ import (
|
||||
//
|
||||
// `layerData` is the parent layer data.
|
||||
func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) {
|
||||
title := "hcsshim.ImportLayer"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::ImportLayer"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(
|
||||
|
||||
6
vendor/github.com/Microsoft/hcsshim/computestorage/initialize.go
generated
vendored
6
vendor/github.com/Microsoft/hcsshim/computestorage/initialize.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -16,8 +18,8 @@ import (
|
||||
//
|
||||
// `layerData` is the parent read-only layer data.
|
||||
func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) {
|
||||
title := "hcsshim.InitializeWritableLayer"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::InitializeWritableLayer"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(
|
||||
|
||||
7
vendor/github.com/Microsoft/hcsshim/computestorage/mount.go
generated
vendored
7
vendor/github.com/Microsoft/hcsshim/computestorage/mount.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -6,14 +8,13 @@ import (
|
||||
"github.com/Microsoft/hcsshim/internal/interop"
|
||||
"github.com/Microsoft/hcsshim/internal/oc"
|
||||
"github.com/pkg/errors"
|
||||
"go.opencensus.io/trace"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// GetLayerVhdMountPath returns the volume path for a virtual disk of a writable container layer.
|
||||
func GetLayerVhdMountPath(ctx context.Context, vhdHandle windows.Handle) (path string, err error) {
|
||||
title := "hcsshim.GetLayerVhdMountPath"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::GetLayerVhdMountPath"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
|
||||
|
||||
14
vendor/github.com/Microsoft/hcsshim/computestorage/setup.go
generated
vendored
14
vendor/github.com/Microsoft/hcsshim/computestorage/setup.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package computestorage
|
||||
|
||||
import (
|
||||
@@ -21,8 +23,8 @@ import (
|
||||
//
|
||||
// `options` are the options applied while processing the layer.
|
||||
func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) {
|
||||
title := "hcsshim.SetupBaseOSLayer"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::SetupBaseOSLayer"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(
|
||||
@@ -48,12 +50,16 @@ func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.H
|
||||
// `volumePath` is the path to the volume to be used for setup.
|
||||
//
|
||||
// `options` are the options applied while processing the layer.
|
||||
//
|
||||
// NOTE: This API is only available on builds of Windows greater than 19645. Inside we
|
||||
// check if the hosts build has the API available by using 'GetVersion' which requires
|
||||
// the calling application to be manifested. https://docs.microsoft.com/en-us/windows/win32/sbscs/manifests
|
||||
func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) {
|
||||
if osversion.Build() < 19645 {
|
||||
return errors.New("SetupBaseOSVolume is not present on builds older than 19645")
|
||||
}
|
||||
title := "hcsshim.SetupBaseOSVolume"
|
||||
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
title := "hcsshim::SetupBaseOSVolume"
|
||||
ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
|
||||
defer span.End()
|
||||
defer func() { oc.SetSpanStatus(span, err) }()
|
||||
span.AddAttributes(
|
||||
|
||||
14
vendor/github.com/Microsoft/hcsshim/computestorage/storage.go
generated
vendored
14
vendor/github.com/Microsoft/hcsshim/computestorage/storage.go
generated
vendored
@@ -7,11 +7,11 @@ import (
|
||||
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
|
||||
)
|
||||
|
||||
//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go storage.go
|
||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go storage.go
|
||||
|
||||
//sys hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) = computestorage.HcsImportLayer?
|
||||
//sys hcsExportLayer(layerPath string, exportFolderPath string, layerData string, options string) (hr error) = computestorage.HcsExportLayer?
|
||||
//sys hcsDestroyLayer(layerPath string) (hr error) = computestorage.HcsDestoryLayer?
|
||||
//sys hcsDestroyLayer(layerPath string) (hr error) = computestorage.HcsDestroyLayer?
|
||||
//sys hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) = computestorage.HcsSetupBaseOSLayer?
|
||||
//sys hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) = computestorage.HcsInitializeWritableLayer?
|
||||
//sys hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) = computestorage.HcsAttachLayerStorageFilter?
|
||||
@@ -19,11 +19,17 @@ import (
|
||||
//sys hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) = computestorage.HcsFormatWritableLayerVhd?
|
||||
//sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath?
|
||||
//sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume?
|
||||
//sys hcsAttachOverlayFilter(volumePath string, layerData string) (hr error) = computestorage.HcsAttachOverlayFilter?
|
||||
//sys hcsDetachOverlayFilter(volumePath string, layerData string) (hr error) = computestorage.HcsDetachOverlayFilter?
|
||||
|
||||
type Version = hcsschema.Version
|
||||
type Layer = hcsschema.Layer
|
||||
|
||||
// LayerData is the data used to describe parent layer information.
|
||||
type LayerData struct {
|
||||
SchemaVersion hcsschema.Version `json:"SchemaVersion,omitempty"`
|
||||
Layers []hcsschema.Layer `json:"Layers,omitempty"`
|
||||
SchemaVersion Version `json:"SchemaVersion,omitempty"`
|
||||
Layers []Layer `json:"Layers,omitempty"`
|
||||
FilterType hcsschema.FileSystemFilterType `json:"FilterType,omitempty"`
|
||||
}
|
||||
|
||||
// ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall.
|
||||
|
||||
296
vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go
generated
vendored
296
vendor/github.com/Microsoft/hcsshim/computestorage/zsyscall_windows.go
generated
vendored
@@ -1,4 +1,6 @@
|
||||
// Code generated mksyscall_windows.exe DO NOT EDIT
|
||||
//go:build windows
|
||||
|
||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
|
||||
|
||||
package computestorage
|
||||
|
||||
@@ -19,6 +21,7 @@ const (
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
errERROR_EINVAL error = syscall.EINVAL
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
@@ -26,55 +29,156 @@ var (
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
return errERROR_EINVAL
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modcomputestorage = windows.NewLazySystemDLL("computestorage.dll")
|
||||
|
||||
procHcsImportLayer = modcomputestorage.NewProc("HcsImportLayer")
|
||||
procHcsExportLayer = modcomputestorage.NewProc("HcsExportLayer")
|
||||
procHcsDestoryLayer = modcomputestorage.NewProc("HcsDestoryLayer")
|
||||
procHcsSetupBaseOSLayer = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
|
||||
procHcsInitializeWritableLayer = modcomputestorage.NewProc("HcsInitializeWritableLayer")
|
||||
procHcsAttachLayerStorageFilter = modcomputestorage.NewProc("HcsAttachLayerStorageFilter")
|
||||
procHcsAttachOverlayFilter = modcomputestorage.NewProc("HcsAttachOverlayFilter")
|
||||
procHcsDestroyLayer = modcomputestorage.NewProc("HcsDestroyLayer")
|
||||
procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter")
|
||||
procHcsDetachOverlayFilter = modcomputestorage.NewProc("HcsDetachOverlayFilter")
|
||||
procHcsExportLayer = modcomputestorage.NewProc("HcsExportLayer")
|
||||
procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
|
||||
procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath")
|
||||
procHcsImportLayer = modcomputestorage.NewProc("HcsImportLayer")
|
||||
procHcsInitializeWritableLayer = modcomputestorage.NewProc("HcsInitializeWritableLayer")
|
||||
procHcsSetupBaseOSLayer = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
|
||||
procHcsSetupBaseOSVolume = modcomputestorage.NewProc("HcsSetupBaseOSVolume")
|
||||
)
|
||||
|
||||
func hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) {
|
||||
func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *uint16
|
||||
_p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
|
||||
_p1, hr = syscall.UTF16PtrFromString(layerData)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
var _p2 *uint16
|
||||
_p2, hr = syscall.UTF16PtrFromString(layerData)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsImportLayer(_p0, _p1, _p2)
|
||||
return _hcsAttachLayerStorageFilter(_p0, _p1)
|
||||
}
|
||||
|
||||
func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) {
|
||||
if hr = procHcsImportLayer.Find(); hr != nil {
|
||||
func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
|
||||
hr = procHcsAttachLayerStorageFilter.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
|
||||
r0, _, _ := syscall.SyscallN(procHcsAttachLayerStorageFilter.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsAttachOverlayFilter(volumePath string, layerData string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(volumePath)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *uint16
|
||||
_p1, hr = syscall.UTF16PtrFromString(layerData)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsAttachOverlayFilter(_p0, _p1)
|
||||
}
|
||||
|
||||
func _hcsAttachOverlayFilter(volumePath *uint16, layerData *uint16) (hr error) {
|
||||
hr = procHcsAttachOverlayFilter.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procHcsAttachOverlayFilter.Addr(), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(layerData)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsDestroyLayer(layerPath string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsDestroyLayer(_p0)
|
||||
}
|
||||
|
||||
func _hcsDestroyLayer(layerPath *uint16) (hr error) {
|
||||
hr = procHcsDestroyLayer.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procHcsDestroyLayer.Addr(), uintptr(unsafe.Pointer(layerPath)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsDetachLayerStorageFilter(layerPath string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsDetachLayerStorageFilter(_p0)
|
||||
}
|
||||
|
||||
func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
|
||||
hr = procHcsDetachLayerStorageFilter.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procHcsDetachLayerStorageFilter.Addr(), uintptr(unsafe.Pointer(layerPath)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsDetachOverlayFilter(volumePath string, layerData string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(volumePath)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *uint16
|
||||
_p1, hr = syscall.UTF16PtrFromString(layerData)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsDetachOverlayFilter(_p0, _p1)
|
||||
}
|
||||
|
||||
func _hcsDetachOverlayFilter(volumePath *uint16, layerData *uint16) (hr error) {
|
||||
hr = procHcsDetachOverlayFilter.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procHcsDetachOverlayFilter.Addr(), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(layerData)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
@@ -109,33 +213,11 @@ func hcsExportLayer(layerPath string, exportFolderPath string, layerData string,
|
||||
}
|
||||
|
||||
func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) {
|
||||
if hr = procHcsExportLayer.Find(); hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall6(procHcsExportLayer.Addr(), 4, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)), 0, 0)
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsDestroyLayer(layerPath string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
||||
hr = procHcsExportLayer.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsDestroyLayer(_p0)
|
||||
}
|
||||
|
||||
func _hcsDestroyLayer(layerPath *uint16) (hr error) {
|
||||
if hr = procHcsDestoryLayer.Find(); hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsDestoryLayer.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
|
||||
r0, _, _ := syscall.SyscallN(procHcsExportLayer.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
@@ -145,25 +227,61 @@ func _hcsDestroyLayer(layerPath *uint16) (hr error) {
|
||||
return
|
||||
}
|
||||
|
||||
func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
|
||||
func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
|
||||
hr = procHcsFormatWritableLayerVhd.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procHcsFormatWritableLayerVhd.Addr(), uintptr(handle))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
|
||||
hr = procHcsGetLayerVhdMountPath.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procHcsGetLayerVhdMountPath.Addr(), uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsImportLayer(layerPath string, sourceFolderPath string, layerData string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *uint16
|
||||
_p1, hr = syscall.UTF16PtrFromString(options)
|
||||
_p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsSetupBaseOSLayer(_p0, handle, _p1)
|
||||
}
|
||||
|
||||
func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
|
||||
if hr = procHcsSetupBaseOSLayer.Find(); hr != nil {
|
||||
var _p2 *uint16
|
||||
_p2, hr = syscall.UTF16PtrFromString(layerData)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
|
||||
return _hcsImportLayer(_p0, _p1, _p2)
|
||||
}
|
||||
|
||||
func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) {
|
||||
hr = procHcsImportLayer.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.SyscallN(procHcsImportLayer.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
@@ -193,10 +311,11 @@ func hcsInitializeWritableLayer(writableLayerPath string, layerData string, opti
|
||||
}
|
||||
|
||||
func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) {
|
||||
if hr = procHcsInitializeWritableLayer.Find(); hr != nil {
|
||||
hr = procHcsInitializeWritableLayer.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
|
||||
r0, _, _ := syscall.SyscallN(procHcsInitializeWritableLayer.Addr(), uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
@@ -206,76 +325,26 @@ func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, o
|
||||
return
|
||||
}
|
||||
|
||||
func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) {
|
||||
func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
var _p1 *uint16
|
||||
_p1, hr = syscall.UTF16PtrFromString(layerData)
|
||||
_p1, hr = syscall.UTF16PtrFromString(options)
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsAttachLayerStorageFilter(_p0, _p1)
|
||||
return _hcsSetupBaseOSLayer(_p0, handle, _p1)
|
||||
}
|
||||
|
||||
func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
|
||||
if hr = procHcsAttachLayerStorageFilter.Find(); hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsAttachLayerStorageFilter.Addr(), 2, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(layerData)), 0)
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsDetachLayerStorageFilter(layerPath string) (hr error) {
|
||||
var _p0 *uint16
|
||||
_p0, hr = syscall.UTF16PtrFromString(layerPath)
|
||||
func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
|
||||
hr = procHcsSetupBaseOSLayer.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
return _hcsDetachLayerStorageFilter(_p0)
|
||||
}
|
||||
|
||||
func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
|
||||
if hr = procHcsDetachLayerStorageFilter.Find(); hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsDetachLayerStorageFilter.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 0)
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
|
||||
if hr = procHcsFormatWritableLayerVhd.Find(); hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
}
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
|
||||
if hr = procHcsGetLayerVhdMountPath.Find(); hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsGetLayerVhdMountPath.Addr(), 2, uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)), 0)
|
||||
r0, _, _ := syscall.SyscallN(procHcsSetupBaseOSLayer.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
@@ -305,10 +374,11 @@ func hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (
|
||||
}
|
||||
|
||||
func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) {
|
||||
if hr = procHcsSetupBaseOSVolume.Find(); hr != nil {
|
||||
hr = procHcsSetupBaseOSVolume.Find()
|
||||
if hr != nil {
|
||||
return
|
||||
}
|
||||
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))
|
||||
r0, _, _ := syscall.SyscallN(procHcsSetupBaseOSVolume.Addr(), uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))
|
||||
if int32(r0) < 0 {
|
||||
if r0&0x1fff0000 == 0x00070000 {
|
||||
r0 &= 0xffff
|
||||
|
||||
6
vendor/github.com/Microsoft/hcsshim/container.go
generated
vendored
6
vendor/github.com/Microsoft/hcsshim/container.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package hcsshim
|
||||
|
||||
import (
|
||||
@@ -60,7 +62,7 @@ type container struct {
|
||||
waitCh chan struct{}
|
||||
}
|
||||
|
||||
// createComputeSystemAdditionalJSON is read from the environment at initialisation
|
||||
// createContainerAdditionalJSON is read from the environment at initialization
|
||||
// time. It allows an environment variable to define additional JSON which
|
||||
// is merged in the CreateComputeSystem call to HCS.
|
||||
var createContainerAdditionalJSON []byte
|
||||
@@ -73,7 +75,7 @@ func init() {
|
||||
func CreateContainer(id string, c *ContainerConfig) (Container, error) {
|
||||
fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err)
|
||||
return nil, fmt.Errorf("failed to merge additional JSON '%s': %w", createContainerAdditionalJSON, err)
|
||||
}
|
||||
|
||||
system, err := hcs.CreateComputeSystem(context.Background(), id, fullConfig)
|
||||
|
||||
16
vendor/github.com/Microsoft/hcsshim/errors.go
generated
vendored
16
vendor/github.com/Microsoft/hcsshim/errors.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package hcsshim
|
||||
|
||||
import (
|
||||
@@ -50,6 +52,9 @@ var (
|
||||
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
||||
ErrUnexpectedValue = hcs.ErrUnexpectedValue
|
||||
|
||||
// ErrOperationDenied is an error when hcs attempts an operation that is explicitly denied
|
||||
ErrOperationDenied = hcs.ErrOperationDenied
|
||||
|
||||
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
||||
ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped
|
||||
|
||||
@@ -110,6 +115,7 @@ func (e *ContainerError) Error() string {
|
||||
s += " encountered an error during " + e.Operation
|
||||
}
|
||||
|
||||
//nolint:errorlint // legacy code
|
||||
switch e.Err.(type) {
|
||||
case nil:
|
||||
break
|
||||
@@ -140,6 +146,7 @@ func (e *ProcessError) Error() string {
|
||||
s += " encountered an error during " + e.Operation
|
||||
}
|
||||
|
||||
//nolint:errorlint // legacy code
|
||||
switch e.Err.(type) {
|
||||
case nil:
|
||||
break
|
||||
@@ -161,10 +168,10 @@ func (e *ProcessError) Error() string {
|
||||
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||
// will currently return true when the error is ErrElementNotFound.
|
||||
func IsNotExist(err error) bool {
|
||||
if _, ok := err.(EndpointNotFoundError); ok {
|
||||
if _, ok := err.(EndpointNotFoundError); ok { //nolint:errorlint // legacy code
|
||||
return true
|
||||
}
|
||||
if _, ok := err.(NetworkNotFoundError); ok {
|
||||
if _, ok := err.(NetworkNotFoundError); ok { //nolint:errorlint // legacy code
|
||||
return true
|
||||
}
|
||||
return hcs.IsNotExist(getInnerError(err))
|
||||
@@ -219,6 +226,7 @@ func IsAccessIsDenied(err error) bool {
|
||||
}
|
||||
|
||||
func getInnerError(err error) error {
|
||||
//nolint:errorlint // legacy code
|
||||
switch pe := err.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
@@ -231,14 +239,14 @@ func getInnerError(err error) error {
|
||||
}
|
||||
|
||||
func convertSystemError(err error, c *container) error {
|
||||
if serr, ok := err.(*hcs.SystemError); ok {
|
||||
if serr, ok := err.(*hcs.SystemError); ok { //nolint:errorlint // legacy code
|
||||
return &ContainerError{Container: c, Operation: serr.Op, Err: serr.Err, Events: serr.Events}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func convertProcessError(err error, p *process) error {
|
||||
if perr, ok := err.(*hcs.ProcessError); ok {
|
||||
if perr, ok := err.(*hcs.ProcessError); ok { //nolint:errorlint // legacy code
|
||||
return &ProcessError{Process: p, Operation: perr.Op, Err: perr.Err, Events: perr.Events}
|
||||
}
|
||||
return err
|
||||
|
||||
12
vendor/github.com/Microsoft/hcsshim/functional_tests.ps1
generated
vendored
12
vendor/github.com/Microsoft/hcsshim/functional_tests.ps1
generated
vendored
@@ -1,12 +0,0 @@
|
||||
# Requirements so far:
|
||||
# dockerd running
|
||||
# - image microsoft/nanoserver (matching host base image) docker load -i c:\baseimages\nanoserver.tar
|
||||
# - image alpine (linux) docker pull --platform=linux alpine
|
||||
|
||||
|
||||
# TODO: Add this a parameter for debugging. ie "functional-tests -debug=$true"
|
||||
#$env:HCSSHIM_FUNCTIONAL_TESTS_DEBUG="yes please"
|
||||
|
||||
#pushd uvm
|
||||
go test -v -tags "functional uvmcreate uvmscratch uvmscsi uvmvpmem uvmvsmb uvmp9" ./...
|
||||
#popd
|
||||
3
vendor/github.com/Microsoft/hcsshim/hcn/doc.go
generated
vendored
Normal file
3
vendor/github.com/Microsoft/hcsshim/hcn/doc.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server
|
||||
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
|
||||
package hcn
|
||||
22
vendor/github.com/Microsoft/hcsshim/hcn/hcn.go
generated
vendored
22
vendor/github.com/Microsoft/hcsshim/hcn/hcn.go
generated
vendored
@@ -1,5 +1,5 @@
|
||||
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server
|
||||
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
|
||||
//go:build windows
|
||||
|
||||
package hcn
|
||||
|
||||
import (
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/Microsoft/go-winio/pkg/guid"
|
||||
)
|
||||
|
||||
//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go hcn.go
|
||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go hcn.go
|
||||
|
||||
/// HNS V1 API
|
||||
|
||||
@@ -228,7 +228,7 @@ func IPv6DualStackSupported() error {
|
||||
return platformDoesNotSupportError("IPv6 DualStack")
|
||||
}
|
||||
|
||||
//L4proxySupported returns an error if the HCN verison does not support L4Proxy
|
||||
// L4proxySupported returns an error if the HCN version does not support L4Proxy
|
||||
func L4proxyPolicySupported() error {
|
||||
supported, err := GetCachedSupportedFeatures()
|
||||
if err != nil {
|
||||
@@ -240,7 +240,7 @@ func L4proxyPolicySupported() error {
|
||||
return platformDoesNotSupportError("L4ProxyPolicy")
|
||||
}
|
||||
|
||||
// L4WfpProxySupported returns an error if the HCN verison does not support L4WfpProxy
|
||||
// L4WfpProxySupported returns an error if the HCN version does not support L4WfpProxy
|
||||
func L4WfpProxyPolicySupported() error {
|
||||
supported, err := GetCachedSupportedFeatures()
|
||||
if err != nil {
|
||||
@@ -312,6 +312,18 @@ func NestedIpSetSupported() error {
|
||||
return platformDoesNotSupportError("NestedIpSet")
|
||||
}
|
||||
|
||||
// DisableHostPortSupported returns an error if the HCN version does not support DisableHostPort flag
|
||||
func DisableHostPortSupported() error {
|
||||
supported, err := GetCachedSupportedFeatures()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if supported.DisableHostPort {
|
||||
return nil
|
||||
}
|
||||
return platformDoesNotSupportError("DisableHostPort")
|
||||
}
|
||||
|
||||
// RequestType are the different operations performed to settings.
|
||||
// Used to update the settings of Endpoint/Namespace objects.
|
||||
type RequestType string
|
||||
|
||||
66
vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go
generated
vendored
66
vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package hcn
|
||||
|
||||
import (
|
||||
@@ -9,7 +11,7 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// IpConfig is assoicated with an endpoint
|
||||
// IpConfig is associated with an endpoint
|
||||
type IpConfig struct {
|
||||
IpAddress string `json:",omitempty"`
|
||||
PrefixLength uint8 `json:",omitempty"`
|
||||
@@ -70,14 +72,14 @@ type PolicyEndpointRequest struct {
|
||||
Policies []EndpointPolicy `json:",omitempty"`
|
||||
}
|
||||
|
||||
func getEndpoint(endpointGuid guid.GUID, query string) (*HostComputeEndpoint, error) {
|
||||
func getEndpoint(endpointGUID guid.GUID, query string) (*HostComputeEndpoint, error) {
|
||||
// Open endpoint.
|
||||
var (
|
||||
endpointHandle hcnEndpoint
|
||||
resultBuffer *uint16
|
||||
propertiesBuffer *uint16
|
||||
)
|
||||
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer)
|
||||
hr := hcnOpenEndpoint(&endpointGUID, &endpointHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -119,8 +121,8 @@ func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
|
||||
}
|
||||
|
||||
var outputEndpoints []HostComputeEndpoint
|
||||
for _, endpointGuid := range endpointIds {
|
||||
endpoint, err := getEndpoint(endpointGuid, query)
|
||||
for _, endpointGUID := range endpointIds {
|
||||
endpoint, err := getEndpoint(endpointGUID, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -129,22 +131,22 @@ func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
|
||||
return outputEndpoints, nil
|
||||
}
|
||||
|
||||
func createEndpoint(networkId string, endpointSettings string) (*HostComputeEndpoint, error) {
|
||||
networkGuid, err := guid.FromString(networkId)
|
||||
func createEndpoint(networkID string, endpointSettings string) (*HostComputeEndpoint, error) {
|
||||
networkGUID, err := guid.FromString(networkID)
|
||||
if err != nil {
|
||||
return nil, errInvalidNetworkID
|
||||
}
|
||||
// Open network.
|
||||
var networkHandle hcnNetwork
|
||||
var resultBuffer *uint16
|
||||
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer)
|
||||
hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Create endpoint.
|
||||
endpointId := guid.GUID{}
|
||||
endpointID := guid.GUID{}
|
||||
var endpointHandle hcnEndpoint
|
||||
hr = hcnCreateEndpoint(networkHandle, &endpointId, endpointSettings, &endpointHandle, &resultBuffer)
|
||||
hr = hcnCreateEndpoint(networkHandle, &endpointID, endpointSettings, &endpointHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnCreateEndpoint", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -178,8 +180,8 @@ func createEndpoint(networkId string, endpointSettings string) (*HostComputeEndp
|
||||
return &outputEndpoint, nil
|
||||
}
|
||||
|
||||
func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, error) {
|
||||
endpointGuid, err := guid.FromString(endpointId)
|
||||
func modifyEndpoint(endpointID string, settings string) (*HostComputeEndpoint, error) {
|
||||
endpointGUID, err := guid.FromString(endpointID)
|
||||
if err != nil {
|
||||
return nil, errInvalidEndpointID
|
||||
}
|
||||
@@ -189,7 +191,7 @@ func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, e
|
||||
resultBuffer *uint16
|
||||
propertiesBuffer *uint16
|
||||
)
|
||||
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer)
|
||||
hr := hcnOpenEndpoint(&endpointGUID, &endpointHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -222,13 +224,13 @@ func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, e
|
||||
return &outputEndpoint, nil
|
||||
}
|
||||
|
||||
func deleteEndpoint(endpointId string) error {
|
||||
endpointGuid, err := guid.FromString(endpointId)
|
||||
func deleteEndpoint(endpointID string) error {
|
||||
endpointGUID, err := guid.FromString(endpointID)
|
||||
if err != nil {
|
||||
return errInvalidEndpointID
|
||||
}
|
||||
var resultBuffer *uint16
|
||||
hr := hcnDeleteEndpoint(&endpointGuid, &resultBuffer)
|
||||
hr := hcnDeleteEndpoint(&endpointGUID, &resultBuffer)
|
||||
if err := checkForErrors("hcnDeleteEndpoint", hr, resultBuffer); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -247,12 +249,12 @@ func ListEndpoints() ([]HostComputeEndpoint, error) {
|
||||
|
||||
// ListEndpointsQuery makes a call to query the list of available endpoints.
|
||||
func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
|
||||
queryJson, err := json.Marshal(query)
|
||||
queryJSON, err := json.Marshal(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endpoints, err := enumerateEndpoints(string(queryJson))
|
||||
endpoints, err := enumerateEndpoints(string(queryJSON))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -260,10 +262,10 @@ func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
|
||||
}
|
||||
|
||||
// ListEndpointsOfNetwork queries the list of endpoints on a network.
|
||||
func ListEndpointsOfNetwork(networkId string) ([]HostComputeEndpoint, error) {
|
||||
func ListEndpointsOfNetwork(networkID string) ([]HostComputeEndpoint, error) {
|
||||
hcnQuery := defaultQuery()
|
||||
// TODO: Once query can convert schema, change to {HostComputeNetwork:networkId}
|
||||
mapA := map[string]string{"VirtualNetwork": networkId}
|
||||
mapA := map[string]string{"VirtualNetwork": networkID}
|
||||
filter, err := json.Marshal(mapA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -274,9 +276,9 @@ func ListEndpointsOfNetwork(networkId string) ([]HostComputeEndpoint, error) {
|
||||
}
|
||||
|
||||
// GetEndpointByID returns an endpoint specified by Id
|
||||
func GetEndpointByID(endpointId string) (*HostComputeEndpoint, error) {
|
||||
func GetEndpointByID(endpointID string) (*HostComputeEndpoint, error) {
|
||||
hcnQuery := defaultQuery()
|
||||
mapA := map[string]string{"ID": endpointId}
|
||||
mapA := map[string]string{"ID": endpointID}
|
||||
filter, err := json.Marshal(mapA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -288,7 +290,7 @@ func GetEndpointByID(endpointId string) (*HostComputeEndpoint, error) {
|
||||
return nil, err
|
||||
}
|
||||
if len(endpoints) == 0 {
|
||||
return nil, EndpointNotFoundError{EndpointID: endpointId}
|
||||
return nil, EndpointNotFoundError{EndpointID: endpointID}
|
||||
}
|
||||
return &endpoints[0], err
|
||||
}
|
||||
@@ -345,15 +347,15 @@ func (endpoint *HostComputeEndpoint) Delete() error {
|
||||
}
|
||||
|
||||
// ModifyEndpointSettings updates the Port/Policy of an Endpoint.
|
||||
func ModifyEndpointSettings(endpointId string, request *ModifyEndpointSettingRequest) error {
|
||||
logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointId)
|
||||
func ModifyEndpointSettings(endpointID string, request *ModifyEndpointSettingRequest) error {
|
||||
logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointID)
|
||||
|
||||
endpointSettingsRequest, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = modifyEndpoint(endpointId, string(endpointSettingsRequest))
|
||||
_, err = modifyEndpoint(endpointID, string(endpointSettingsRequest))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -364,25 +366,25 @@ func ModifyEndpointSettings(endpointId string, request *ModifyEndpointSettingReq
|
||||
func (endpoint *HostComputeEndpoint) ApplyPolicy(requestType RequestType, endpointPolicy PolicyEndpointRequest) error {
|
||||
logrus.Debugf("hcn::HostComputeEndpoint::ApplyPolicy id=%s", endpoint.Id)
|
||||
|
||||
settingsJson, err := json.Marshal(endpointPolicy)
|
||||
settingsJSON, err := json.Marshal(endpointPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestMessage := &ModifyEndpointSettingRequest{
|
||||
ResourceType: EndpointResourceTypePolicy,
|
||||
RequestType: requestType,
|
||||
Settings: settingsJson,
|
||||
Settings: settingsJSON,
|
||||
}
|
||||
|
||||
return ModifyEndpointSettings(endpoint.Id, requestMessage)
|
||||
}
|
||||
|
||||
// NamespaceAttach modifies a Namespace to add an endpoint.
|
||||
func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceId string) error {
|
||||
return AddNamespaceEndpoint(namespaceId, endpoint.Id)
|
||||
func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceID string) error {
|
||||
return AddNamespaceEndpoint(namespaceID, endpoint.Id)
|
||||
}
|
||||
|
||||
// NamespaceDetach modifies a Namespace to remove an endpoint.
|
||||
func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceId string) error {
|
||||
return RemoveNamespaceEndpoint(namespaceId, endpoint.Id)
|
||||
func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceID string) error {
|
||||
return RemoveNamespaceEndpoint(namespaceID, endpoint.Id)
|
||||
}
|
||||
|
||||
76
vendor/github.com/Microsoft/hcsshim/hcn/hcnerrors.go
generated
vendored
76
vendor/github.com/Microsoft/hcsshim/hcn/hcnerrors.go
generated
vendored
@@ -1,15 +1,17 @@
|
||||
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server
|
||||
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
|
||||
//go:build windows
|
||||
|
||||
package hcn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
"github.com/Microsoft/hcsshim/internal/hcs"
|
||||
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||
"github.com/Microsoft/hcsshim/internal/interop"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -48,8 +50,8 @@ type ErrorCode uint32
|
||||
|
||||
// For common errors, define the error as it is in windows, so we can quickly determine it later
|
||||
const (
|
||||
ERROR_NOT_FOUND = 0x490
|
||||
HCN_E_PORT_ALREADY_EXISTS ErrorCode = 0x803b0013
|
||||
ERROR_NOT_FOUND = ErrorCode(windows.ERROR_NOT_FOUND)
|
||||
HCN_E_PORT_ALREADY_EXISTS ErrorCode = ErrorCode(windows.HCN_E_PORT_ALREADY_EXISTS)
|
||||
)
|
||||
|
||||
type HcnError struct {
|
||||
@@ -62,8 +64,8 @@ func (e *HcnError) Error() string {
|
||||
}
|
||||
|
||||
func CheckErrorWithCode(err error, code ErrorCode) bool {
|
||||
hcnError, ok := err.(*HcnError)
|
||||
if ok {
|
||||
var hcnError *HcnError
|
||||
if errors.As(err, &hcnError) {
|
||||
return hcnError.code == code
|
||||
}
|
||||
return false
|
||||
@@ -80,22 +82,24 @@ func IsPortAlreadyExistsError(err error) bool {
|
||||
func new(hr error, title string, rest string) error {
|
||||
err := &HcnError{}
|
||||
hcsError := hcserror.New(hr, title, rest)
|
||||
err.HcsError = hcsError.(*hcserror.HcsError)
|
||||
err.HcsError = hcsError.(*hcserror.HcsError) //nolint:errorlint
|
||||
err.code = ErrorCode(hcserror.Win32FromError(hr))
|
||||
return err
|
||||
}
|
||||
|
||||
//
|
||||
// Note that the below errors are not errors returned by hcn itself
|
||||
// we wish to seperate them as they are shim usage error
|
||||
// we wish to separate them as they are shim usage error
|
||||
//
|
||||
|
||||
// NetworkNotFoundError results from a failed seach for a network by Id or Name
|
||||
// NetworkNotFoundError results from a failed search for a network by Id or Name
|
||||
type NetworkNotFoundError struct {
|
||||
NetworkName string
|
||||
NetworkID string
|
||||
}
|
||||
|
||||
var _ error = NetworkNotFoundError{}
|
||||
|
||||
func (e NetworkNotFoundError) Error() string {
|
||||
if e.NetworkName != "" {
|
||||
return fmt.Sprintf("Network name %q not found", e.NetworkName)
|
||||
@@ -103,12 +107,14 @@ func (e NetworkNotFoundError) Error() string {
|
||||
return fmt.Sprintf("Network ID %q not found", e.NetworkID)
|
||||
}
|
||||
|
||||
// EndpointNotFoundError results from a failed seach for an endpoint by Id or Name
|
||||
// EndpointNotFoundError results from a failed search for an endpoint by Id or Name
|
||||
type EndpointNotFoundError struct {
|
||||
EndpointName string
|
||||
EndpointID string
|
||||
}
|
||||
|
||||
var _ error = EndpointNotFoundError{}
|
||||
|
||||
func (e EndpointNotFoundError) Error() string {
|
||||
if e.EndpointName != "" {
|
||||
return fmt.Sprintf("Endpoint name %q not found", e.EndpointName)
|
||||
@@ -116,29 +122,35 @@ func (e EndpointNotFoundError) Error() string {
|
||||
return fmt.Sprintf("Endpoint ID %q not found", e.EndpointID)
|
||||
}
|
||||
|
||||
// NamespaceNotFoundError results from a failed seach for a namsepace by Id
|
||||
// NamespaceNotFoundError results from a failed search for a namsepace by Id
|
||||
type NamespaceNotFoundError struct {
|
||||
NamespaceID string
|
||||
}
|
||||
|
||||
var _ error = NamespaceNotFoundError{}
|
||||
|
||||
func (e NamespaceNotFoundError) Error() string {
|
||||
return fmt.Sprintf("Namespace ID %q not found", e.NamespaceID)
|
||||
}
|
||||
|
||||
// LoadBalancerNotFoundError results from a failed seach for a loadbalancer by Id
|
||||
// LoadBalancerNotFoundError results from a failed search for a loadbalancer by Id
|
||||
type LoadBalancerNotFoundError struct {
|
||||
LoadBalancerId string
|
||||
}
|
||||
|
||||
var _ error = LoadBalancerNotFoundError{}
|
||||
|
||||
func (e LoadBalancerNotFoundError) Error() string {
|
||||
return fmt.Sprintf("LoadBalancer %q not found", e.LoadBalancerId)
|
||||
}
|
||||
|
||||
// RouteNotFoundError results from a failed seach for a route by Id
|
||||
// RouteNotFoundError results from a failed search for a route by Id
|
||||
type RouteNotFoundError struct {
|
||||
RouteId string
|
||||
}
|
||||
|
||||
var _ error = RouteNotFoundError{}
|
||||
|
||||
func (e RouteNotFoundError) Error() string {
|
||||
return fmt.Sprintf("SDN Route %q not found", e.RouteId)
|
||||
}
|
||||
@@ -146,19 +158,31 @@ func (e RouteNotFoundError) Error() string {
|
||||
// IsNotFoundError returns a boolean indicating whether the error was caused by
|
||||
// a resource not being found.
|
||||
func IsNotFoundError(err error) bool {
|
||||
switch pe := err.(type) {
|
||||
case NetworkNotFoundError:
|
||||
// Calling [errors.As] in a loop over `[]error{NetworkNotFoundError{}, ...}` will not work,
|
||||
// since the loop variable will be an interface type (ie, `error`) and `errors.As(error, *error)` will
|
||||
// always succeed.
|
||||
// Unless golang adds loops over (or arrays of) types, we need to manually call `errors.As` for
|
||||
// each potential error type.
|
||||
//
|
||||
// Also, for T = NetworkNotFoundError and co, the error implementation is for T, not *T
|
||||
if e := (NetworkNotFoundError{}); errors.As(err, &e) {
|
||||
return true
|
||||
case EndpointNotFoundError:
|
||||
return true
|
||||
case NamespaceNotFoundError:
|
||||
return true
|
||||
case LoadBalancerNotFoundError:
|
||||
return true
|
||||
case RouteNotFoundError:
|
||||
return true
|
||||
case *hcserror.HcsError:
|
||||
return pe.Err == hcs.ErrElementNotFound
|
||||
}
|
||||
if e := (EndpointNotFoundError{}); errors.As(err, &e) {
|
||||
return true
|
||||
}
|
||||
if e := (NamespaceNotFoundError{}); errors.As(err, &e) {
|
||||
return true
|
||||
}
|
||||
if e := (LoadBalancerNotFoundError{}); errors.As(err, &e) {
|
||||
return true
|
||||
}
|
||||
if e := (RouteNotFoundError{}); errors.As(err, &e) {
|
||||
return true
|
||||
}
|
||||
if e := (&hcserror.HcsError{}); errors.As(err, &e) {
|
||||
return errors.Is(e.Err, hcs.ErrElementNotFound)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
5
vendor/github.com/Microsoft/hcsshim/hcn/hcnglobals.go
generated
vendored
5
vendor/github.com/Microsoft/hcsshim/hcn/hcnglobals.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package hcn
|
||||
|
||||
import (
|
||||
@@ -82,6 +84,9 @@ var (
|
||||
|
||||
//HNS 15.0 allows for NestedIpSet support
|
||||
NestedIpSetVersion = VersionRanges{VersionRange{MinVersion: Version{Major: 15, Minor: 0}, MaxVersion: Version{Major: math.MaxInt32, Minor: math.MaxInt32}}}
|
||||
|
||||
//HNS 15.1 allows support for DisableHostPort flag.
|
||||
DisableHostPortVersion = VersionRanges{VersionRange{MinVersion: Version{Major: 15, Minor: 1}, MaxVersion: Version{Major: math.MaxInt32, Minor: math.MaxInt32}}}
|
||||
)
|
||||
|
||||
// GetGlobals returns the global properties of the HCN Service.
|
||||
|
||||
34
vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go
generated
vendored
34
vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
//go:build windows
|
||||
|
||||
package hcn
|
||||
|
||||
import (
|
||||
@@ -28,14 +30,14 @@ type HostComputeLoadBalancer struct {
|
||||
Flags LoadBalancerFlags `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn
|
||||
}
|
||||
|
||||
//LoadBalancerFlags modify settings for a loadbalancer.
|
||||
// LoadBalancerFlags modify settings for a loadbalancer.
|
||||
type LoadBalancerFlags uint32
|
||||
|
||||
var (
|
||||
// LoadBalancerFlagsNone is the default.
|
||||
LoadBalancerFlagsNone LoadBalancerFlags = 0
|
||||
// LoadBalancerFlagsDSR enables Direct Server Return (DSR)
|
||||
LoadBalancerFlagsDSR LoadBalancerFlags = 1
|
||||
LoadBalancerFlagsDSR LoadBalancerFlags = 1
|
||||
LoadBalancerFlagsIPv6 LoadBalancerFlags = 2
|
||||
)
|
||||
|
||||
@@ -67,14 +69,14 @@ var (
|
||||
LoadBalancerDistributionSourceIP LoadBalancerDistribution = 2
|
||||
)
|
||||
|
||||
func getLoadBalancer(loadBalancerGuid guid.GUID, query string) (*HostComputeLoadBalancer, error) {
|
||||
func getLoadBalancer(loadBalancerGUID guid.GUID, query string) (*HostComputeLoadBalancer, error) {
|
||||
// Open loadBalancer.
|
||||
var (
|
||||
loadBalancerHandle hcnLoadBalancer
|
||||
resultBuffer *uint16
|
||||
propertiesBuffer *uint16
|
||||
)
|
||||
hr := hcnOpenLoadBalancer(&loadBalancerGuid, &loadBalancerHandle, &resultBuffer)
|
||||
hr := hcnOpenLoadBalancer(&loadBalancerGUID, &loadBalancerHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnOpenLoadBalancer", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -115,8 +117,8 @@ func enumerateLoadBalancers(query string) ([]HostComputeLoadBalancer, error) {
|
||||
}
|
||||
|
||||
var outputLoadBalancers []HostComputeLoadBalancer
|
||||
for _, loadBalancerGuid := range loadBalancerIds {
|
||||
loadBalancer, err := getLoadBalancer(loadBalancerGuid, query)
|
||||
for _, loadBalancerGUID := range loadBalancerIds {
|
||||
loadBalancer, err := getLoadBalancer(loadBalancerGUID, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -132,8 +134,8 @@ func createLoadBalancer(settings string) (*HostComputeLoadBalancer, error) {
|
||||
resultBuffer *uint16
|
||||
propertiesBuffer *uint16
|
||||
)
|
||||
loadBalancerGuid := guid.GUID{}
|
||||
hr := hcnCreateLoadBalancer(&loadBalancerGuid, settings, &loadBalancerHandle, &resultBuffer)
|
||||
loadBalancerGUID := guid.GUID{}
|
||||
hr := hcnCreateLoadBalancer(&loadBalancerGUID, settings, &loadBalancerHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnCreateLoadBalancer", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -161,13 +163,13 @@ func createLoadBalancer(settings string) (*HostComputeLoadBalancer, error) {
|
||||
return &outputLoadBalancer, nil
|
||||
}
|
||||
|
||||
func deleteLoadBalancer(loadBalancerId string) error {
|
||||
loadBalancerGuid, err := guid.FromString(loadBalancerId)
|
||||
func deleteLoadBalancer(loadBalancerID string) error {
|
||||
loadBalancerGUID, err := guid.FromString(loadBalancerID)
|
||||
if err != nil {
|
||||
return errInvalidLoadBalancerID
|
||||
}
|
||||
var resultBuffer *uint16
|
||||
hr := hcnDeleteLoadBalancer(&loadBalancerGuid, &resultBuffer)
|
||||
hr := hcnDeleteLoadBalancer(&loadBalancerGUID, &resultBuffer)
|
||||
if err := checkForErrors("hcnDeleteLoadBalancer", hr, resultBuffer); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -186,12 +188,12 @@ func ListLoadBalancers() ([]HostComputeLoadBalancer, error) {
|
||||
|
||||
// ListLoadBalancersQuery makes a call to query the list of available loadBalancers.
|
||||
func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer, error) {
|
||||
queryJson, err := json.Marshal(query)
|
||||
queryJSON, err := json.Marshal(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
loadBalancers, err := enumerateLoadBalancers(string(queryJson))
|
||||
loadBalancers, err := enumerateLoadBalancers(string(queryJSON))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -199,9 +201,9 @@ func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer,
|
||||
}
|
||||
|
||||
// GetLoadBalancerByID returns the LoadBalancer specified by Id.
|
||||
func GetLoadBalancerByID(loadBalancerId string) (*HostComputeLoadBalancer, error) {
|
||||
func GetLoadBalancerByID(loadBalancerID string) (*HostComputeLoadBalancer, error) {
|
||||
hcnQuery := defaultQuery()
|
||||
mapA := map[string]string{"ID": loadBalancerId}
|
||||
mapA := map[string]string{"ID": loadBalancerID}
|
||||
filter, err := json.Marshal(mapA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -213,7 +215,7 @@ func GetLoadBalancerByID(loadBalancerId string) (*HostComputeLoadBalancer, error
|
||||
return nil, err
|
||||
}
|
||||
if len(loadBalancers) == 0 {
|
||||
return nil, LoadBalancerNotFoundError{LoadBalancerId: loadBalancerId}
|
||||
return nil, LoadBalancerNotFoundError{LoadBalancerId: loadBalancerID}
|
||||
}
|
||||
return &loadBalancers[0], err
|
||||
}
|
||||
|
||||
88
vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace.go
generated
vendored
88
vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace.go
generated
vendored
@@ -1,7 +1,10 @@
|
||||
//go:build windows
|
||||
|
||||
package hcn
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
@@ -27,7 +30,7 @@ type NamespaceResourceContainer struct {
|
||||
type NamespaceResourceType string
|
||||
|
||||
var (
|
||||
// NamespaceResourceTypeContainer are contianers associated with a Namespace.
|
||||
// NamespaceResourceTypeContainer are containers associated with a Namespace.
|
||||
NamespaceResourceTypeContainer NamespaceResourceType = "Container"
|
||||
// NamespaceResourceTypeEndpoint are endpoints associated with a Namespace.
|
||||
NamespaceResourceTypeEndpoint NamespaceResourceType = "Endpoint"
|
||||
@@ -70,14 +73,14 @@ type ModifyNamespaceSettingRequest struct {
|
||||
Settings json.RawMessage `json:",omitempty"`
|
||||
}
|
||||
|
||||
func getNamespace(namespaceGuid guid.GUID, query string) (*HostComputeNamespace, error) {
|
||||
func getNamespace(namespaceGUID guid.GUID, query string) (*HostComputeNamespace, error) {
|
||||
// Open namespace.
|
||||
var (
|
||||
namespaceHandle hcnNamespace
|
||||
resultBuffer *uint16
|
||||
propertiesBuffer *uint16
|
||||
)
|
||||
hr := hcnOpenNamespace(&namespaceGuid, &namespaceHandle, &resultBuffer)
|
||||
hr := hcnOpenNamespace(&namespaceGUID, &namespaceHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -118,8 +121,8 @@ func enumerateNamespaces(query string) ([]HostComputeNamespace, error) {
|
||||
}
|
||||
|
||||
var outputNamespaces []HostComputeNamespace
|
||||
for _, namespaceGuid := range namespaceIds {
|
||||
namespace, err := getNamespace(namespaceGuid, query)
|
||||
for _, namespaceGUID := range namespaceIds {
|
||||
namespace, err := getNamespace(namespaceGUID, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -135,8 +138,8 @@ func createNamespace(settings string) (*HostComputeNamespace, error) {
|
||||
resultBuffer *uint16
|
||||
propertiesBuffer *uint16
|
||||
)
|
||||
namespaceGuid := guid.GUID{}
|
||||
hr := hcnCreateNamespace(&namespaceGuid, settings, &namespaceHandle, &resultBuffer)
|
||||
namespaceGUID := guid.GUID{}
|
||||
hr := hcnCreateNamespace(&namespaceGUID, settings, &namespaceHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnCreateNamespace", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -164,8 +167,8 @@ func createNamespace(settings string) (*HostComputeNamespace, error) {
|
||||
return &outputNamespace, nil
|
||||
}
|
||||
|
||||
func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace, error) {
|
||||
namespaceGuid, err := guid.FromString(namespaceId)
|
||||
func modifyNamespace(namespaceID string, settings string) (*HostComputeNamespace, error) {
|
||||
namespaceGUID, err := guid.FromString(namespaceID)
|
||||
if err != nil {
|
||||
return nil, errInvalidNamespaceID
|
||||
}
|
||||
@@ -175,7 +178,7 @@ func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace
|
||||
resultBuffer *uint16
|
||||
propertiesBuffer *uint16
|
||||
)
|
||||
hr := hcnOpenNamespace(&namespaceGuid, &namespaceHandle, &resultBuffer)
|
||||
hr := hcnOpenNamespace(&namespaceGUID, &namespaceHandle, &resultBuffer)
|
||||
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -208,13 +211,13 @@ func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace
|
||||
return &outputNamespace, nil
|
||||
}
|
||||
|
||||
func deleteNamespace(namespaceId string) error {
|
||||
namespaceGuid, err := guid.FromString(namespaceId)
|
||||
func deleteNamespace(namespaceID string) error {
|
||||
namespaceGUID, err := guid.FromString(namespaceID)
|
||||
if err != nil {
|
||||
return errInvalidNamespaceID
|
||||
}
|
||||
var resultBuffer *uint16
|
||||
hr := hcnDeleteNamespace(&namespaceGuid, &resultBuffer)
|
||||
hr := hcnDeleteNamespace(&namespaceGUID, &resultBuffer)
|
||||
if err := checkForErrors("hcnDeleteNamespace", hr, resultBuffer); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -233,12 +236,12 @@ func ListNamespaces() ([]HostComputeNamespace, error) {
|
||||
|
||||
// ListNamespacesQuery makes a call to query the list of available namespaces.
|
||||
func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error) {
|
||||
queryJson, err := json.Marshal(query)
|
||||
queryJSON, err := json.Marshal(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespaces, err := enumerateNamespaces(string(queryJson))
|
||||
namespaces, err := enumerateNamespaces(string(queryJSON))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -246,9 +249,9 @@ func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error)
|
||||
}
|
||||
|
||||
// GetNamespaceByID returns the Namespace specified by Id.
|
||||
func GetNamespaceByID(namespaceId string) (*HostComputeNamespace, error) {
|
||||
func GetNamespaceByID(namespaceID string) (*HostComputeNamespace, error) {
|
||||
hcnQuery := defaultQuery()
|
||||
mapA := map[string]string{"ID": namespaceId}
|
||||
mapA := map[string]string{"ID": namespaceID}
|
||||
filter, err := json.Marshal(mapA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -260,15 +263,15 @@ func GetNamespaceByID(namespaceId string) (*HostComputeNamespace, error) {
|
||||
return nil, err
|
||||
}
|
||||
if len(namespaces) == 0 {
|
||||
return nil, NamespaceNotFoundError{NamespaceID: namespaceId}
|
||||
return nil, NamespaceNotFoundError{NamespaceID: namespaceID}
|
||||
}
|
||||
|
||||
return &namespaces[0], err
|
||||
}
|
||||
|
||||
// GetNamespaceEndpointIds returns the endpoints of the Namespace specified by Id.
|
||||
func GetNamespaceEndpointIds(namespaceId string) ([]string, error) {
|
||||
namespace, err := GetNamespaceByID(namespaceId)
|
||||
func GetNamespaceEndpointIds(namespaceID string) ([]string, error) {
|
||||
namespace, err := GetNamespaceByID(namespaceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -286,19 +289,19 @@ func GetNamespaceEndpointIds(namespaceId string) ([]string, error) {
|
||||
}
|
||||
|
||||
// GetNamespaceContainerIds returns the containers of the Namespace specified by Id.
|
||||
func GetNamespaceContainerIds(namespaceId string) ([]string, error) {
|
||||
namespace, err := GetNamespaceByID(namespaceId)
|
||||
func GetNamespaceContainerIds(namespaceID string) ([]string, error) {
|
||||
namespace, err := GetNamespaceByID(namespaceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var containerIds []string
|
||||
for _, resource := range namespace.Resources {
|
||||
if resource.Type == "Container" {
|
||||
var contaienrResource NamespaceResourceContainer
|
||||
if err := json.Unmarshal([]byte(resource.Data), &contaienrResource); err != nil {
|
||||
var containerResource NamespaceResourceContainer
|
||||
if err := json.Unmarshal([]byte(resource.Data), &containerResource); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containerIds = append(containerIds, contaienrResource.Id)
|
||||
containerIds = append(containerIds, containerResource.Id)
|
||||
}
|
||||
}
|
||||
return containerIds, nil
|
||||
@@ -375,8 +378,9 @@ func (namespace *HostComputeNamespace) Sync() error {
|
||||
}
|
||||
shimPath := runhcs.VMPipePath(cfg.HostUniqueID)
|
||||
if err := runhcs.IssueVMRequest(shimPath, &req); err != nil {
|
||||
// The shim is likey gone. Simply ignore the sync as if it didn't exist.
|
||||
if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.ERROR_FILE_NOT_FOUND {
|
||||
// The shim is likely gone. Simply ignore the sync as if it didn't exist.
|
||||
var perr *os.PathError
|
||||
if errors.As(err, &perr) && errors.Is(perr.Err, syscall.ERROR_FILE_NOT_FOUND) {
|
||||
// Remove the reg key there is no point to try again
|
||||
_ = cfg.Remove()
|
||||
return nil
|
||||
@@ -394,15 +398,15 @@ func (namespace *HostComputeNamespace) Sync() error {
|
||||
}
|
||||
|
||||
// ModifyNamespaceSettings updates the Endpoints/Containers of a Namespace.
|
||||
func ModifyNamespaceSettings(namespaceId string, request *ModifyNamespaceSettingRequest) error {
|
||||
logrus.Debugf("hcn::HostComputeNamespace::ModifyNamespaceSettings id=%s", namespaceId)
|
||||
func ModifyNamespaceSettings(namespaceID string, request *ModifyNamespaceSettingRequest) error {
|
||||
logrus.Debugf("hcn::HostComputeNamespace::ModifyNamespaceSettings id=%s", namespaceID)
|
||||
|
||||
namespaceSettings, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = modifyNamespace(namespaceId, string(namespaceSettings))
|
||||
_, err = modifyNamespace(namespaceID, string(namespaceSettings))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -410,37 +414,37 @@ func ModifyNamespaceSettings(namespaceId string, request *ModifyNamespaceSetting
|
||||
}
|
||||
|
||||
// AddNamespaceEndpoint adds an endpoint to a Namespace.
|
||||
func AddNamespaceEndpoint(namespaceId string, endpointId string) error {
|
||||
logrus.Debugf("hcn::HostComputeEndpoint::AddNamespaceEndpoint id=%s", endpointId)
|
||||
func AddNamespaceEndpoint(namespaceID string, endpointID string) error {
|
||||
logrus.Debugf("hcn::HostComputeEndpoint::AddNamespaceEndpoint id=%s", endpointID)
|
||||
|
||||
mapA := map[string]string{"EndpointId": endpointId}
|
||||
settingsJson, err := json.Marshal(mapA)
|
||||
mapA := map[string]string{"EndpointId": endpointID}
|
||||
settingsJSON, err := json.Marshal(mapA)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestMessage := &ModifyNamespaceSettingRequest{
|
||||
ResourceType: NamespaceResourceTypeEndpoint,
|
||||
RequestType: RequestTypeAdd,
|
||||
Settings: settingsJson,
|
||||
Settings: settingsJSON,
|
||||
}
|
||||
|
||||
return ModifyNamespaceSettings(namespaceId, requestMessage)
|
||||
return ModifyNamespaceSettings(namespaceID, requestMessage)
|
||||
}
|
||||
|
||||
// RemoveNamespaceEndpoint removes an endpoint from a Namespace.
|
||||
func RemoveNamespaceEndpoint(namespaceId string, endpointId string) error {
|
||||
logrus.Debugf("hcn::HostComputeNamespace::RemoveNamespaceEndpoint id=%s", endpointId)
|
||||
func RemoveNamespaceEndpoint(namespaceID string, endpointID string) error {
|
||||
logrus.Debugf("hcn::HostComputeNamespace::RemoveNamespaceEndpoint id=%s", endpointID)
|
||||
|
||||
mapA := map[string]string{"EndpointId": endpointId}
|
||||
settingsJson, err := json.Marshal(mapA)
|
||||
mapA := map[string]string{"EndpointId": endpointID}
|
||||
settingsJSON, err := json.Marshal(mapA)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestMessage := &ModifyNamespaceSettingRequest{
|
||||
ResourceType: NamespaceResourceTypeEndpoint,
|
||||
RequestType: RequestTypeRemove,
|
||||
Settings: settingsJson,
|
||||
Settings: settingsJSON,
|
||||
}
|
||||
|
||||
return ModifyNamespaceSettings(namespaceId, requestMessage)
|
||||
return ModifyNamespaceSettings(namespaceID, requestMessage)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user