Compare commits

..

101 Commits

Author SHA1 Message Date
8fc26ce7a0 Merge pull request #991 from containernetworking/dependabot/docker/dot-github/actions/retest-action/alpine-3.19
build(deps): bump alpine from 3.18 to 3.19 in /.github/actions/retest-action
2024-03-12 02:54:07 +09:00
c8d165df6d Merge branch 'main' into dependabot/docker/dot-github/actions/retest-action/alpine-3.19 2024-03-12 02:27:00 +09:00
1b5811957e Merge pull request #1010 from containernetworking/dependabot/github_actions/actions/checkout-4
build(deps): bump actions/checkout from 3 to 4
2024-03-11 18:12:59 +01:00
8a3014f202 build(deps): bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 17:03:59 +00:00
019727a392 Merge pull request #1005 from austinvazquez/update-golangci-lint-action-package
Update golangci-lint-action package to v4
2024-03-11 18:03:14 +01:00
352e0512e8 Update golangci-lint-action package to v4
This change updates golangci-lint-action package to v4 to resolve NodeJS
16 deprecation warnings.

Signed-off-by: Austin Vazquez <macedonv@amazon.com>
2024-03-11 17:52:02 +01:00
9c016b5d12 Rename unused variables to resolve lint warnings
Signed-off-by: Austin Vazquez <macedonv@amazon.com>
2024-03-11 17:52:02 +01:00
0729398940 Merge pull request #1017 from containernetworking/dependabot/go_modules/golang-6a70725da1
build(deps): bump the golang group with 5 updates
2024-03-11 17:50:33 +01:00
394ab0d149 build(deps): bump the golang group with 5 updates
Bumps the golang group with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim) | `0.11.4` | `0.12.0` |
| [github.com/alexflint/go-filemutex](https://github.com/alexflint/go-filemutex) | `1.2.0` | `1.3.0` |
| [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) | `2.13.2` | `2.16.0` |
| [github.com/onsi/gomega](https://github.com/onsi/gomega) | `1.30.0` | `1.31.1` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.15.0` | `0.17.0` |


Updates `github.com/Microsoft/hcsshim` from 0.11.4 to 0.12.0
- [Release notes](https://github.com/Microsoft/hcsshim/releases)
- [Commits](https://github.com/Microsoft/hcsshim/compare/v0.11.4...v0.12.0)

Updates `github.com/alexflint/go-filemutex` from 1.2.0 to 1.3.0
- [Release notes](https://github.com/alexflint/go-filemutex/releases)
- [Commits](https://github.com/alexflint/go-filemutex/compare/v1.2.0...v1.3.0)

Updates `github.com/onsi/ginkgo/v2` from 2.13.2 to 2.16.0
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.13.2...v2.16.0)

Updates `github.com/onsi/gomega` from 1.30.0 to 1.31.1
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.30.0...v1.31.1)

Updates `golang.org/x/sys` from 0.15.0 to 0.17.0
- [Commits](https://github.com/golang/sys/compare/v0.15.0...v0.17.0)

---
updated-dependencies:
- dependency-name: github.com/Microsoft/hcsshim
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: github.com/alexflint/go-filemutex
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 15:54:46 +00:00
0144de0fcf Merge pull request #1011 from containernetworking/dependabot/github_actions/actions/setup-go-5
build(deps): bump actions/setup-go from 3 to 5
2024-03-11 16:51:01 +01:00
47373d2612 build(deps): bump actions/setup-go from 3 to 5
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v3...v5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 15:07:08 +00:00
8e8410f726 Merge pull request #1006 from austinvazquez/update-go-in-ci
Update to Go v1.22 in CI and release
2024-03-11 16:06:20 +01:00
2bae9b67d3 Update to Go v1.22 in CI and release
Signed-off-by: Austin Vazquez <macedonv@amazon.com>
2024-03-11 15:52:12 +01:00
976edfe1bc Merge pull request #1009 from adrianchiris/fix-lint-version
Fix version of golangci-lint
2024-03-11 15:51:56 +01:00
cb244060c2 Fix version of golangci-lint
currently the workflow will use latest
version which is a moving target.

newer versions may cause ci failures due
to new checks added.

Signed-off-by: adrianc <adrianc@nvidia.com>
2024-02-13 10:35:41 +02:00
d1aada912d Merge pull request #1000 from s1061123/add-build-gh-action
Add github action to build binaries for each platform at release
2024-02-12 17:28:13 +01:00
8b2b1d20d6 Add github action to build binaries for each platform at release
This change introduces new github action to build cni plugin
binaries for each platform at tagged new release.

Signed-off-by: Tomofumi Hayashi <tohayash@redhat.com>
2024-02-06 01:01:35 +09:00
14bdce598f Merge pull request #997 from ormergi/bridge-cont-iface-state
bridge: Enable disabling bridge interface
2024-02-02 21:22:32 +01:00
7e131a0076 bridge: Enable disabling bridge interface
The new `disableContainerInterface` parameter is added to the bridge plugin to
enable setting the container interface state down.

When the parameter is enabled, the container interface (veth peer that is placed
at the container ns) remain down (i.e: disabled).
The bridge and host peer interfaces state are not affected by the parameter.

Since IPAM logic involve various configurations including waiting for addresses
to be realized and setting the interface state UP, the new parameter cannot work
with IPAM.
In case both IPAM and DisableContainerInterface parameters are set, the bridge
plugin will raise an error.

Signed-off-by: Or Mergi <ormergi@redhat.com>
2024-01-10 15:35:23 +02:00
b6a0e0bc96 Merge pull request #990 from containernetworking/dependabot/github_actions/actions/setup-go-5
build(deps): bump actions/setup-go from 4 to 5
2023-12-11 17:08:17 +01:00
133a764c4d build(deps): bump alpine in /.github/actions/retest-action
Bumps alpine from 3.18 to 3.19.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-11 02:50:07 +00:00
e6099fb83d build(deps): bump actions/setup-go from 4 to 5
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-11 02:16:03 +00:00
1fb5bf669e Merge pull request #982 from jingyuanliang/patch-1
Bump to golang:1.21-alpine in release.sh
2023-12-04 10:37:33 +01:00
3712c1cfcb Merge pull request #988 from containernetworking/dependabot/go_modules/golang-2d6cee5bad
build(deps): bump the golang group with 2 updates
2023-12-04 10:36:51 +01:00
825421709e build(deps): bump the golang group with 2 updates
Bumps the golang group with 2 updates: [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) and [golang.org/x/sys](https://github.com/golang/sys).


Updates `github.com/onsi/ginkgo/v2` from 2.13.1 to 2.13.2
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.13.1...v2.13.2)

Updates `golang.org/x/sys` from 0.14.0 to 0.15.0
- [Commits](https://github.com/golang/sys/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: golang
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-04 02:47:46 +00:00
d708217503 Bump to golang:1.21-alpine in release.sh
Also make this overridable in env vars.

Signed-off-by: Jingyuan Liang <jingyuanliang@google.com>
2023-11-17 09:01:30 +00:00
abee8ccc0d Merge pull request #954 from cyclinder/improve_cmd_del
macvlan cmdDel: replace the loadConf function with json.unmarshal
2023-11-16 19:06:11 +01:00
e1474463ef Merge pull request #978 from containernetworking/dependabot/go_modules/golang-439c5fc513
build(deps): bump the golang group with 3 updates
2023-11-16 19:05:16 +01:00
11ee4b61d9 Merge pull request #969 from s1061123/fix-netns-override
Add CNI_NETNS_OVERRIDE for upcoming CNI change
2023-11-16 19:04:53 +01:00
a4cbf13a9b Add CNI_NETNS_OVERRIDE for upcoming CNI change
containernetwork/cni#890 introduces CNI_NETNS_OVERRIDE and plugin
testing requires this flag. This change enables CNI_NETNS_OVERRIDE
for further containernetwork/cni vendor update.

Signed-off-by: Tomofumi Hayashi <tohayash@redhat.com>
2023-11-16 23:18:00 +09:00
6cac5d603b build(deps): bump the golang group with 3 updates
Bumps the golang group with 3 updates: [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim), [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) and [github.com/onsi/gomega](https://github.com/onsi/gomega).


Updates `github.com/Microsoft/hcsshim` from 0.11.2 to 0.11.4
- [Release notes](https://github.com/Microsoft/hcsshim/releases)
- [Commits](https://github.com/Microsoft/hcsshim/compare/v0.11.2...v0.11.4)

Updates `github.com/onsi/ginkgo/v2` from 2.13.0 to 2.13.1
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.13.0...v2.13.1)

Updates `github.com/onsi/gomega` from 1.29.0 to 1.30.0
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.29.0...v1.30.0)

---
updated-dependencies:
- dependency-name: github.com/Microsoft/hcsshim
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: golang
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: golang
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-16 12:41:14 +00:00
333fc9a0d7 Merge pull request #981 from arthur-zhang/dev-revert
revert some code in pr 962
2023-11-16 13:39:59 +01:00
f90ac41ae4 revert some code in pr 962
Signed-off-by: arthur-zhang <zhangya_no1@qq.com>
2023-11-14 10:04:18 +08:00
93a1b3d0e7 Merge pull request #979 from s1061123/fix/ndisc_ipvlan
Add ndisc_notify in ipvlan for ipv6 ndp
2023-11-14 00:27:01 +01:00
00406f9d1e Merge branch 'main' into fix/ndisc_ipvlan 2023-11-14 08:18:07 +09:00
e82848a9cb Merge pull request #962 from arthur-zhang/dev-pr-bridge
bridge: remove useless code
2023-11-13 18:01:02 +01:00
5280b4d582 bridge: fix spelling
Signed-off-by: arthur-zhang <zhangya_no1@qq.com>
2023-11-13 17:11:21 +01:00
495a2cbb0c bridge: remove useless firstV4Addr
Signed-off-by: arthur-zhang <zhangya_no1@qq.com>
2023-11-13 17:11:21 +01:00
8c59fc1eea bridge: remove useless check
gws.defaultRouteFound here is always false.

Signed-off-by: arthur-zhang <zhangya_no1@qq.com>
2023-11-13 17:11:21 +01:00
2eee7cef35 Merge pull request #974 from zshi-redhat/macvlan-ipv6-ndisc
macvlan: enable ipv6 ndisc_notify
2023-11-13 17:08:56 +01:00
1079e113fe Add ndisc_notify in ipvlan for ipv6 ndp
Signed-off-by: Tomofumi Hayashi <tohayash@redhat.com>
2023-11-14 01:07:59 +09:00
999ca15763 macvlan: enable ipv6 ndisc_notify
Signed-off-by: Zenghui Shi <zshi@redhat.com>
2023-11-07 19:43:50 +08:00
dad27e9f72 Merge pull request #963 from containernetworking/dependabot/go_modules/google.golang.org/grpc-1.56.3
build(deps): bump google.golang.org/grpc from 1.50.1 to 1.56.3
2023-11-01 10:21:47 +01:00
0b1a96ff30 build(deps): bump google.golang.org/grpc from 1.50.1 to 1.56.3
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.50.1 to 1.56.3.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.50.1...v1.56.3)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-31 19:09:22 +00:00
c8c26897ba Merge pull request #970 from containernetworking/dependabot/go_modules/golang-1eaf3aa819
build(deps): bump the golang group with 3 updates
2023-10-31 20:08:15 +01:00
28c5faee75 build(deps): bump the golang group with 3 updates
Bumps the golang group with 3 updates: [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim), [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) and [github.com/onsi/gomega](https://github.com/onsi/gomega).


Updates `github.com/Microsoft/hcsshim` from 0.11.1 to 0.11.2
- [Release notes](https://github.com/Microsoft/hcsshim/releases)
- [Commits](https://github.com/Microsoft/hcsshim/compare/v0.11.1...v0.11.2)

Updates `github.com/onsi/ginkgo/v2` from 2.12.0 to 2.13.0
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.12.0...v2.13.0)

Updates `github.com/onsi/gomega` from 1.28.0 to 1.29.0
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.28.0...v1.29.0)

---
updated-dependencies:
- dependency-name: github.com/Microsoft/hcsshim
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: golang
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: golang
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-31 15:06:19 +00:00
d0d9e36662 Merge pull request #961 from squeed/dependabot-batch
dependabot: batch updates
2023-10-31 16:04:45 +01:00
f7662a2435 Merge pull request #968 from mmorel-35/patch-1
fix workflow warnings
2023-10-31 11:47:42 +01:00
aacae5c053 dependabot: batch updates
Rather than endless rebases, just batch all go updates to once a week.

Signed-off-by: Casey Callendrello <c1@caseyc.net>
2023-10-31 11:46:29 +01:00
6b7876125d fix workflow warnings
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-10-31 09:07:15 +01:00
2f0faf6721 Merge pull request #967 from squeed/fix-lint
fix lint errors
2023-10-31 08:40:30 +01:00
37531cdaf5 fix lint errors
Fix a small ginkgo compare issue, and ignore dot imports.

Signed-off-by: Casey Callendrello <c1@caseyc.net>
2023-10-30 17:55:55 +01:00
a8d4e0a7dd Merge pull request #949 from containernetworking/dependabot/go_modules/github.com/onsi/gomega-1.28.0
build(deps): bump github.com/onsi/gomega from 1.27.8 to 1.28.0
2023-10-17 12:31:08 +02:00
845ef62b74 macvlan cmdDel: replace the loadConf function with json.unmarshal
When the master interface on the node has been deleted, and loadConf tries
to get the MTU, This causes cmdDel to return a linkNotFound error to the
runtime. The cmdDel only needs to unmarshal the netConf. No need to
get the MTU. So we just replaced the loadConf function with
json.unmarshal in cmdDel.

Signed-off-by: cyclinder <qifeng.guo@daocloud.io>
2023-10-17 10:26:18 +08:00
691186ca7f build(deps): bump github.com/onsi/gomega from 1.27.8 to 1.28.0
Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.27.8 to 1.28.0.
- [Release notes](https://github.com/onsi/gomega/releases)
- [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/gomega/compare/v1.27.8...v1.28.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/gomega
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 15:44:53 +00:00
adaeedd6af Merge pull request #955 from containernetworking/dependabot/go_modules/golang.org/x/net-0.17.0
build(deps): bump golang.org/x/net from 0.10.0 to 0.17.0
2023-10-16 17:43:46 +02:00
19e5747a8c build(deps): bump golang.org/x/net from 0.10.0 to 0.17.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.10.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.10.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 15:26:26 +00:00
4cf3da4ae3 Merge pull request #948 from twz123/posix-sh
build: Use POSIX sh for shell scripts
2023-10-16 17:25:04 +02:00
c20da1521f Merge pull request #952 from containernetworking/dependabot/go_modules/golang.org/x/sys-0.13.0
build(deps): bump golang.org/x/sys from 0.10.0 to 0.13.0
2023-10-16 17:24:51 +02:00
b66b5dd85f Merge pull request #945 from containernetworking/dependabot/github_actions/actions/checkout-4
build(deps): bump actions/checkout from 3 to 4
2023-10-16 17:23:45 +02:00
e727ad6697 Merge pull request #946 from containernetworking/dependabot/go_modules/github.com/Microsoft/hcsshim-0.11.1
build(deps): bump github.com/Microsoft/hcsshim from 0.9.9 to 0.11.1
2023-10-16 17:23:25 +02:00
18172539d8 build(deps): bump github.com/Microsoft/hcsshim from 0.9.9 to 0.11.1
Bumps [github.com/Microsoft/hcsshim](https://github.com/Microsoft/hcsshim) from 0.9.9 to 0.11.1.
- [Release notes](https://github.com/Microsoft/hcsshim/releases)
- [Commits](https://github.com/Microsoft/hcsshim/compare/v0.9.9...v0.11.1)

---
updated-dependencies:
- dependency-name: github.com/Microsoft/hcsshim
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 15:11:01 +00:00
f20b8408a4 Merge pull request #937 from containernetworking/dependabot/go_modules/github.com/coreos/go-iptables-0.7.0
build(deps): bump github.com/coreos/go-iptables from 0.6.0 to 0.7.0
2023-10-16 17:10:05 +02:00
6ff8e5eb86 Merge pull request #950 from ricky-rav/OCPBUGS-16788
Create IPAM files with 0600 permissions
2023-10-12 09:13:05 -05:00
61fa963636 build(deps): bump golang.org/x/sys from 0.10.0 to 0.13.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.10.0 to 0.13.0.
- [Commits](https://github.com/golang/sys/compare/v0.10.0...v0.13.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 02:20:37 +00:00
33ccedc66f Create IPAM files with 0600 permissions
Conform to CIS Benchmarks "1.1.9 Ensure that the Container Network Interface file permissions are set to 600 or more restrictive"
https://www.tenable.com/audits/items/CIS_Kubernetes_v1.20_v1.0.1_Level_1_Master.audit:f1717a5dd65d498074dd41c4a639e47d

Signed-off-by: Riccardo Ravaioli <rravaiol@redhat.com>
2023-10-02 11:59:31 +02:00
853b82d19f build: Use POSIX sh for shell scripts
The scripts didn't really use any bash specific features. Convert
them to POSIX shell scripts, so that the plugins can be built without
requiring bash.

Signed-off-by: Tom Wieczorek <twieczorek@mirantis.com>
2023-09-29 16:57:19 +02:00
d216b0c39b build(deps): bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-11 02:11:46 +00:00
f95505231a Merge pull request #942 from mmorel-35/patch-1
ci(lint) extend timeout to 5 min
2023-09-04 17:18:17 +02:00
5f25a93a47 ci(lint) extend timeout to 5 min
This extends the timeout or golangci-lint execution to 5 min as it is only one minute now it fails for several PR.

Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2023-09-01 20:45:00 +00:00
7c11d48630 build(deps): bump github.com/coreos/go-iptables from 0.6.0 to 0.7.0
Bumps [github.com/coreos/go-iptables](https://github.com/coreos/go-iptables) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/coreos/go-iptables/releases)
- [Commits](https://github.com/coreos/go-iptables/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: github.com/coreos/go-iptables
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-07 02:47:30 +00:00
9d9ec6e3e1 Merge pull request #927 from sockmister/vrf_filter_fix
vrf: fix route filter to use output iface
2023-07-21 13:49:33 +02:00
8fd63065a6 Merge pull request #913 from AlinaSecret/dhcp/fix-race-test
Fix race conditions in DHCP test
2023-07-21 12:55:01 +02:00
c1a7948b19 vrf: fix route filter to use output iface
current route filter uses RT_FILTER_IIF in conjunction with LinkIndex.
This combination is ignored by netlink, rendering the filter
ineffective

Signed-off-by: Poh Chiat Koh <poh@inter.link>
2023-07-21 12:50:21 +02:00
1561794ae9 Merge pull request #924 from SirPhuttel/go-iptables_review
Review code using go-iptables module
2023-07-21 12:23:08 +02:00
fb8ca5d31e Merge pull request #918 from SirPhuttel/rawhide_testing
Two minor testsuite fixes
2023-07-21 12:22:46 +02:00
f2574a7cb1 Merge pull request #926 from containernetworking/dependabot/go_modules/golang.org/x/sys-0.10.0
build(deps): bump golang.org/x/sys from 0.9.0 to 0.10.0
2023-07-21 11:56:30 +02:00
438548a9dd Merge pull request #902 from SirPhuttel/applyconfigecho
spoofcheck: Make use of go-nft's ApplyConfigEcho()
2023-07-20 12:01:18 +02:00
8e69e38d51 test_linux.sh: Do not fail if called twice
The script is set to exit on error, so mkdir failing because
/tmp/cni-rootless already exists aborts the test run. Call 'mkdir -p' to
avoid the spurious error.

Signed-off-by: Phil Sutter <psutter@redhat.com>
2023-07-20 11:34:34 +02:00
0a100e5d8f meta: firewall: Fix firewalld test with non-abstract sockets
On a recent Fedora Rawhide, dbus-daemon-1.14.8-1 prints a string
prefixed by 'unix:path' instead of the expected 'unix:abstract', thereby
failing the test. Allowing this alternate prefix fixes the test, so for
communication with the daemon it is not relevant.

Signed-off-by: Phil Sutter <psutter@redhat.com>
2023-07-20 11:34:34 +02:00
3eb775c5e6 plugins: meta: portmap: Implement a teardown() fast path
Just attempt to delete the known rules referring to the custom chain,
then flush and delete it. If the latter succeeds, no referencing rules
are left and the job is done.

If the final flush'n'delete fails, fall back to the referencing rule
search which is slow with large rulesets.

Signed-off-by: Phil Sutter <psutter@redhat.com>
2023-07-20 11:34:02 +02:00
719f60bb91 utils: iptables: Use go-iptables' ChainExists()
Starting with v0.5.0, go-iptables exports a fast ChainExists() which
does not rely upon listing all chains and searching the results but
probes chain existence by listing its first rule. This should make a
significant difference in rulesets with thousands of chains.

Signed-off-by: Phil Sutter <psutter@redhat.com>
2023-07-20 11:34:02 +02:00
2ba7f1608f spoofcheck: Make use of go-nft's ApplyConfigEcho()
Store the relevant applied config part for later to extract the rule to
delete from there instead of having to list the ruleset. This is much
faster especially with large rulesets.

Signed-off-by: Phil Sutter <psutter@redhat.com>
2023-07-20 11:32:09 +02:00
bf79945c70 Merge pull request #929 from squeed/fix-ci-cnitool-version
test: install binaries using `go install`
2023-07-20 11:26:31 +02:00
ba41448fe6 test: install binaries using go install
We were getting tip- versions of all the tools, and this was unstable.

Signed-off-by: Casey Callendrello <c1@caseyc.net>
2023-07-20 11:15:41 +02:00
13fd3de77f build(deps): bump golang.org/x/sys from 0.9.0 to 0.10.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.9.0 to 0.10.0.
- [Commits](https://github.com/golang/sys/compare/v0.9.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-10 02:29:05 +00:00
283f200489 Merge pull request #897 from containernetworking/dependabot/docker/dot-github/actions/retest-action/alpine-3.18
build(deps): bump alpine from 3.17 to 3.18 in /.github/actions/retest-action
2023-07-03 17:05:49 +02:00
a7e8db00cb Merge pull request #911 from containernetworking/dependabot/go_modules/golang.org/x/sys-0.9.0
build(deps): bump golang.org/x/sys from 0.7.0 to 0.9.0
2023-07-03 17:05:17 +02:00
ffb2e2d7d1 Merge pull request #912 from containernetworking/dependabot/go_modules/github.com/onsi/ginkgo/v2-2.11.0
build(deps): bump github.com/onsi/ginkgo/v2 from 2.9.2 to 2.11.0
2023-07-03 17:05:02 +02:00
d03b84d8f2 Merge pull request #874 from travelping/vrf-add-routes
Add routes propagation for VRF plugin
2023-06-27 12:20:45 +02:00
1512d727cb Merge pull request #914 from tariq1890/tx-qlen
[tuning] add ability to set tx queue len
2023-06-26 17:47:01 +02:00
470eee1385 [tuning]add ability to set tx queue len
Signed-off-by: Tariq Ibrahim <tibrahim@nvidia.com>
2023-06-25 23:28:48 -07:00
2216cff9e8 build(deps): bump github.com/onsi/ginkgo/v2 from 2.9.2 to 2.11.0
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.9.2 to 2.11.0.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.9.2...v2.11.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 02:58:59 +00:00
83029befef build(deps): bump golang.org/x/sys from 0.7.0 to 0.9.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.7.0 to 0.9.0.
- [Commits](https://github.com/golang/sys/compare/v0.7.0...v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 02:58:45 +00:00
48aa2f4eef Fix race conditions in DHCP test
The test named "correctly handles multiple DELs for the same container" in the ipam/dhcp package experiences race conditions when multiple goroutines concurrently access and modify the Args struct (of type CmdArgs).
To address these issues, a copy of the CmdArgs struct is now created in each function to eliminate data races.

Also, the test-linux.sh and test-windows.sh scripts have been updated to include the '-race' flag, enabling race detection during testing. This change helps prevent future race conditions by activating the Go race detector.

Signed-off-by: Alina Sudakov <asudakov@redhat.com>
2023-06-14 17:57:46 +03:00
ca12d49b41 Add routes propagation for VRF plugin
Up until now, if previous plugin assigned routes to interface, movement of
this interface to new VRF cause routes to be deleted.

This patch adds funtionality to VRF plugin to save the routes before
interface is assgined to VRF, and then re-apply all saved routes to new VRF.

Signed-off-by: Artur Korzeniewski <artur.korzeniewski@travelping.com>
2023-06-02 14:21:28 +02:00
2b097c5a62 Merge pull request #900 from squeed/disable-stale
github: remove stale issue cleanup
2023-05-25 10:32:04 +02:00
0389a29052 github: remove stale issue cleanup
In retrospect, this was a bad idea. It's closing too many valid issues.

Signed-off-by: Casey Callendrello <c1@caseyc.net>
2023-05-25 10:31:15 +02:00
6265f4e4ca Merge pull request #832 from maiqueb/tap-plugin-set-as-bridge-port
tap: allow for a tap device to be created as a bridge port
2023-05-22 10:59:28 -05:00
edab9efdea tap: allow for a tap device to be created as a bridge port
This extends the tap plugin API enabling the user to instruct the CNI
plugin the created tap device must be set as a port of an *existing*
linux bridge on the pod network namespace.

This is helpful for KubeVirt, allowing network connectivity to be
extended from the pod's interface into the Virtual Machine running
inside the pod.

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
2023-05-19 16:26:14 +02:00
1b2dc7c2a4 build(deps): bump alpine in /.github/actions/retest-action
Bumps alpine from 3.17 to 3.18.

---
updated-dependencies:
- dependency-name: alpine
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-15 03:01:50 +00:00
982 changed files with 69260 additions and 41528 deletions

View File

@ -1,4 +1,4 @@
FROM alpine:3.17 FROM alpine:3.19
RUN apk add --no-cache curl jq RUN apk add --no-cache curl jq

View File

@ -17,3 +17,7 @@ updates:
directory: "/" # Location of package manifests directory: "/" # Location of package manifests
schedule: schedule:
interval: "weekly" interval: "weekly"
groups:
golang:
patterns:
- "*"

View File

@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out code - name: Check out code
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Re-Test Action - name: Re-Test Action
uses: ./.github/actions/retest-action uses: ./.github/actions/retest-action

106
.github/workflows/release.yaml vendored Normal file
View File

@ -0,0 +1,106 @@
---
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.21
- name: Checkout code
uses: actions/checkout@v4
- name: Build
env:
GOARCH: ${{ matrix.goarch }}
CGO_ENABLED: 0
run: ./build_linux.sh
- name: COPY files
run: cp README.md LICENSE bin/
- name: Create dist directory
run: mkdir dist
- name: Create archive file
working-directory: ./bin
run: tar cfzv ../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
- name: COPY files
run: cp README.md LICENSE bin/
- name: Create dist directory
run: mkdir dist
- name: Create archive file
working-directory: ./bin
run: tar cfzv ../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

View File

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

View File

@ -4,7 +4,7 @@ name: test
on: ["push", "pull_request"] on: ["push", "pull_request"]
env: env:
GO_VERSION: "1.20" GO_VERSION: "1.22"
LINUX_ARCHES: "amd64 386 arm arm64 s390x mips64le ppc64le riscv64" LINUX_ARCHES: "amd64 386 arm arm64 s390x mips64le ppc64le riscv64"
jobs: jobs:
@ -12,28 +12,29 @@ jobs:
name: Lint name: Lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4
- name: setup go - name: setup go
uses: actions/setup-go@v4 uses: actions/setup-go@v5
with: with:
go-version: ${{ env.GO_VERSION }} go-version-file: go.mod
- uses: actions/checkout@v3
- uses: ibiqlik/action-yamllint@v3 - uses: ibiqlik/action-yamllint@v3
with: with:
format: auto format: auto
- uses: golangci/golangci-lint-action@v3 - uses: golangci/golangci-lint-action@v4
with: with:
version: v1.55.2
args: -v args: -v
skip-cache: true
build: build:
name: Build all linux architectures name: Build all linux architectures
needs: lint needs: lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4
- name: setup go - name: setup go
uses: actions/setup-go@v4 uses: actions/setup-go@v5
with: with:
go-version: ${{ env.GO_VERSION }} go-version-file: go.mod
- uses: actions/checkout@v3
- name: Build on all supported architectures - name: Build on all supported architectures
run: | run: |
set -e set -e
@ -53,24 +54,21 @@ jobs:
sudo apt-get install linux-modules-extra-$(uname -r) sudo apt-get install linux-modules-extra-$(uname -r)
- name: Install nftables - name: Install nftables
run: sudo apt-get install nftables run: sudo apt-get install nftables
- uses: actions/checkout@v4
- name: setup go - name: setup go
uses: actions/setup-go@v4 uses: actions/setup-go@v5
with: with:
go-version: ${{ env.GO_VERSION }} go-version-file: go.mod
- name: Set up Go for root - name: Set up Go for root
run: | run: |
sudo ln -sf `which go` `sudo which go` || true sudo ln -sf `which go` `sudo which go` || true
sudo go version sudo go version
- uses: actions/checkout@v3
- name: Install test binaries - name: Install test binaries
env:
GO111MODULE: off
run: | run: |
go get github.com/containernetworking/cni/cnitool go install github.com/containernetworking/cni/cnitool@latest
go get github.com/mattn/goveralls go install github.com/mattn/goveralls@latest
go get github.com/modocache/gover go install github.com/modocache/gover@latest
- name: test - name: test
run: PATH=$PATH:$(go env GOPATH)/bin COVERALLS=1 ./test_linux.sh run: PATH=$PATH:$(go env GOPATH)/bin COVERALLS=1 ./test_linux.sh
@ -87,10 +85,10 @@ jobs:
needs: build needs: build
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v4
- name: setup go - name: setup go
uses: actions/setup-go@v4 uses: actions/setup-go@v5
with: with:
go-version: ${{ env.GO_VERSION }} go-version-file: go.mod
- uses: actions/checkout@v3
- name: test - name: test
run: bash ./test_windows.sh run: bash ./test_windows.sh

View File

@ -6,6 +6,8 @@ issues:
- linters: - linters:
- revive - revive
text: " and that stutters;" text: " and that stutters;"
- path: '(.+)_test\.go'
text: "dot-imports: should not use dot imports"
linters: linters:
disable: disable:
@ -40,3 +42,4 @@ linters-settings:
run: run:
skip-dirs: skip-dirs:
- vendor - vendor
timeout: 5m

View File

@ -1,8 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env sh
set -e set -e
cd "$(dirname "$0")" cd "$(dirname "$0")"
if [ "$(uname)" == "Darwin" ]; then if [ "$(uname)" = "Darwin" ]; then
export GOOS="${GOOS:-linux}" export GOOS="${GOOS:-linux}"
fi fi

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env sh
set -e set -e
cd "$(dirname "$0")" cd "$(dirname "$0")"

40
go.mod
View File

@ -3,42 +3,48 @@ module github.com/containernetworking/plugins
go 1.20 go 1.20
require ( require (
github.com/Microsoft/hcsshim v0.9.9 github.com/Microsoft/hcsshim v0.12.0
github.com/alexflint/go-filemutex v1.2.0 github.com/alexflint/go-filemutex v1.3.0
github.com/buger/jsonparser v1.1.1 github.com/buger/jsonparser v1.1.1
github.com/containernetworking/cni v1.1.2 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/coreos/go-systemd/v22 v22.5.0
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c
github.com/d2g/dhcp4client v1.0.0 github.com/d2g/dhcp4client v1.0.0
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5 github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5
github.com/godbus/dbus/v5 v5.1.0 github.com/godbus/dbus/v5 v5.1.0
github.com/mattn/go-shellwords v1.0.12 github.com/mattn/go-shellwords v1.0.12
github.com/networkplumbing/go-nft v0.3.0 github.com/networkplumbing/go-nft v0.4.0
github.com/onsi/ginkgo/v2 v2.9.2 github.com/onsi/ginkgo/v2 v2.16.0
github.com/onsi/gomega v1.27.6 github.com/onsi/gomega v1.31.1
github.com/opencontainers/selinux v1.11.0 github.com/opencontainers/selinux v1.11.0
github.com/safchain/ethtool v0.3.0 github.com/safchain/ethtool v0.3.0
github.com/vishvananda/netlink v1.2.1-beta.2 github.com/vishvananda/netlink v1.2.1-beta.2
golang.org/x/sys v0.7.0 golang.org/x/sys v0.17.0
) )
require ( require (
github.com/Microsoft/go-winio v0.6.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/cgroups/v3 v3.0.2 // indirect
github.com/go-logr/logr v1.2.4 // 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 v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/go-cmp v0.5.9 // 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-20230323073829-e72429f035bd // indirect github.com/google/pprof v0.0.0-20230323073829-e72429f035bd // indirect
github.com/pkg/errors v0.9.1 // 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/stretchr/testify v1.8.2 // indirect
github.com/vishvananda/netns v0.0.4 // indirect github.com/vishvananda/netns v0.0.4 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
golang.org/x/mod v0.9.0 // indirect golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.8.0 // indirect golang.org/x/net v0.20.0 // indirect
golang.org/x/text v0.8.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.7.0 // indirect golang.org/x/tools v0.17.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.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

939
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@ const (
) )
type NftConfigurer interface { type NftConfigurer interface {
Apply(*nft.Config) error Apply(*nft.Config) (*nft.Config, error)
Read(filterCommands ...string) (*nft.Config, error) Read(filterCommands ...string) (*nft.Config, error)
} }
@ -39,12 +39,16 @@ type SpoofChecker struct {
macAddress string macAddress string
refID string refID string
configurer NftConfigurer configurer NftConfigurer
rulestore *nft.Config
} }
type defaultNftConfigurer struct{} type defaultNftConfigurer struct{}
func (dnc defaultNftConfigurer) Apply(cfg *nft.Config) error { func (dnc defaultNftConfigurer) Apply(cfg *nft.Config) (*nft.Config, error) {
return nft.ApplyConfig(cfg) 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) { 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 { 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 // Setup applies nftables configuration to restrict traffic
@ -88,7 +92,7 @@ func (sc *SpoofChecker) Setup() error {
macChain := sc.macChain(ifaceChain.Name) macChain := sc.macChain(ifaceChain.Name)
baseConfig.AddChain(macChain) 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) return fmt.Errorf("failed to setup spoof-check: %v", err)
} }
@ -102,45 +106,59 @@ func (sc *SpoofChecker) Setup() error {
rulesConfig.AddRule(sc.matchMacRule(macChain.Name)) rulesConfig.AddRule(sc.matchMacRule(macChain.Name))
rulesConfig.AddRule(sc.dropRule(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) return fmt.Errorf("failed to setup spoof-check: %v", err)
} }
sc.rulestore = rulestore
return nil 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. // 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 // The table and base-chain are expected to survive while the base-chain rule that matches the
// interface is removed. // interface is removed.
func (sc *SpoofChecker) Teardown() error { func (sc *SpoofChecker) Teardown() error {
ifaceChain := sc.ifaceChain() ifaceChain := sc.ifaceChain()
currentConfig, ifaceMatchRuleErr := sc.configurer.Read(listChainBridgeNatPrerouting()...)
if ifaceMatchRuleErr == nil {
expectedRuleToFind := sc.matchIfaceJumpToChainRule(preRoutingBaseChainName, ifaceChain.Name) expectedRuleToFind := sc.matchIfaceJumpToChainRule(preRoutingBaseChainName, ifaceChain.Name)
// It is safer to exclude the statement matching, avoiding cases where a current statement includes // It is safer to exclude the statement matching, avoiding cases where a current statement includes
// additional default entries (e.g. counters). // additional default entries (e.g. counters).
ruleToFindExcludingStatements := *expectedRuleToFind ruleToFindExcludingStatements := *expectedRuleToFind
ruleToFindExcludingStatements.Expr = nil ruleToFindExcludingStatements.Expr = nil
rules := currentConfig.LookupRule(&ruleToFindExcludingStatements)
if len(rules) > 0 { rules, ifaceMatchRuleErr := sc.findPreroutingRule(&ruleToFindExcludingStatements)
if ifaceMatchRuleErr == nil && len(rules) > 0 {
c := nft.NewConfig() c := nft.NewConfig()
for _, rule := range rules { for _, rule := range rules {
c.DeleteRule(rule) c.DeleteRule(rule)
} }
if err := sc.configurer.Apply(c); err != nil { if _, err := sc.configurer.Apply(c); err != nil {
ifaceMatchRuleErr = fmt.Errorf("failed to delete iface match rule: %v", err) 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 { } else {
fmt.Fprintf(os.Stderr, "spoofcheck/teardown: unable to detect iface match rule for deletion: %+v", expectedRuleToFind) fmt.Fprintf(os.Stderr, "spoofcheck/teardown: unable to detect iface match rule for deletion: %+v", expectedRuleToFind)
} }
}
regularChainsConfig := nft.NewConfig() regularChainsConfig := nft.NewConfig()
regularChainsConfig.DeleteChain(ifaceChain) regularChainsConfig.DeleteChain(ifaceChain)
regularChainsConfig.DeleteChain(sc.macChain(ifaceChain.Name)) regularChainsConfig.DeleteChain(sc.macChain(ifaceChain.Name))
var regularChainsErr error 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) regularChainsErr = fmt.Errorf("failed to delete regular chains: %v", err)
} }

View File

@ -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) { func assertExpectedRegularChainsDeletionInTeardownConfig(action configurerStub) {
@ -274,21 +293,28 @@ type configurerStub struct {
failFirstApplyConfig bool failFirstApplyConfig bool
failSecondApplyConfig bool failSecondApplyConfig bool
failReadConfig 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++ a.applyCounter++
if a.failFirstApplyConfig && a.applyCounter == 1 { if a.failFirstApplyConfig && a.applyCounter == 1 {
return fmt.Errorf(errorFirstApplyText) return nil, fmt.Errorf(errorFirstApplyText)
} }
if a.failSecondApplyConfig && a.applyCounter == 2 { if a.failSecondApplyConfig && a.applyCounter == 2 {
return fmt.Errorf(errorSecondApplyText) return nil, fmt.Errorf(errorSecondApplyText)
} }
a.applyConfig = append(a.applyConfig, c) 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) { func (a *configurerStub) Read(_ ...string) (*nft.Config, error) {
a.readCalled = true
if a.failReadConfig { if a.failReadConfig {
return nil, fmt.Errorf(errorReadText) return nil, fmt.Errorf(errorReadText)
} }

View File

@ -182,7 +182,7 @@ var _ = Describe("Linux namespace operations", func() {
testNsInode, err := getInodeNS(targetNetNS) testNsInode, err := getInodeNS(targetNetNS)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(testNsInode).NotTo(Equal(0)) Expect(testNsInode).NotTo(Equal(uint64(0)))
Expect(testNsInode).NotTo(Equal(origNSInode)) Expect(testNsInode).NotTo(Equal(origNSInode))
}) })

View File

@ -29,6 +29,7 @@ func envCleanup() {
os.Unsetenv("CNI_NETNS") os.Unsetenv("CNI_NETNS")
os.Unsetenv("CNI_IFNAME") os.Unsetenv("CNI_IFNAME")
os.Unsetenv("CNI_CONTAINERID") os.Unsetenv("CNI_CONTAINERID")
os.Unsetenv("CNI_NETNS_OVERRIDE")
} }
func CmdAdd(cniNetns, cniContainerID, cniIfname string, conf []byte, f func() error) (types.Result, []byte, error) { 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_NETNS", cniNetns)
os.Setenv("CNI_IFNAME", cniIfname) os.Setenv("CNI_IFNAME", cniIfname)
os.Setenv("CNI_CONTAINERID", cniContainerID) os.Setenv("CNI_CONTAINERID", cniContainerID)
os.Setenv("CNI_NETNS_OVERRIDE", "1")
defer envCleanup() defer envCleanup()
// Redirect stdout to capture plugin result // 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_NETNS", cniNetns)
os.Setenv("CNI_IFNAME", cniIfname) os.Setenv("CNI_IFNAME", cniIfname)
os.Setenv("CNI_CONTAINERID", cniContainerID) os.Setenv("CNI_CONTAINERID", cniContainerID)
os.Setenv("CNI_NETNS_OVERRIDE", "1")
defer envCleanup() defer envCleanup()
return f() return f()
@ -102,6 +105,7 @@ func CmdDel(cniNetns, cniContainerID, cniIfname string, f func() error) error {
os.Setenv("CNI_NETNS", cniNetns) os.Setenv("CNI_NETNS", cniNetns)
os.Setenv("CNI_IFNAME", cniIfname) os.Setenv("CNI_IFNAME", cniIfname)
os.Setenv("CNI_CONTAINERID", cniContainerID) os.Setenv("CNI_CONTAINERID", cniContainerID)
os.Setenv("CNI_NETNS_OVERRIDE", "1")
defer envCleanup() defer envCleanup()
return f() return f()

View File

@ -29,9 +29,9 @@ func EnsureChain(ipt *iptables.IPTables, table, chain string) error {
if ipt == nil { if ipt == nil {
return errors.New("failed to ensure iptable chain: IPTables was 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 { 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 { if !exists {
err = ipt.NewChain(table, chain) err = ipt.NewChain(table, chain)
@ -45,24 +45,6 @@ func EnsureChain(ipt *iptables.IPTables, table, chain string) error {
return nil 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. // DeleteRule idempotently delete the iptables rule in the specified table/chain.
// It does not return an error if the referring chain doesn't exist // It does not return an error if the referring chain doesn't exist
func DeleteRule(ipt *iptables.IPTables, table, chain string, rulespec ...string) error { func DeleteRule(ipt *iptables.IPTables, table, chain string, rulespec ...string) error {

View File

@ -332,9 +332,17 @@ var _ = Describe("DHCP Operations", func() {
started.Done() started.Done()
started.Wait() started.Wait()
err = originalNS.Do(func(ns.NetNS) error { err := originalNS.Do(func(ns.NetNS) error {
return testutils.CmdDelWithArgs(args, func() 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()) Expect(err).NotTo(HaveOccurred())

View File

@ -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) { func (s *Store) Reserve(id string, ifname string, ip net.IP, rangeID string) (bool, error) {
fname := GetEscapedPath(s.dataDir, ip.String()) 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) { if os.IsExist(err) {
return false, nil 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 // store the reserved ip in lastIPFile
ipfile := GetEscapedPath(s.dataDir, lastIPFilePrefix+rangeID) 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 { if err != nil {
return false, err return false, err
} }

View File

@ -60,6 +60,7 @@ type NetConf struct {
PreserveDefaultVlan bool `json:"preserveDefaultVlan"` PreserveDefaultVlan bool `json:"preserveDefaultVlan"`
MacSpoofChk bool `json:"macspoofchk,omitempty"` MacSpoofChk bool `json:"macspoofchk,omitempty"`
EnableDad bool `json:"enabledad,omitempty"` EnableDad bool `json:"enabledad,omitempty"`
DisableContainerInterface bool `json:"disableContainerInterface,omitempty"`
Args struct { Args struct {
Cni BridgeArgs `json:"cni,omitempty"` Cni BridgeArgs `json:"cni,omitempty"`
@ -530,6 +531,10 @@ func cmdAdd(args *skel.CmdArgs) error {
isLayer3 := n.IPAM.Type != "" isLayer3 := n.IPAM.Type != ""
if isLayer3 && n.DisableContainerInterface {
return fmt.Errorf("cannot use IPAM when DisableContainerInterface flag is set")
}
if n.IsDefaultGW { if n.IsDefaultGW {
n.IsGW = true n.IsGW = true
} }
@ -629,14 +634,10 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
if n.IsGW { if n.IsGW {
var firstV4Addr net.IP
var vlanInterface *current.Interface var vlanInterface *current.Interface
// Set the IP address(es) on the bridge and enable forwarding // Set the IP address(es) on the bridge and enable forwarding
for _, gws := range []*gwInfo{gwsV4, gwsV6} { for _, gws := range []*gwInfo{gwsV4, gwsV6} {
for _, gw := range gws.gws { for _, gw := range gws.gws {
if gw.IP.To4() != nil && firstV4Addr == nil {
firstV4Addr = gw.IP
}
if n.Vlan != 0 { if n.Vlan != 0 {
vlanIface, err := ensureVlanInterface(br, n.Vlan, n.PreserveDefaultVlan) vlanIface, err := ensureVlanInterface(br, n.Vlan, n.PreserveDefaultVlan)
if err != nil { 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 { if err := netns.Do(func(_ ns.NetNS) error {
link, err := netlink.LinkByName(args.IfName) link, err := netlink.LinkByName(args.IfName)
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve link: %v", err) return fmt.Errorf("failed to retrieve link: %v", err)
} }
// If layer 2 we still need to set the container veth to up // If layer 2 we still need to set the container veth to up
if err = netlink.LinkSetUp(link); err != nil { if err = netlink.LinkSetUp(link); err != nil {
return fmt.Errorf("failed to set %q up: %v", args.IfName, err) return fmt.Errorf("failed to set %q up: %v", args.IfName, err)
@ -696,8 +698,12 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
} }
var hostVeth netlink.Link hostVeth, err := netlink.LinkByName(hostInterface.Name)
if err != nil {
return err
}
if !n.DisableContainerInterface {
// check bridge port state // check bridge port state
retries := []int{0, 50, 500, 1000, 1000} retries := []int{0, 50, 500, 1000, 1000}
for idx, sleep := range retries { for idx, sleep := range retries {
@ -715,6 +721,7 @@ func cmdAdd(args *skel.CmdArgs) error {
return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState) return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState)
} }
} }
}
// In certain circumstances, the host-side of the veth may change addrs // In certain circumstances, the host-side of the veth may change addrs
hostInterface.Mac = hostVeth.Attrs().HardwareAddr.String() hostInterface.Mac = hostVeth.Attrs().HardwareAddr.String()
@ -733,7 +740,7 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
// Use incoming DNS settings if provided, otherwise use the // 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) { if dnsConfSet(n.DNS) {
result.DNS = n.DNS result.DNS = n.DNS
} }
@ -783,7 +790,6 @@ func cmdDel(args *skel.CmdArgs) error {
} }
return err return err
}) })
if err != nil { if err != nil {
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times // 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. // so don't return an error if the device is already removed.

View File

@ -78,6 +78,8 @@ type testCase struct {
removeDefaultVlan bool removeDefaultVlan bool
ipMasq bool ipMasq bool
macspoofchk bool macspoofchk bool
disableContIface bool
AddErr020 string AddErr020 string
DelErr020 string DelErr020 string
AddErr010 string AddErr010 string
@ -154,6 +156,9 @@ const (
netDefault = `, netDefault = `,
"isDefaultGateway": true` "isDefaultGateway": true`
disableContainerInterface = `,
"disableContainerInterface": true`
ipamStartStr = `, ipamStartStr = `,
"ipam": { "ipam": {
"type": "host-local"` "type": "host-local"`
@ -248,6 +253,10 @@ func (tc testCase) netConfJSON(dataDir string) string {
conf += fmt.Sprintf(macspoofchkFormat, tc.macspoofchk) conf += fmt.Sprintf(macspoofchkFormat, tc.macspoofchk)
} }
if tc.disableContIface {
conf += disableContainerInterface
}
if !tc.isLayer2 { if !tc.isLayer2 {
conf += netDefault conf += netDefault
if tc.subnet != "" || tc.ranges != nil { 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(err).NotTo(HaveOccurred())
Expect(link.Attrs().Name).To(Equal(IFNAME)) Expect(link.Attrs().Name).To(Equal(IFNAME))
Expect(link).To(BeAssignableToTypeOf(&netlink.Veth{})) Expect(link).To(BeAssignableToTypeOf(&netlink.Veth{}))
assertContainerInterfaceLinkState(&tc, link)
expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs() expCIDRsV4, expCIDRsV6 := tc.expectedCIDRs()
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) addrs, err := netlink.AddrList(link, netlink.FAMILY_V4)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(addrs).To(HaveLen(len(expCIDRsV4))) Expect(addrs).To(HaveLen(len(expCIDRsV4)))
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6) 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()) Expect(err).NotTo(HaveOccurred())
assertIPv6Addresses(&tc, addrs, expCIDRsV6)
// Ignore link local address which may or may not be // Ignore link local address which may or may not be
// ready when we read addresses. // ready when we read addresses.
var foundAddrs int var foundAddrs int
@ -728,6 +739,15 @@ func (tester *testerV10x) cmdAddTest(tc testCase, dataDir string) (types.Result,
return result, nil 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) { func (tester *testerV10x) cmdCheckTest(tc testCase, conf *Net, _ string) {
// Generate network config and command arguments // Generate network config and command arguments
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf) 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(err).NotTo(HaveOccurred())
Expect(addrs).To(HaveLen(len(expCIDRsV4))) Expect(addrs).To(HaveLen(len(expCIDRsV4)))
addrs, err = netlink.AddrList(link, netlink.FAMILY_V6) 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()) Expect(err).NotTo(HaveOccurred())
assertIPv6Addresses(&tc, addrs, expCIDRsV6)
// Ignore link local address which may or may not be // Ignore link local address which may or may not be
// ready when we read addresses. // ready when we read addresses.
var foundAddrs int var foundAddrs int
@ -1053,6 +1074,14 @@ func (tester *testerV04x) cmdAddTest(tc testCase, dataDir string) (types.Result,
return result, nil 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) { func (tester *testerV04x) cmdCheckTest(tc testCase, conf *Net, _ string) {
// Generate network config and command arguments // Generate network config and command arguments
tester.args = tc.createCheckCmdArgs(tester.targetNS, conf) tester.args = tc.createCheckCmdArgs(tester.targetNS, conf)
@ -2461,6 +2490,36 @@ var _ = Describe("bridge Operations", func() {
return nil return nil
})).To(Succeed()) })).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() { It("check vlan id when loading net conf", func() {

View File

@ -136,7 +136,6 @@ func cmdAdd(args *skel.CmdArgs) error {
err = netns.Do(func(_ ns.NetNS) error { err = netns.Do(func(_ ns.NetNS) error {
return ipam.ConfigureIface(args.IfName, result) return ipam.ConfigureIface(args.IfName, result)
}) })
if err != nil { if err != nil {
return err return err
} }
@ -165,7 +164,6 @@ func cmdDel(args *skel.CmdArgs) error {
} }
return err return err
}) })
if err != nil { if err != nil {
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times // 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. // so don't return an error if the device is already removed.

View File

@ -371,7 +371,7 @@ var _ = Describe("dummy Operations", func() {
StdinData: []byte(fmt.Sprintf(confFmt, ver)), StdinData: []byte(fmt.Sprintf(confFmt, ver)),
} }
_ = originalNS.Do(func(netNS ns.NetNS) error { _ = originalNS.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, _, err = testutils.CmdAddWithArgs(args, func() error { _, _, err = testutils.CmdAddWithArgs(args, func() error {

View File

@ -293,6 +293,7 @@ func cmdAdd(args *skel.CmdArgs) error {
err = netns.Do(func(_ ns.NetNS) 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/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) return ipam.ConfigureIface(args.IfName, result)
}) })
@ -333,7 +334,6 @@ func cmdDel(args *skel.CmdArgs) error {
} }
return nil return nil
}) })
if err != nil { if err != nil {
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times // 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. // so don't return an error if the device is already removed.

View File

@ -351,6 +351,7 @@ func cmdAdd(args *skel.CmdArgs) error {
err = netns.Do(func(_ ns.NetNS) 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/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) return ipam.ConfigureIface(args.IfName, result)
}) })
@ -382,13 +383,13 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
func cmdDel(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 { if err != nil {
return err return fmt.Errorf("failed to load netConf: %v", err)
} }
isLayer3 := n.IPAM.Type != "" isLayer3 := n.IPAM.Type != ""
if isLayer3 { if isLayer3 {
err = ipam.ExecDel(n.IPAM.Type, args.StdinData) err = ipam.ExecDel(n.IPAM.Type, args.StdinData)
if err != nil { if err != nil {
@ -410,7 +411,6 @@ func cmdDel(args *skel.CmdArgs) error {
} }
return nil return nil
}) })
if err != nil { if err != nil {
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times // 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. // so don't return an error if the device is already removed.

View File

@ -47,6 +47,7 @@ type NetConf struct {
Owner *uint32 `json:"owner,omitempty"` Owner *uint32 `json:"owner,omitempty"`
Group *uint32 `json:"group,omitempty"` Group *uint32 `json:"group,omitempty"`
SelinuxContext string `json:"selinuxContext,omitempty"` SelinuxContext string `json:"selinuxContext,omitempty"`
Bridge string `json:"bridge,omitempty"`
Args *struct{} `json:"args,omitempty"` Args *struct{} `json:"args,omitempty"`
RuntimeConfig struct { RuntimeConfig struct {
Mac string `json:"mac,omitempty"` 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) 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) err = netlink.LinkSetUp(link)
if err != nil { if err != nil {
return fmt.Errorf("failed to set tap interface up: %v", err) return fmt.Errorf("failed to set tap interface up: %v", err)
@ -358,7 +371,6 @@ func cmdDel(args *skel.CmdArgs) error {
} }
return nil return nil
}) })
if err != nil { if err != nil {
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times // 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. // so don't return an error if the device is already removed.

View File

@ -314,5 +314,120 @@ var _ = Describe("Add, check, remove tap plugin", func() {
Expect(err).NotTo(HaveOccurred()) 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())
})
} }
}) })

View File

@ -244,7 +244,6 @@ func cmdDel(args *skel.CmdArgs) error {
} }
return err return err
}) })
if err != nil { if err != nil {
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times // 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. // so don't return an error if the device is already removed.

View File

@ -499,7 +499,7 @@ var _ = Describe("vlan Operations", func() {
StdinData: []byte(fmt.Sprintf(confFmt, ver, masterInterface, 1600, isInContainer, dataDir)), 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() defer GinkgoRecover()
_, _, err = testutils.CmdAddWithArgs(args, func() error { _, _, 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)), 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() defer GinkgoRecover()
_, _, err = testutils.CmdAddWithArgs(args, func() error { _, _, err = testutils.CmdAddWithArgs(args, func() error {

View File

@ -165,7 +165,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
r, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) r, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
Expect(err).NotTo(HaveOccurred(), string(out)) Expect(err).NotTo(HaveOccurred(), string(out))
@ -202,7 +202,7 @@ var _ = Describe("bandwidth test", func() {
return nil return nil
})).To(Succeed()) })).To(Succeed())
Expect(hostNs.Do(func(n ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
ifbLink, err := netlink.LinkByName(hostIfname) ifbLink, err := netlink.LinkByName(hostIfname)
@ -260,7 +260,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, ifbDeviceName, []byte(conf), func() error { return cmdAdd(args) }) _, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, ifbDeviceName, []byte(conf), func() error { return cmdAdd(args) })
@ -271,7 +271,7 @@ var _ = Describe("bandwidth test", func() {
return nil return nil
})).To(Succeed()) })).To(Succeed())
Expect(hostNs.Do(func(n ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
containerIfLink, err := netlink.LinkByName(hostIfname) containerIfLink, err := netlink.LinkByName(hostIfname)
@ -327,7 +327,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, ifbDeviceName, []byte(conf), func() error { return cmdAdd(args) }) _, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, ifbDeviceName, []byte(conf), func() error { return cmdAdd(args) })
@ -338,7 +338,7 @@ var _ = Describe("bandwidth test", func() {
return nil return nil
})).To(Succeed()) })).To(Succeed())
Expect(hostNs.Do(func(n ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
containerIfLink, err := netlink.LinkByName(hostIfname) containerIfLink, err := netlink.LinkByName(hostIfname)
@ -396,7 +396,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) _, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
@ -448,7 +448,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
r, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) r, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
Expect(err).NotTo(HaveOccurred(), string(out)) Expect(err).NotTo(HaveOccurred(), string(out))
@ -485,7 +485,7 @@ var _ = Describe("bandwidth test", func() {
return nil return nil
})).To(Succeed()) })).To(Succeed())
Expect(hostNs.Do(func(n ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
ifbLink, err := netlink.LinkByName(hostIfname) ifbLink, err := netlink.LinkByName(hostIfname)
@ -551,7 +551,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) _, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
@ -601,7 +601,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) _, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
Expect(err).NotTo(HaveOccurred(), string(out)) Expect(err).NotTo(HaveOccurred(), string(out))
@ -669,7 +669,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
r, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) r, out, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
Expect(err).NotTo(HaveOccurred(), string(out)) Expect(err).NotTo(HaveOccurred(), string(out))
@ -706,7 +706,7 @@ var _ = Describe("bandwidth test", func() {
return nil return nil
})).To(Succeed()) })).To(Succeed())
Expect(hostNs.Do(func(n ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
ifbLink, err := netlink.LinkByName(hostIfname) ifbLink, err := netlink.LinkByName(hostIfname)
@ -768,7 +768,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) _, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
@ -801,7 +801,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) _, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })
@ -853,7 +853,7 @@ var _ = Describe("bandwidth test", func() {
StdinData: []byte(conf), StdinData: []byte(conf),
} }
Expect(hostNs.Do(func(netNS ns.NetNS) error { Expect(hostNs.Do(func(_ ns.NetNS) error {
defer GinkgoRecover() defer GinkgoRecover()
_, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) }) _, _, err := testutils.CmdAdd(containerNs.Path(), args.ContainerID, "", []byte(conf), func() error { return cmdAdd(args) })

View File

@ -86,7 +86,8 @@ func spawnSessionDbus(wg *sync.WaitGroup) (string, *exec.Cmd) {
bytes, err := bufio.NewReader(stdout).ReadString('\n') bytes, err := bufio.NewReader(stdout).ReadString('\n')
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
busAddr := strings.TrimSpace(bytes) 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 var startWg sync.WaitGroup
wg.Add(1) wg.Add(1)

View File

@ -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. // 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. // It will first delete all references to this chain in the entryChains.
func (c *chain) teardown(ipt *iptables.IPTables) error { func (c *chain) teardown(ipt *iptables.IPTables) error {
// flush the chain // nothing to do if the custom chain doesn't exist to begin with
// This will succeed *and create the chain* if it does not exist. exists, err := ipt.ChainExists(c.table, c.name)
// If the chain doesn't exist, the next checks will fail. if err == nil && !exists {
if err := utils.ClearChain(ipt, c.table, c.name); err != nil { return nil
return err }
// 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 { for _, entryChain := range c.entryChains {
entryChainRules, err := ipt.List(c.table, entryChain) entryChainRules, err := ipt.List(c.table, entryChain)
if err != nil || len(entryChainRules) < 1 { 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. // check the chain.
func (c *chain) check(ipt *iptables.IPTables) error { 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 { if err != nil {
return err return err
} }

View File

@ -66,7 +66,6 @@ func withLockAndNetNS(nspath string, toRun func(_ ns.NetNS) error) error {
} }
err = ns.WithNetNSPath(nspath, toRun) err = ns.WithNetNSPath(nspath, toRun)
if err != nil { if err != nil {
return err return err
} }

View File

@ -53,6 +53,7 @@ type TuningConf struct {
Mac string `json:"mac,omitempty"` Mac string `json:"mac,omitempty"`
Promisc bool `json:"promisc,omitempty"` Promisc bool `json:"promisc,omitempty"`
Mtu int `json:"mtu,omitempty"` Mtu int `json:"mtu,omitempty"`
TxQLen *int `json:"txQLen,omitempty"`
Allmulti *bool `json:"allmulti,omitempty"` Allmulti *bool `json:"allmulti,omitempty"`
RuntimeConfig struct { RuntimeConfig struct {
@ -69,6 +70,7 @@ type IPAMArgs struct {
Promisc *bool `json:"promisc,omitempty"` Promisc *bool `json:"promisc,omitempty"`
Mtu *int `json:"mtu,omitempty"` Mtu *int `json:"mtu,omitempty"`
Allmulti *bool `json:"allmulti,omitempty"` Allmulti *bool `json:"allmulti,omitempty"`
TxQLen *int `json:"txQLen,omitempty"`
} }
// configToRestore will contain interface attributes that should be restored on cmdDel // configToRestore will contain interface attributes that should be restored on cmdDel
@ -77,6 +79,7 @@ type configToRestore struct {
Promisc *bool `json:"promisc,omitempty"` Promisc *bool `json:"promisc,omitempty"`
Mtu int `json:"mtu,omitempty"` Mtu int `json:"mtu,omitempty"`
Allmulti *bool `json:"allmulti,omitempty"` Allmulti *bool `json:"allmulti,omitempty"`
TxQLen *int `json:"txQLen,omitempty"`
} }
// MacEnvArgs represents CNI_ARG // MacEnvArgs represents CNI_ARG
@ -136,6 +139,10 @@ func parseConf(data []byte, envArgs string) (*TuningConf, error) {
if conf.Args.A.Allmulti != nil { if conf.Args.A.Allmulti != nil {
conf.Allmulti = conf.Args.A.Allmulti conf.Allmulti = conf.Args.A.Allmulti
} }
if conf.Args.A.TxQLen != nil {
conf.TxQLen = conf.Args.A.TxQLen
}
} }
return &conf, nil return &conf, nil
@ -204,6 +211,14 @@ func changeAllmulti(ifName string, val bool) error {
return netlink.LinkSetAllmulticastOff(link) 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 { func createBackup(ifName, containerID, backupPath string, tuningConf *TuningConf) error {
config := configToRestore{} config := configToRestore{}
link, err := netlink.LinkByName(ifName) link, err := netlink.LinkByName(ifName)
@ -224,6 +239,10 @@ func createBackup(ifName, containerID, backupPath string, tuningConf *TuningConf
config.Allmulti = new(bool) config.Allmulti = new(bool)
*config.Allmulti = (link.Attrs().RawFlags&unix.IFF_ALLMULTI != 0) *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.Stat(backupPath); os.IsNotExist(err) {
if err = os.MkdirAll(backupPath, 0o600); err != nil { 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 { if len(errStr) > 0 {
return fmt.Errorf(strings.Join(errStr, "; ")) 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 { if err = createBackup(args.IfName, args.ContainerID, tuningConf.DataDir, tuningConf); err != nil {
return err return err
} }
@ -377,6 +403,12 @@ func cmdAdd(args *skel.CmdArgs) error {
return err return err
} }
} }
if tuningConf.TxQLen != nil {
if err = changeTxQLen(args.IfName, *tuningConf.TxQLen); err != nil {
return err
}
}
return nil return nil
}) })
if err != nil { if err != nil {
@ -483,6 +515,13 @@ func cmdCheck(args *skel.CmdArgs) error {
args.IfName, tuningConf.Allmulti, allmulti) 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 return nil
}) })
if err != nil { if err != nil {

View File

@ -125,6 +125,8 @@ var _ = Describe("tuning plugin", func() {
*beforeConf.Promisc = (link.Attrs().Promisc != 0) *beforeConf.Promisc = (link.Attrs().Promisc != 0)
beforeConf.Allmulti = new(bool) beforeConf.Allmulti = new(bool)
*beforeConf.Allmulti = (link.Attrs().RawFlags&unix.IFF_ALLMULTI != 0) *beforeConf.Allmulti = (link.Attrs().RawFlags&unix.IFF_ALLMULTI != 0)
beforeConf.TxQLen = new(int)
*beforeConf.TxQLen = link.Attrs().TxQLen
return nil return nil
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -487,6 +489,138 @@ var _ = Describe("tuning plugin", func() {
Expect(err).NotTo(HaveOccurred()) 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() { It(fmt.Sprintf("[%s] configures and deconfigures mac address (from conf file) with ADD/DEL", ver), func() {
mac := "c2:11:22:33:44:55" mac := "c2:11:22:33:44:55"
conf := []byte(fmt.Sprintf(`{ conf := []byte(fmt.Sprintf(`{
@ -780,7 +914,7 @@ var _ = Describe("tuning plugin", func() {
Expect(err).NotTo(HaveOccurred()) 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(`{ conf := []byte(fmt.Sprintf(`{
"name": "test", "name": "test",
"type": "iplink", "type": "iplink",
@ -788,6 +922,7 @@ var _ = Describe("tuning plugin", func() {
"mac": "c2:11:22:33:44:77", "mac": "c2:11:22:33:44:77",
"promisc": true, "promisc": true,
"mtu": 4000, "mtu": 4000,
"txQLen": 20000,
"dataDir": "/tmp/tuning-test", "dataDir": "/tmp/tuning-test",
"prevResult": { "prevResult": {
"interfaces": [ "interfaces": [
@ -834,6 +969,7 @@ var _ = Describe("tuning plugin", func() {
Expect(link.Attrs().HardwareAddr).To(Equal(hw)) Expect(link.Attrs().HardwareAddr).To(Equal(hw))
Expect(link.Attrs().Promisc).To(Equal(1)) Expect(link.Attrs().Promisc).To(Equal(1))
Expect(link.Attrs().MTU).To(Equal(4000)) Expect(link.Attrs().MTU).To(Equal(4000))
Expect(link.Attrs().TxQLen).To(Equal(20000))
Expect("/tmp/tuning-test/dummy_dummy0.json").Should(BeAnExistingFile()) 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().HardwareAddr.String()).To(Equal(beforeConf.Mac))
Expect(link.Attrs().MTU).To(Equal(beforeConf.Mtu)) Expect(link.Attrs().MTU).To(Equal(beforeConf.Mtu))
Expect(link.Attrs().Promisc != 0).To(Equal(*beforeConf.Promisc)) Expect(link.Attrs().Promisc != 0).To(Equal(*beforeConf.Promisc))
Expect(link.Attrs().TxQLen).To(Equal(*beforeConf.TxQLen))
return nil return nil
}) })

View File

@ -75,7 +75,6 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
return nil return nil
}) })
if err != nil { if err != nil {
return fmt.Errorf("cmdAdd failed: %v", err) return fmt.Errorf("cmdAdd failed: %v", err)
} }
@ -121,7 +120,6 @@ func cmdDel(args *skel.CmdArgs) error {
} }
return nil return nil
}) })
if err != nil { if err != nil {
// if NetNs is passed down by the Cloud Orchestration Engine, or if it called multiple times // 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. // so don't return an error if the device is already removed.

View File

@ -104,6 +104,19 @@ func addInterface(vrf *netlink.Vrf, intf string) error {
if err != nil { if err != nil {
return fmt.Errorf("failed getting ipv6 addresses for %s", intf) 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) err = netlink.LinkSetMaster(i, vrf)
if err != nil { if err != nil {
return fmt.Errorf("could not set vrf %s as master of %s: %v", vrf.Name, intf, err) 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 return nil
} }

View File

@ -17,6 +17,8 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net"
"strings"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -107,7 +109,7 @@ var _ = Describe("vrf plugin", func() {
}, },
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
_, err = netlink.LinkByName(IF0Name) _, err = netlink.LinkByName(IF1Name)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
return nil return nil
}) })
@ -177,6 +179,256 @@ var _ = Describe("vrf plugin", func() {
Expect(err).NotTo(HaveOccurred()) 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() { It("fails if the interface already has a master set", func() {
conf := configFor("test", IF0Name, VRF0Name, "10.0.0.2/24") 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) 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) { func checkInterfaceOnVRF(vrfName, intfName string) {
vrf, err := netlink.LinkByName(vrfName) vrf, err := netlink.LinkByName(vrfName)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@ -702,3 +983,46 @@ func checkInterfaceOnVRF(vrfName, intfName string) {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(master.Attrs().Name).To(Equal(vrfName)) 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))
}
}

View File

@ -1,8 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env sh
set -xe set -xe
SRC_DIR="${SRC_DIR:-$PWD}" SRC_DIR="${SRC_DIR:-$PWD}"
DOCKER="${DOCKER:-docker}" DOCKER="${DOCKER:-docker}"
GOLANG="${GOLANG:-golang:1.22-alpine}"
TAG=$(git describe --tags --dirty) TAG=$(git describe --tags --dirty)
RELEASE_DIR=release-${TAG} RELEASE_DIR=release-${TAG}
@ -16,7 +17,7 @@ rm -Rf ${SRC_DIR}/${RELEASE_DIR}
mkdir -p ${SRC_DIR}/${RELEASE_DIR} mkdir -p ${SRC_DIR}/${RELEASE_DIR}
mkdir -p ${OUTPUT_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 "\ /bin/sh -xe -c "\
apk --no-cache add bash tar; apk --no-cache add bash tar;
cd /go/src/github.com/containernetworking/plugins; umask 0022; cd /go/src/github.com/containernetworking/plugins; umask 0022;

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env sh
# #
# Run CNI plugin tests. # Run CNI plugin tests.
# #
@ -10,12 +10,12 @@ set -e
cd "$(dirname "$0")" cd "$(dirname "$0")"
# Build all plugins before testing # Build all plugins before testing
source ./build_linux.sh . ./build_linux.sh
echo "Running tests" echo "Running tests"
function testrun { testrun() {
sudo -E bash -c "umask 0; PATH=${GOPATH}/bin:$(pwd)/bin:${PATH} go test $@" sudo -E sh -c "umask 0; PATH=${GOPATH}/bin:$(pwd)/bin:${PATH} go test -race $*"
} }
COVERALLS=${COVERALLS:-""} COVERALLS=${COVERALLS:-""}
@ -31,7 +31,7 @@ PKG=${PKG:-$(go list ./... | xargs echo)}
i=0 i=0
for t in ${PKG}; do for t in ${PKG}; do
if [ -n "${COVERALLS}" ]; then if [ -n "${COVERALLS}" ]; then
COVERFLAGS="-covermode set -coverprofile ${i}.coverprofile" COVERFLAGS="-covermode atomic -coverprofile ${i}.coverprofile"
fi fi
echo "${t}" echo "${t}"
testrun "${COVERFLAGS:-""} ${t}" testrun "${COVERFLAGS:-""} ${t}"
@ -39,5 +39,5 @@ for t in ${PKG}; do
done done
# Run the pkg/ns tests as non root user # 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) (export XDG_RUNTIME_DIR=/tmp/cni-rootless; cd pkg/ns/; unshare -rmn go test)

View File

@ -1,11 +1,11 @@
#!/usr/bin/env bash #!/usr/bin/env sh
# #
# Run CNI plugin tests. # Run CNI plugin tests.
# #
set -e set -e
cd "$(dirname "$0")" cd "$(dirname "$0")"
source ./build_windows.sh . ./build_windows.sh
echo "Running tests" echo "Running tests"
@ -17,4 +17,4 @@ for d in $PLUGINS; do
done done
echo "testing packages $PKGS" 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

View File

@ -8,12 +8,8 @@ linters:
- containedctx # struct contains a context - containedctx # struct contains a context
- dupl # duplicate code - dupl # duplicate code
- errname # erorrs are named correctly - errname # erorrs are named correctly
- goconst # strings that should be constants
- godot # comments end in a period
- misspell
- nolintlint # "//nolint" directives are properly explained - nolintlint # "//nolint" directives are properly explained
- revive # golint replacement - revive # golint replacement
- stylecheck # golint replacement, less configurable than revive
- unconvert # unnecessary conversions - unconvert # unnecessary conversions
- wastedassign - wastedassign
@ -23,10 +19,7 @@ linters:
- exhaustive # check exhaustiveness of enum switch statements - exhaustive # check exhaustiveness of enum switch statements
- gofmt # files are gofmt'ed - gofmt # files are gofmt'ed
- gosec # security - gosec # security
- nestif # deeply nested ifs
- nilerr # returns nil even with non-nil error - nilerr # returns nil even with non-nil error
- prealloc # slices that can be pre-allocated
- structcheck # unused struct fields
- unparam # unused function params - unparam # unused function params
issues: issues:
@ -42,6 +35,18 @@ issues:
text: "^line-length-limit: " text: "^line-length-limit: "
source: "^//(go:generate|sys) " 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 # allow unjustified ignores of error checks in defer statements
- linters: - linters:
- nolintlint - nolintlint
@ -56,6 +61,8 @@ issues:
linters-settings: linters-settings:
exhaustive:
default-signifies-exhaustive: true
govet: govet:
enable-all: true enable-all: true
disable: disable:
@ -98,6 +105,8 @@ linters-settings:
disabled: true disabled: true
- name: flag-parameter # excessive, and a common idiom we use - name: flag-parameter # excessive, and a common idiom we use
disabled: true disabled: true
- name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
disabled: true
# general config # general config
- name: line-length-limit - name: line-length-limit
arguments: arguments:
@ -138,7 +147,3 @@ linters-settings:
- VPCI - VPCI
- WCOW - WCOW
- WIM - WIM
stylecheck:
checks:
- "all"
- "-ST1003" # use revive's var naming

View File

@ -23,7 +23,7 @@ import (
const afHVSock = 34 // AF_HYPERV const afHVSock = 34 // AF_HYPERV
// Well known Service and VM IDs // 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. // HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000 func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
@ -31,7 +31,7 @@ func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
} }
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions. // 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{ return guid.GUID{
Data1: 0xffffffff, Data1: 0xffffffff,
Data2: 0xffff, Data2: 0xffff,
@ -246,7 +246,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
var addrbuf [addrlen * 2]byte var addrbuf [addrlen * 2]byte
var bytes uint32 var bytes uint32
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /*rxdatalen*/, addrlen, addrlen, &bytes, &c.o) err = syscall.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 { if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err)) return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
} }

View File

@ -0,0 +1,2 @@
// This package contains Win32 filesystem functionality.
package fs

202
vendor/github.com/Microsoft/go-winio/internal/fs/fs.go generated vendored Normal file
View File

@ -0,0 +1,202 @@
//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 *syscall.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.
//
// 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
// 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
)
// 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
)
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 = 0x00100000
SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F0000
)
// 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
}
}

View 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
)

View File

@ -0,0 +1,64 @@
//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
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procCreateFileW = modkernel32.NewProc("CreateFileW")
)
func CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.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 *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.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 = windows.Handle(r0)
if handle == windows.InvalidHandle {
err = errnoErr(e1)
}
return
}

View File

@ -100,8 +100,8 @@ func (f *runtimeFunc) Load() error {
(*byte)(unsafe.Pointer(&f.addr)), (*byte)(unsafe.Pointer(&f.addr)),
uint32(unsafe.Sizeof(f.addr)), uint32(unsafe.Sizeof(f.addr)),
&n, &n,
nil, //overlapped nil, // overlapped
0, //completionRoutine 0, // completionRoutine
) )
}) })
return f.err return f.err

View 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 {
// allready 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 }

View File

@ -16,11 +16,12 @@ import (
"unsafe" "unsafe"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/fs"
) )
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe //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 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 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 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 localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
@ -163,19 +164,21 @@ func (s pipeAddress) String() string {
} }
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout. // 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) (syscall.Handle, error) {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return syscall.Handle(0), ctx.Err() return syscall.Handle(0), ctx.Err()
default: default:
h, err := createFile(*path, wh, err := fs.CreateFile(*path,
access, access,
0, 0, // mode
nil, nil, // security attributes
syscall.OPEN_EXISTING, fs.OPEN_EXISTING,
windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS, fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.SECURITY_ANONYMOUS,
0) 0, // template file handle
)
h := syscall.Handle(wh)
if err == nil { if err == nil {
return h, nil return h, nil
} }
@ -219,7 +222,7 @@ func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) { func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
var err error var err error
var h syscall.Handle var h syscall.Handle
h, err = tryDialPipe(ctx, &path, access) h, err = tryDialPipe(ctx, &path, fs.AccessMask(access))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -279,6 +282,7 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
} }
defer localFree(ntPath.Buffer) defer localFree(ntPath.Buffer)
oa.ObjectName = &ntPath oa.ObjectName = &ntPath
oa.Attributes = windows.OBJ_CASE_INSENSITIVE
// The security descriptor is only needed for the first pipe. // The security descriptor is only needed for the first pipe.
if first { if first {

View File

@ -63,7 +63,6 @@ var (
procBackupWrite = modkernel32.NewProc("BackupWrite") procBackupWrite = modkernel32.NewProc("BackupWrite")
procCancelIoEx = modkernel32.NewProc("CancelIoEx") procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateFileW = modkernel32.NewProc("CreateFileW")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
@ -305,24 +304,6 @@ func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
return 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) { 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) r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
newport = syscall.Handle(r0) newport = syscall.Handle(r0)

View File

@ -1 +1,3 @@
* text=auto eol=lf * text=auto eol=lf
vendor/** -text
test/vendor/** -text

View File

@ -6,6 +6,7 @@
# Ignore vscode setting files # Ignore vscode setting files
.vscode/ .vscode/
.idea/
# Test binary, build with `go test -c` # Test binary, build with `go test -c`
*.test *.test
@ -23,16 +24,30 @@ service/pkg/
*.img *.img
*.vhd *.vhd
*.tar.gz *.tar.gz
*.tar
# Make stuff # Make stuff
.rootfs-done .rootfs-done
bin/* bin/*
rootfs/* rootfs/*
rootfs-conv/*
*.o *.o
/build/ /build/
deps/* deps/*
out/* out/*
.idea/ # protobuf files
.vscode/ # 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

View File

@ -1,23 +1,72 @@
run: run:
timeout: 8m timeout: 8m
tests: true
build-tags:
- admin
- functional
- integration
skip-dirs:
# paths are relative to module root
- cri-containerd/test-images
linters: linters:
enable: 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: 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: stylecheck:
# https://staticcheck.io/docs/checks # https://staticcheck.io/docs/checks
checks: ["all"] checks: ["all"]
issues: 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: 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 - path: layer.go
linters: linters:
- stylecheck - stylecheck
@ -28,11 +77,21 @@ issues:
- stylecheck - stylecheck
Text: "ST1003:" Text: "ST1003:"
- path: internal\\hcs\\schema2\\ - path: cmd\\ncproxy\\nodenetsvc\\
linters: linters:
- stylecheck - stylecheck
Text: "ST1003:" Text: "ST1003:"
- path: cmd\\ncproxy_mock\\
linters:
- stylecheck
Text: "ST1003:"
- path: internal\\hcs\\schema2\\
linters:
- stylecheck
- gofmt
- path: internal\\wclayer\\ - path: internal\\wclayer\\
linters: linters:
- stylecheck - stylecheck
@ -97,3 +156,19 @@ issues:
linters: linters:
- stylecheck - 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:"

View File

@ -1,4 +1,5 @@
BASE:=base.tar.gz BASE:=base.tar.gz
DEV_BUILD:=0
GO:=go GO:=go
GO_FLAGS:=-ldflags "-s -w" # strip Go binaries GO_FLAGS:=-ldflags "-s -w" # strip Go binaries
@ -12,15 +13,41 @@ GO_FLAGS_EXTRA:=
ifeq "$(GOMODVENDOR)" "1" ifeq "$(GOMODVENDOR)" "1"
GO_FLAGS_EXTRA += -mod=vendor GO_FLAGS_EXTRA += -mod=vendor
endif 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) GO_BUILD:=CGO_ENABLED=$(CGO_ENABLED) $(GO) build $(GO_FLAGS) $(GO_FLAGS_EXTRA)
SRCROOT=$(dir $(abspath $(firstword $(MAKEFILE_LIST)))) 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 # The link aliases for gcstools
GCS_TOOLS=\ 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 all: out/initrd.img out/rootfs.tar.gz
@ -29,21 +56,62 @@ clean:
rm -rf bin deps rootfs out rm -rf bin deps rootfs out
test: 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 rootfs: out/rootfs.vhd
@mkdir -p out
rm -rf rootfs snp: out/kernelinitrd.vmgs out/rootfs.hash.vhd out/rootfs.vhd out/v2056.vmgs
mkdir -p rootfs/bin/
cp bin/init rootfs/ simple: out/simple.vmgs snp
cp bin/vsockexec rootfs/bin/
cp bin/cmd/gcs rootfs/bin/ %.vmgs: %.bin
cp bin/cmd/gcstools rootfs/bin/ rm -f $@
for tool in $(GCS_TOOLS); do ln -s gcstools rootfs/bin/$$tool; done # 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
git -C $(SRCROOT) rev-parse HEAD > rootfs/gcs.commit && \ $(PATH_PREFIX)/$(VMGS_TOOL) create --filepath $@ --filesize `du -BM $< | sed "s/M.*/*1024*1024/" | bc`
git -C $(SRCROOT) rev-parse --abbrev-ref HEAD > rootfs/gcs.branch $(PATH_PREFIX)/$(VMGS_TOOL) write --filepath $@ --datapath $< -i=8
tar -zcf $@ -C rootfs .
rm -rf rootfs # 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 out/rootfs.tar.gz: out/initrd.img
rm -rf rootfs-conv rm -rf rootfs-conv
@ -52,27 +120,60 @@ out/rootfs.tar.gz: out/initrd.img
tar -zcf $@ -C rootfs-conv . tar -zcf $@ -C rootfs-conv .
rm -rf rootfs-conv rm -rf rootfs-conv
out/initrd.img: $(BASE) out/delta.tar.gz $(SRCROOT)/hack/catcpio.sh out/initrd.img: $(BASE) $(DELTA_TARGET) $(SRCROOT)/hack/catcpio.sh
$(SRCROOT)/hack/catcpio.sh "$(BASE)" out/delta.tar.gz > out/initrd.img.uncompressed $(SRCROOT)/hack/catcpio.sh "$(BASE)" $(DELTA_TARGET) > out/initrd.img.uncompressed
gzip -c out/initrd.img.uncompressed > $@ gzip -c out/initrd.img.uncompressed > $@
rm out/initrd.img.uncompressed rm out/initrd.img.uncompressed
-include deps/cmd/gcs.gomake # This target includes utilities which may be useful for testing purposes.
-include deps/cmd/gcstools.gomake 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. 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
%.gomake: $(SRCROOT)/Makefile 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 $@) @mkdir -p $(dir $@)
@/bin/echo $(@:deps/%.gomake=bin/%): $(SRCROOT)/hack/gomakedeps.sh > $@.new GOOS=linux $(GO_BUILD) -o $@ $(SRCROOT)/$(@:bin/%=%)
@/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)
bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o bin/vsockexec: vsockexec/vsockexec.o vsockexec/vsock.o
@mkdir -p bin @mkdir -p bin

View File

@ -1,49 +1,25 @@
version = "unstable" version = "2"
generator = "gogoctrd" generators = ["go", "go-grpc"]
plugins = ["grpc", "fieldpath"]
# Control protoc include paths. Below are usually some good defaults, but feel # Control protoc include paths.
# free to try it without them if it works for your project.
[includes] [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"] before = ["./protobuf"]
# Paths that should be treated as include roots in relation to the vendor # defaults are "/usr/local/include" and "/usr/include", which don't exist on Windows.
# directory. These will be calculated with the vendor directory nearest the # override defaults to supress errors about non-existant directories.
# target package. after = []
packages = ["github.com/gogo/protobuf"]
# Paths that will be added untouched to the end of the includes. We use # This section maps protobuf imports to Go packages.
# `/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.
[packages] [packages]
"gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto" # github.com/containerd/cgroups protofiles still list their go path as "github.com/containerd/cgroups/cgroup1/stats"
"google/protobuf/any.proto" = "github.com/gogo/protobuf/types" "github.com/containerd/cgroups/v3/cgroup1/stats/metrics.proto" = "github.com/containerd/cgroups/v3/cgroup1/stats"
"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"
[[overrides]] [[overrides]]
prefixes = ["github.com/Microsoft/hcsshim/internal/shimdiag"] prefixes = [
plugins = ["ttrpc"] "github.com/Microsoft/hcsshim/internal/shimdiag",
"github.com/Microsoft/hcsshim/internal/extendedtask",
[[overrides]] "github.com/Microsoft/hcsshim/internal/computeagent",
prefixes = ["github.com/Microsoft/hcsshim/internal/computeagent"] "github.com/Microsoft/hcsshim/internal/ncproxyttrpc",
plugins = ["ttrpc"] "github.com/Microsoft/hcsshim/internal/vmservice",
]
[[overrides]] generators = ["go", "go-ttrpc"]
prefixes = ["github.com/Microsoft/hcsshim/internal/ncproxyttrpc"]
plugins = ["ttrpc"]
[[overrides]]
prefixes = ["github.com/Microsoft/hcsshim/internal/vmservice"]
plugins = ["ttrpc"]

View File

@ -9,15 +9,18 @@ It is primarily used in the [Moby](https://github.com/moby/moby) and [Containerd
## Building ## 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). 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 ### 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. 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 ```powershell
C:\> $env:GOOS="linux" C:\> $env:GOOS="linux"
C:\> go build .\cmd\gcs\ C:\> go build .\cmd\gcs\
``` ```
or on a Linux machine or on a Linux machine
```sh ```sh
> go build ./cmd/gcs > go build ./cmd/gcs
``` ```
@ -33,13 +36,15 @@ make all
``` ```
If the build is successful, in the `./out` folder you should see: If the build is successful, in the `./out` folder you should see:
```sh ```sh
> ls ./out/ > ls ./out/
delta.tar.gz initrd.img rootfs.tar.gz delta.tar.gz initrd.img rootfs.tar.gz
``` ```
### Containerd Shim ### 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. 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 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 ```powershell
.\containerd.exe config default | Out-File "C:\Program Files\containerd\config.toml" -Encoding ascii .\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. 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: To trial using the shim out with ctr.exe:
```powershell ```powershell
C:\> ctr.exe run --runtime io.containerd.runhcs.v1 --rm mcr.microsoft.com/windows/nanoserver:2004 windows-test cmd /c "echo Hello World!" 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 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 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 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 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. 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 We require that contributors sign their commits
certify they either authored the work themselves or otherwise have permission to use it in this project. Please see https://developercertificate.org/ for to certify they either authored the work themselves or otherwise have permission to use it in this project.
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.
### 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 Please see [the developer certificate](https://developercertificate.org) for more info,
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 as well as to make sure that you can attest to the rules listed.
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 Our CI uses the [DCO Github app](https://github.com/apps/dco) to ensure that all commits in a given PR are signed-off.
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).
``` ### Linting
replace (
github.com/Microsoft/hcsshim => ../ 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 Additional editor [integrations options are also available][lint-ide].
CI in this project will check if the files are out of date and will fail if this is true.
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 ## Code of Conduct
@ -101,7 +144,7 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio
## Dependencies ## 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). 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. 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
View 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 -->

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -17,8 +19,8 @@ import (
// //
// `layerData` is the parent read-only layer data. // `layerData` is the parent read-only layer data.
func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) { func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData LayerData) (err error) {
title := "hcsshim.AttachLayerStorageFilter" title := "hcsshim::AttachLayerStorageFilter"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -36,3 +38,31 @@ func AttachLayerStorageFilter(ctx context.Context, layerPath string, layerData L
} }
return nil 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
}

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -12,8 +14,8 @@ import (
// //
// `layerPath` is a path to a directory containing the layer to export. // `layerPath` is a path to a directory containing the layer to export.
func DestroyLayer(ctx context.Context, layerPath string) (err error) { func DestroyLayer(ctx context.Context, layerPath string) (err error) {
title := "hcsshim.DestroyLayer" title := "hcsshim::DestroyLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("layerPath", layerPath)) span.AddAttributes(trace.StringAttribute("layerPath", layerPath))

View File

@ -1,8 +1,12 @@
//go:build windows
package computestorage package computestorage
import ( import (
"context" "context"
"encoding/json"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
"github.com/Microsoft/hcsshim/internal/oc" "github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.opencensus.io/trace" "go.opencensus.io/trace"
@ -12,8 +16,8 @@ import (
// //
// `layerPath` is a path to a directory containing the layer to export. // `layerPath` is a path to a directory containing the layer to export.
func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) { func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error) {
title := "hcsshim.DetachLayerStorageFilter" title := "hcsshim::DetachLayerStorageFilter"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(trace.StringAttribute("layerPath", layerPath)) span.AddAttributes(trace.StringAttribute("layerPath", layerPath))
@ -24,3 +28,27 @@ func DetachLayerStorageFilter(ctx context.Context, layerPath string) (err error)
} }
return nil 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
}

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -19,8 +21,8 @@ import (
// //
// `options` are the export options applied to the exported layer. // `options` are the export options applied to the exported layer.
func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) { func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerData LayerData, options ExportLayerOptions) (err error) {
title := "hcsshim.ExportLayer" title := "hcsshim::ExportLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -28,17 +30,17 @@ func ExportLayer(ctx context.Context, layerPath, exportFolderPath string, layerD
trace.StringAttribute("exportFolderPath", exportFolderPath), trace.StringAttribute("exportFolderPath", exportFolderPath),
) )
ldbytes, err := json.Marshal(layerData) ldBytes, err := json.Marshal(layerData)
if err != nil { if err != nil {
return err return err
} }
obytes, err := json.Marshal(options) oBytes, err := json.Marshal(options)
if err != nil { if err != nil {
return err return err
} }
err = hcsExportLayer(layerPath, exportFolderPath, string(ldbytes), string(obytes)) err = hcsExportLayer(layerPath, exportFolderPath, string(ldBytes), string(oBytes))
if err != nil { if err != nil {
return errors.Wrap(err, "failed to export layer") return errors.Wrap(err, "failed to export layer")
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -5,16 +7,20 @@ import (
"github.com/Microsoft/hcsshim/internal/oc" "github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.opencensus.io/trace"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
// FormatWritableLayerVhd formats a virtual disk for use as a writable container layer. // FormatWritableLayerVhd formats a virtual disk for use as a writable container layer.
// //
// If the VHD is not mounted it will be temporarily mounted. // 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) { func FormatWritableLayerVhd(ctx context.Context, vhdHandle windows.Handle) (err error) {
title := "hcsshim.FormatWritableLayerVhd" title := "hcsshim::FormatWritableLayerVhd"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -6,13 +8,17 @@ import (
"path/filepath" "path/filepath"
"syscall" "syscall"
"github.com/Microsoft/go-winio/pkg/security"
"github.com/Microsoft/go-winio/vhd" "github.com/Microsoft/go-winio/vhd"
"github.com/Microsoft/hcsshim/internal/memory"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sys/windows" "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 // 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 // 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{ createParams := &vhd.CreateVirtualDiskParameters{
Version: 2, Version: 2,
Version2: vhd.CreateVersion2{ Version2: vhd.CreateVersion2{
MaximumSize: sizeInGB * 1024 * 1024 * 1024, MaximumSize: sizeInGB * memory.GiB,
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024, BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
}, },
} }
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams) 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{ createParams := &vhd.CreateVirtualDiskParameters{
Version: 2, Version: 2,
Version2: vhd.CreateVersion2{ Version2: vhd.CreateVersion2{
MaximumSize: sizeInGB * 1024 * 1024 * 1024, MaximumSize: sizeInGB * memory.GiB,
BlockSizeInBytes: defaultVHDXBlockSizeInMB * 1024 * 1024, BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
}, },
} }
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams) handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -19,8 +21,8 @@ import (
// //
// `layerData` is the parent layer data. // `layerData` is the parent layer data.
func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) { func ImportLayer(ctx context.Context, layerPath, sourceFolderPath string, layerData LayerData) (err error) {
title := "hcsshim.ImportLayer" title := "hcsshim::ImportLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -16,8 +18,8 @@ import (
// //
// `layerData` is the parent read-only layer data. // `layerData` is the parent read-only layer data.
func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) { func InitializeWritableLayer(ctx context.Context, layerPath string, layerData LayerData) (err error) {
title := "hcsshim.InitializeWritableLayer" title := "hcsshim::InitializeWritableLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -6,14 +8,13 @@ import (
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/Microsoft/hcsshim/internal/oc" "github.com/Microsoft/hcsshim/internal/oc"
"github.com/pkg/errors" "github.com/pkg/errors"
"go.opencensus.io/trace"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
// GetLayerVhdMountPath returns the volume path for a virtual disk of a writable container layer. // 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) { func GetLayerVhdMountPath(ctx context.Context, vhdHandle windows.Handle) (path string, err error) {
title := "hcsshim.GetLayerVhdMountPath" title := "hcsshim::GetLayerVhdMountPath"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()

View File

@ -1,3 +1,5 @@
//go:build windows
package computestorage package computestorage
import ( import (
@ -21,8 +23,8 @@ import (
// //
// `options` are the options applied while processing the layer. // `options` are the options applied while processing the layer.
func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) { func SetupBaseOSLayer(ctx context.Context, layerPath string, vhdHandle windows.Handle, options OsLayerOptions) (err error) {
title := "hcsshim.SetupBaseOSLayer" title := "hcsshim::SetupBaseOSLayer"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( 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. // `volumePath` is the path to the volume to be used for setup.
// //
// `options` are the options applied while processing the layer. // `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) { func SetupBaseOSVolume(ctx context.Context, layerPath, volumePath string, options OsLayerOptions) (err error) {
if osversion.Build() < 19645 { if osversion.Build() < 19645 {
return errors.New("SetupBaseOSVolume is not present on builds older than 19645") return errors.New("SetupBaseOSVolume is not present on builds older than 19645")
} }
title := "hcsshim.SetupBaseOSVolume" title := "hcsshim::SetupBaseOSVolume"
ctx, span := trace.StartSpan(ctx, title) //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, title) //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -7,11 +7,11 @@ import (
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" 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 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 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 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 hcsInitializeWritableLayer(writableLayerPath string, layerData string, options string) (hr error) = computestorage.HcsInitializeWritableLayer?
//sys hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) = computestorage.HcsAttachLayerStorageFilter? //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 hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) = computestorage.HcsFormatWritableLayerVhd?
//sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath? //sys hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) = computestorage.HcsGetLayerVhdMountPath?
//sys hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (hr error) = computestorage.HcsSetupBaseOSVolume? //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. // LayerData is the data used to describe parent layer information.
type LayerData struct { type LayerData struct {
SchemaVersion hcsschema.Version `json:"SchemaVersion,omitempty"` SchemaVersion Version `json:"SchemaVersion,omitempty"`
Layers []hcsschema.Layer `json:"Layers,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. // ExportLayerOptions are the set of options that are used with the `computestorage.HcsExportLayer` syscall.

View File

@ -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 package computestorage
@ -19,6 +21,7 @@ const (
var ( var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
) )
// errnoErr returns common boxed Errno values, to prevent // errnoErr returns common boxed Errno values, to prevent
@ -26,7 +29,7 @@ var (
func errnoErr(e syscall.Errno) error { func errnoErr(e syscall.Errno) error {
switch e { switch e {
case 0: case 0:
return nil return errERROR_EINVAL
case errnoERROR_IO_PENDING: case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING return errERROR_IO_PENDING
} }
@ -39,42 +42,146 @@ func errnoErr(e syscall.Errno) error {
var ( var (
modcomputestorage = windows.NewLazySystemDLL("computestorage.dll") 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") procHcsAttachLayerStorageFilter = modcomputestorage.NewProc("HcsAttachLayerStorageFilter")
procHcsAttachOverlayFilter = modcomputestorage.NewProc("HcsAttachOverlayFilter")
procHcsDestroyLayer = modcomputestorage.NewProc("HcsDestroyLayer")
procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter") procHcsDetachLayerStorageFilter = modcomputestorage.NewProc("HcsDetachLayerStorageFilter")
procHcsDetachOverlayFilter = modcomputestorage.NewProc("HcsDetachOverlayFilter")
procHcsExportLayer = modcomputestorage.NewProc("HcsExportLayer")
procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd") procHcsFormatWritableLayerVhd = modcomputestorage.NewProc("HcsFormatWritableLayerVhd")
procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath") procHcsGetLayerVhdMountPath = modcomputestorage.NewProc("HcsGetLayerVhdMountPath")
procHcsImportLayer = modcomputestorage.NewProc("HcsImportLayer")
procHcsInitializeWritableLayer = modcomputestorage.NewProc("HcsInitializeWritableLayer")
procHcsSetupBaseOSLayer = modcomputestorage.NewProc("HcsSetupBaseOSLayer")
procHcsSetupBaseOSVolume = modcomputestorage.NewProc("HcsSetupBaseOSVolume") 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 var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath) _p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil { if hr != nil {
return return
} }
var _p1 *uint16 var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(sourceFolderPath) _p1, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil { if hr != nil {
return return
} }
var _p2 *uint16 return _hcsAttachLayerStorageFilter(_p0, _p1)
_p2, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil {
return
}
return _hcsImportLayer(_p0, _p1, _p2)
} }
func _hcsImportLayer(layerPath *uint16, sourceFolderPath *uint16, layerData *uint16) (hr error) { func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) {
if hr = procHcsImportLayer.Find(); hr != nil { hr = procHcsAttachLayerStorageFilter.Find()
if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData))) 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 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.Syscall(procHcsAttachOverlayFilter.Addr(), 2, uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(layerData)), 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)
if hr != nil {
return
}
return _hcsDestroyLayer(_p0)
}
func _hcsDestroyLayer(layerPath *uint16) (hr error) {
hr = procHcsDestroyLayer.Find()
if hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsDestroyLayer.Addr(), 1, uintptr(unsafe.Pointer(layerPath)), 0, 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)
if hr != nil {
return
}
return _hcsDetachLayerStorageFilter(_p0)
}
func _hcsDetachLayerStorageFilter(layerPath *uint16) (hr error) {
hr = procHcsDetachLayerStorageFilter.Find()
if 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 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.Syscall(procHcsDetachOverlayFilter.Addr(), 2, uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(layerData)), 0)
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -109,7 +216,8 @@ func hcsExportLayer(layerPath string, exportFolderPath string, layerData string,
} }
func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) { func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uint16, options *uint16) (hr error) {
if hr = procHcsExportLayer.Find(); hr != nil { hr = procHcsExportLayer.Find()
if hr != nil {
return 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) r0, _, _ := syscall.Syscall6(procHcsExportLayer.Addr(), 4, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(exportFolderPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)), 0, 0)
@ -122,20 +230,12 @@ func _hcsExportLayer(layerPath *uint16, exportFolderPath *uint16, layerData *uin
return return
} }
func hcsDestroyLayer(layerPath string) (hr error) { func hcsFormatWritableLayerVhd(handle windows.Handle) (hr error) {
var _p0 *uint16 hr = procHcsFormatWritableLayerVhd.Find()
_p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil { if hr != nil {
return return
} }
return _hcsDestroyLayer(_p0) r0, _, _ := syscall.Syscall(procHcsFormatWritableLayerVhd.Addr(), 1, uintptr(handle), 0, 0)
}
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)
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -145,25 +245,46 @@ func _hcsDestroyLayer(layerPath *uint16) (hr error) {
return return
} }
func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) { func hcsGetLayerVhdMountPath(vhdHandle windows.Handle, mountPath **uint16) (hr error) {
hr = procHcsGetLayerVhdMountPath.Find()
if hr != nil {
return
}
r0, _, _ := syscall.Syscall(procHcsGetLayerVhdMountPath.Addr(), 2, uintptr(vhdHandle), uintptr(unsafe.Pointer(mountPath)), 0)
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 var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath) _p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil { if hr != nil {
return return
} }
var _p1 *uint16 var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(options) _p1, hr = syscall.UTF16PtrFromString(sourceFolderPath)
if hr != nil { if hr != nil {
return return
} }
return _hcsSetupBaseOSLayer(_p0, handle, _p1) var _p2 *uint16
} _p2, hr = syscall.UTF16PtrFromString(layerData)
if hr != nil {
func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
if hr = procHcsSetupBaseOSLayer.Find(); hr != nil {
return 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.Syscall(procHcsImportLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(sourceFolderPath)), uintptr(unsafe.Pointer(layerData)))
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -193,7 +314,8 @@ func hcsInitializeWritableLayer(writableLayerPath string, layerData string, opti
} }
func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) { func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, options *uint16) (hr error) {
if hr = procHcsInitializeWritableLayer.Find(); hr != nil { hr = procHcsInitializeWritableLayer.Find()
if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options))) r0, _, _ := syscall.Syscall(procHcsInitializeWritableLayer.Addr(), 3, uintptr(unsafe.Pointer(writableLayerPath)), uintptr(unsafe.Pointer(layerData)), uintptr(unsafe.Pointer(options)))
@ -206,76 +328,26 @@ func _hcsInitializeWritableLayer(writableLayerPath *uint16, layerData *uint16, o
return return
} }
func hcsAttachLayerStorageFilter(layerPath string, layerData string) (hr error) { func hcsSetupBaseOSLayer(layerPath string, handle windows.Handle, options string) (hr error) {
var _p0 *uint16 var _p0 *uint16
_p0, hr = syscall.UTF16PtrFromString(layerPath) _p0, hr = syscall.UTF16PtrFromString(layerPath)
if hr != nil { if hr != nil {
return return
} }
var _p1 *uint16 var _p1 *uint16
_p1, hr = syscall.UTF16PtrFromString(layerData) _p1, hr = syscall.UTF16PtrFromString(options)
if hr != nil { if hr != nil {
return return
} }
return _hcsAttachLayerStorageFilter(_p0, _p1) return _hcsSetupBaseOSLayer(_p0, handle, _p1)
} }
func _hcsAttachLayerStorageFilter(layerPath *uint16, layerData *uint16) (hr error) { func _hcsSetupBaseOSLayer(layerPath *uint16, handle windows.Handle, options *uint16) (hr error) {
if hr = procHcsAttachLayerStorageFilter.Find(); hr != nil { hr = procHcsSetupBaseOSLayer.Find()
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)
if hr != nil { if hr != nil {
return return
} }
return _hcsDetachLayerStorageFilter(_p0) r0, _, _ := syscall.Syscall(procHcsSetupBaseOSLayer.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(handle), uintptr(unsafe.Pointer(options)))
}
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)
if int32(r0) < 0 { if int32(r0) < 0 {
if r0&0x1fff0000 == 0x00070000 { if r0&0x1fff0000 == 0x00070000 {
r0 &= 0xffff r0 &= 0xffff
@ -305,7 +377,8 @@ func hcsSetupBaseOSVolume(layerPath string, volumePath string, options string) (
} }
func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) { func _hcsSetupBaseOSVolume(layerPath *uint16, volumePath *uint16, options *uint16) (hr error) {
if hr = procHcsSetupBaseOSVolume.Find(); hr != nil { hr = procHcsSetupBaseOSVolume.Find()
if hr != nil {
return return
} }
r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options))) r0, _, _ := syscall.Syscall(procHcsSetupBaseOSVolume.Addr(), 3, uintptr(unsafe.Pointer(layerPath)), uintptr(unsafe.Pointer(volumePath)), uintptr(unsafe.Pointer(options)))

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (
@ -60,7 +62,7 @@ type container struct {
waitCh chan 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 // time. It allows an environment variable to define additional JSON which
// is merged in the CreateComputeSystem call to HCS. // is merged in the CreateComputeSystem call to HCS.
var createContainerAdditionalJSON []byte var createContainerAdditionalJSON []byte
@ -73,7 +75,7 @@ func init() {
func CreateContainer(id string, c *ContainerConfig) (Container, error) { func CreateContainer(id string, c *ContainerConfig) (Container, error) {
fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON) fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
if err != nil { 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) system, err := hcs.CreateComputeSystem(context.Background(), id, fullConfig)

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (
@ -50,6 +52,9 @@ var (
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value // ErrUnexpectedValue is an error encountered when hcs returns an invalid value
ErrUnexpectedValue = hcs.ErrUnexpectedValue 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 is an error encountered when a shutdown or terminate request is made on a stopped container
ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped
@ -110,6 +115,7 @@ func (e *ContainerError) Error() string {
s += " encountered an error during " + e.Operation s += " encountered an error during " + e.Operation
} }
//nolint:errorlint // legacy code
switch e.Err.(type) { switch e.Err.(type) {
case nil: case nil:
break break
@ -140,6 +146,7 @@ func (e *ProcessError) Error() string {
s += " encountered an error during " + e.Operation s += " encountered an error during " + e.Operation
} }
//nolint:errorlint // legacy code
switch e.Err.(type) { switch e.Err.(type) {
case nil: case nil:
break break
@ -161,10 +168,10 @@ func (e *ProcessError) Error() string {
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound. // will currently return true when the error is ErrElementNotFound.
func IsNotExist(err error) bool { func IsNotExist(err error) bool {
if _, ok := err.(EndpointNotFoundError); ok { if _, ok := err.(EndpointNotFoundError); ok { //nolint:errorlint // legacy code
return true return true
} }
if _, ok := err.(NetworkNotFoundError); ok { if _, ok := err.(NetworkNotFoundError); ok { //nolint:errorlint // legacy code
return true return true
} }
return hcs.IsNotExist(getInnerError(err)) return hcs.IsNotExist(getInnerError(err))
@ -219,6 +226,7 @@ func IsAccessIsDenied(err error) bool {
} }
func getInnerError(err error) error { func getInnerError(err error) error {
//nolint:errorlint // legacy code
switch pe := err.(type) { switch pe := err.(type) {
case nil: case nil:
return nil return nil
@ -231,14 +239,14 @@ func getInnerError(err error) error {
} }
func convertSystemError(err error, c *container) 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 &ContainerError{Container: c, Operation: serr.Op, Err: serr.Err, Events: serr.Events}
} }
return err return err
} }
func convertProcessError(err error, p *process) error { 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 &ProcessError{Process: p, Operation: perr.Op, Err: perr.Err, Events: perr.Events}
} }
return err return err

View File

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

View File

@ -1,5 +1,5 @@
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server //go:build windows
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
package hcn package hcn
import ( import (
@ -10,7 +10,7 @@ import (
"github.com/Microsoft/go-winio/pkg/guid" "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 /// HNS V1 API
@ -228,7 +228,7 @@ func IPv6DualStackSupported() error {
return platformDoesNotSupportError("IPv6 DualStack") 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 { func L4proxyPolicySupported() error {
supported, err := GetCachedSupportedFeatures() supported, err := GetCachedSupportedFeatures()
if err != nil { if err != nil {
@ -240,7 +240,7 @@ func L4proxyPolicySupported() error {
return platformDoesNotSupportError("L4ProxyPolicy") 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 { func L4WfpProxyPolicySupported() error {
supported, err := GetCachedSupportedFeatures() supported, err := GetCachedSupportedFeatures()
if err != nil { if err != nil {
@ -312,6 +312,18 @@ func NestedIpSetSupported() error {
return platformDoesNotSupportError("NestedIpSet") 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. // RequestType are the different operations performed to settings.
// Used to update the settings of Endpoint/Namespace objects. // Used to update the settings of Endpoint/Namespace objects.
type RequestType string type RequestType string

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -9,7 +11,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// IpConfig is assoicated with an endpoint // IpConfig is associated with an endpoint
type IpConfig struct { type IpConfig struct {
IpAddress string `json:",omitempty"` IpAddress string `json:",omitempty"`
PrefixLength uint8 `json:",omitempty"` PrefixLength uint8 `json:",omitempty"`
@ -70,14 +72,14 @@ type PolicyEndpointRequest struct {
Policies []EndpointPolicy `json:",omitempty"` Policies []EndpointPolicy `json:",omitempty"`
} }
func getEndpoint(endpointGuid guid.GUID, query string) (*HostComputeEndpoint, error) { func getEndpoint(endpointGUID guid.GUID, query string) (*HostComputeEndpoint, error) {
// Open endpoint. // Open endpoint.
var ( var (
endpointHandle hcnEndpoint endpointHandle hcnEndpoint
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer) hr := hcnOpenEndpoint(&endpointGUID, &endpointHandle, &resultBuffer)
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -119,8 +121,8 @@ func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
} }
var outputEndpoints []HostComputeEndpoint var outputEndpoints []HostComputeEndpoint
for _, endpointGuid := range endpointIds { for _, endpointGUID := range endpointIds {
endpoint, err := getEndpoint(endpointGuid, query) endpoint, err := getEndpoint(endpointGUID, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -129,22 +131,22 @@ func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
return outputEndpoints, nil return outputEndpoints, nil
} }
func createEndpoint(networkId string, endpointSettings string) (*HostComputeEndpoint, error) { func createEndpoint(networkID string, endpointSettings string) (*HostComputeEndpoint, error) {
networkGuid, err := guid.FromString(networkId) networkGUID, err := guid.FromString(networkID)
if err != nil { if err != nil {
return nil, errInvalidNetworkID return nil, errInvalidNetworkID
} }
// Open network. // Open network.
var networkHandle hcnNetwork var networkHandle hcnNetwork
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer) hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
// Create endpoint. // Create endpoint.
endpointId := guid.GUID{} endpointID := guid.GUID{}
var endpointHandle hcnEndpoint 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 { if err := checkForErrors("hcnCreateEndpoint", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -178,8 +180,8 @@ func createEndpoint(networkId string, endpointSettings string) (*HostComputeEndp
return &outputEndpoint, nil return &outputEndpoint, nil
} }
func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, error) { func modifyEndpoint(endpointID string, settings string) (*HostComputeEndpoint, error) {
endpointGuid, err := guid.FromString(endpointId) endpointGUID, err := guid.FromString(endpointID)
if err != nil { if err != nil {
return nil, errInvalidEndpointID return nil, errInvalidEndpointID
} }
@ -189,7 +191,7 @@ func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, e
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer) hr := hcnOpenEndpoint(&endpointGUID, &endpointHandle, &resultBuffer)
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -222,13 +224,13 @@ func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, e
return &outputEndpoint, nil return &outputEndpoint, nil
} }
func deleteEndpoint(endpointId string) error { func deleteEndpoint(endpointID string) error {
endpointGuid, err := guid.FromString(endpointId) endpointGUID, err := guid.FromString(endpointID)
if err != nil { if err != nil {
return errInvalidEndpointID return errInvalidEndpointID
} }
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnDeleteEndpoint(&endpointGuid, &resultBuffer) hr := hcnDeleteEndpoint(&endpointGUID, &resultBuffer)
if err := checkForErrors("hcnDeleteEndpoint", hr, resultBuffer); err != nil { if err := checkForErrors("hcnDeleteEndpoint", hr, resultBuffer); err != nil {
return err return err
} }
@ -247,12 +249,12 @@ func ListEndpoints() ([]HostComputeEndpoint, error) {
// ListEndpointsQuery makes a call to query the list of available endpoints. // ListEndpointsQuery makes a call to query the list of available endpoints.
func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) { func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
queryJson, err := json.Marshal(query) queryJSON, err := json.Marshal(query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
endpoints, err := enumerateEndpoints(string(queryJson)) endpoints, err := enumerateEndpoints(string(queryJSON))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -260,10 +262,10 @@ func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
} }
// ListEndpointsOfNetwork queries the list of endpoints on a network. // ListEndpointsOfNetwork queries the list of endpoints on a network.
func ListEndpointsOfNetwork(networkId string) ([]HostComputeEndpoint, error) { func ListEndpointsOfNetwork(networkID string) ([]HostComputeEndpoint, error) {
hcnQuery := defaultQuery() hcnQuery := defaultQuery()
// TODO: Once query can convert schema, change to {HostComputeNetwork:networkId} // 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) filter, err := json.Marshal(mapA)
if err != nil { if err != nil {
return nil, err return nil, err
@ -274,9 +276,9 @@ func ListEndpointsOfNetwork(networkId string) ([]HostComputeEndpoint, error) {
} }
// GetEndpointByID returns an endpoint specified by Id // GetEndpointByID returns an endpoint specified by Id
func GetEndpointByID(endpointId string) (*HostComputeEndpoint, error) { func GetEndpointByID(endpointID string) (*HostComputeEndpoint, error) {
hcnQuery := defaultQuery() hcnQuery := defaultQuery()
mapA := map[string]string{"ID": endpointId} mapA := map[string]string{"ID": endpointID}
filter, err := json.Marshal(mapA) filter, err := json.Marshal(mapA)
if err != nil { if err != nil {
return nil, err return nil, err
@ -288,7 +290,7 @@ func GetEndpointByID(endpointId string) (*HostComputeEndpoint, error) {
return nil, err return nil, err
} }
if len(endpoints) == 0 { if len(endpoints) == 0 {
return nil, EndpointNotFoundError{EndpointID: endpointId} return nil, EndpointNotFoundError{EndpointID: endpointID}
} }
return &endpoints[0], err return &endpoints[0], err
} }
@ -345,15 +347,15 @@ func (endpoint *HostComputeEndpoint) Delete() error {
} }
// ModifyEndpointSettings updates the Port/Policy of an Endpoint. // ModifyEndpointSettings updates the Port/Policy of an Endpoint.
func ModifyEndpointSettings(endpointId string, request *ModifyEndpointSettingRequest) error { func ModifyEndpointSettings(endpointID string, request *ModifyEndpointSettingRequest) error {
logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointId) logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointID)
endpointSettingsRequest, err := json.Marshal(request) endpointSettingsRequest, err := json.Marshal(request)
if err != nil { if err != nil {
return err return err
} }
_, err = modifyEndpoint(endpointId, string(endpointSettingsRequest)) _, err = modifyEndpoint(endpointID, string(endpointSettingsRequest))
if err != nil { if err != nil {
return err return err
} }
@ -364,25 +366,25 @@ func ModifyEndpointSettings(endpointId string, request *ModifyEndpointSettingReq
func (endpoint *HostComputeEndpoint) ApplyPolicy(requestType RequestType, endpointPolicy PolicyEndpointRequest) error { func (endpoint *HostComputeEndpoint) ApplyPolicy(requestType RequestType, endpointPolicy PolicyEndpointRequest) error {
logrus.Debugf("hcn::HostComputeEndpoint::ApplyPolicy id=%s", endpoint.Id) logrus.Debugf("hcn::HostComputeEndpoint::ApplyPolicy id=%s", endpoint.Id)
settingsJson, err := json.Marshal(endpointPolicy) settingsJSON, err := json.Marshal(endpointPolicy)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyEndpointSettingRequest{ requestMessage := &ModifyEndpointSettingRequest{
ResourceType: EndpointResourceTypePolicy, ResourceType: EndpointResourceTypePolicy,
RequestType: requestType, RequestType: requestType,
Settings: settingsJson, Settings: settingsJSON,
} }
return ModifyEndpointSettings(endpoint.Id, requestMessage) return ModifyEndpointSettings(endpoint.Id, requestMessage)
} }
// NamespaceAttach modifies a Namespace to add an endpoint. // NamespaceAttach modifies a Namespace to add an endpoint.
func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceId string) error { func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceID string) error {
return AddNamespaceEndpoint(namespaceId, endpoint.Id) return AddNamespaceEndpoint(namespaceID, endpoint.Id)
} }
// NamespaceDetach modifies a Namespace to remove an endpoint. // NamespaceDetach modifies a Namespace to remove an endpoint.
func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceId string) error { func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceID string) error {
return RemoveNamespaceEndpoint(namespaceId, endpoint.Id) return RemoveNamespaceEndpoint(namespaceID, endpoint.Id)
} }

View File

@ -1,15 +1,17 @@
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server //go:build windows
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
package hcn package hcn
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/sirupsen/logrus"
"golang.org/x/sys/windows"
"github.com/Microsoft/hcsshim/internal/hcs" "github.com/Microsoft/hcsshim/internal/hcs"
"github.com/Microsoft/hcsshim/internal/hcserror" "github.com/Microsoft/hcsshim/internal/hcserror"
"github.com/Microsoft/hcsshim/internal/interop" "github.com/Microsoft/hcsshim/internal/interop"
"github.com/sirupsen/logrus"
) )
var ( 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 // For common errors, define the error as it is in windows, so we can quickly determine it later
const ( const (
ERROR_NOT_FOUND = 0x490 ERROR_NOT_FOUND = ErrorCode(windows.ERROR_NOT_FOUND)
HCN_E_PORT_ALREADY_EXISTS ErrorCode = 0x803b0013 HCN_E_PORT_ALREADY_EXISTS ErrorCode = ErrorCode(windows.HCN_E_PORT_ALREADY_EXISTS)
) )
type HcnError struct { type HcnError struct {
@ -62,8 +64,8 @@ func (e *HcnError) Error() string {
} }
func CheckErrorWithCode(err error, code ErrorCode) bool { func CheckErrorWithCode(err error, code ErrorCode) bool {
hcnError, ok := err.(*HcnError) var hcnError *HcnError
if ok { if errors.As(err, &hcnError) {
return hcnError.code == code return hcnError.code == code
} }
return false return false
@ -80,22 +82,24 @@ func IsPortAlreadyExistsError(err error) bool {
func new(hr error, title string, rest string) error { func new(hr error, title string, rest string) error {
err := &HcnError{} err := &HcnError{}
hcsError := hcserror.New(hr, title, rest) hcsError := hcserror.New(hr, title, rest)
err.HcsError = hcsError.(*hcserror.HcsError) err.HcsError = hcsError.(*hcserror.HcsError) //nolint:errorlint
err.code = ErrorCode(hcserror.Win32FromError(hr)) err.code = ErrorCode(hcserror.Win32FromError(hr))
return err return err
} }
// //
// Note that the below errors are not errors returned by hcn itself // 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 { type NetworkNotFoundError struct {
NetworkName string NetworkName string
NetworkID string NetworkID string
} }
var _ error = NetworkNotFoundError{}
func (e NetworkNotFoundError) Error() string { func (e NetworkNotFoundError) Error() string {
if e.NetworkName != "" { if e.NetworkName != "" {
return fmt.Sprintf("Network name %q not found", 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) 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 { type EndpointNotFoundError struct {
EndpointName string EndpointName string
EndpointID string EndpointID string
} }
var _ error = EndpointNotFoundError{}
func (e EndpointNotFoundError) Error() string { func (e EndpointNotFoundError) Error() string {
if e.EndpointName != "" { if e.EndpointName != "" {
return fmt.Sprintf("Endpoint name %q not found", 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) 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 { type NamespaceNotFoundError struct {
NamespaceID string NamespaceID string
} }
var _ error = NamespaceNotFoundError{}
func (e NamespaceNotFoundError) Error() string { func (e NamespaceNotFoundError) Error() string {
return fmt.Sprintf("Namespace ID %q not found", e.NamespaceID) 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 { type LoadBalancerNotFoundError struct {
LoadBalancerId string LoadBalancerId string
} }
var _ error = LoadBalancerNotFoundError{}
func (e LoadBalancerNotFoundError) Error() string { func (e LoadBalancerNotFoundError) Error() string {
return fmt.Sprintf("LoadBalancer %q not found", e.LoadBalancerId) 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 { type RouteNotFoundError struct {
RouteId string RouteId string
} }
var _ error = RouteNotFoundError{}
func (e RouteNotFoundError) Error() string { func (e RouteNotFoundError) Error() string {
return fmt.Sprintf("SDN Route %q not found", e.RouteId) 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 // IsNotFoundError returns a boolean indicating whether the error was caused by
// a resource not being found. // a resource not being found.
func IsNotFoundError(err error) bool { func IsNotFoundError(err error) bool {
switch pe := err.(type) { // Calling [errors.As] in a loop over `[]error{NetworkNotFoundError{}, ...}` will not work,
case NetworkNotFoundError: // 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 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 return false
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -82,6 +84,9 @@ var (
//HNS 15.0 allows for NestedIpSet support //HNS 15.0 allows for NestedIpSet support
NestedIpSetVersion = VersionRanges{VersionRange{MinVersion: Version{Major: 15, Minor: 0}, MaxVersion: Version{Major: math.MaxInt32, Minor: math.MaxInt32}}} 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. // GetGlobals returns the global properties of the HCN Service.

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -28,7 +30,7 @@ type HostComputeLoadBalancer struct {
Flags LoadBalancerFlags `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn Flags LoadBalancerFlags `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn
} }
//LoadBalancerFlags modify settings for a loadbalancer. // LoadBalancerFlags modify settings for a loadbalancer.
type LoadBalancerFlags uint32 type LoadBalancerFlags uint32
var ( var (
@ -67,14 +69,14 @@ var (
LoadBalancerDistributionSourceIP LoadBalancerDistribution = 2 LoadBalancerDistributionSourceIP LoadBalancerDistribution = 2
) )
func getLoadBalancer(loadBalancerGuid guid.GUID, query string) (*HostComputeLoadBalancer, error) { func getLoadBalancer(loadBalancerGUID guid.GUID, query string) (*HostComputeLoadBalancer, error) {
// Open loadBalancer. // Open loadBalancer.
var ( var (
loadBalancerHandle hcnLoadBalancer loadBalancerHandle hcnLoadBalancer
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenLoadBalancer(&loadBalancerGuid, &loadBalancerHandle, &resultBuffer) hr := hcnOpenLoadBalancer(&loadBalancerGUID, &loadBalancerHandle, &resultBuffer)
if err := checkForErrors("hcnOpenLoadBalancer", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenLoadBalancer", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -115,8 +117,8 @@ func enumerateLoadBalancers(query string) ([]HostComputeLoadBalancer, error) {
} }
var outputLoadBalancers []HostComputeLoadBalancer var outputLoadBalancers []HostComputeLoadBalancer
for _, loadBalancerGuid := range loadBalancerIds { for _, loadBalancerGUID := range loadBalancerIds {
loadBalancer, err := getLoadBalancer(loadBalancerGuid, query) loadBalancer, err := getLoadBalancer(loadBalancerGUID, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -132,8 +134,8 @@ func createLoadBalancer(settings string) (*HostComputeLoadBalancer, error) {
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
loadBalancerGuid := guid.GUID{} loadBalancerGUID := guid.GUID{}
hr := hcnCreateLoadBalancer(&loadBalancerGuid, settings, &loadBalancerHandle, &resultBuffer) hr := hcnCreateLoadBalancer(&loadBalancerGUID, settings, &loadBalancerHandle, &resultBuffer)
if err := checkForErrors("hcnCreateLoadBalancer", hr, resultBuffer); err != nil { if err := checkForErrors("hcnCreateLoadBalancer", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -161,13 +163,13 @@ func createLoadBalancer(settings string) (*HostComputeLoadBalancer, error) {
return &outputLoadBalancer, nil return &outputLoadBalancer, nil
} }
func deleteLoadBalancer(loadBalancerId string) error { func deleteLoadBalancer(loadBalancerID string) error {
loadBalancerGuid, err := guid.FromString(loadBalancerId) loadBalancerGUID, err := guid.FromString(loadBalancerID)
if err != nil { if err != nil {
return errInvalidLoadBalancerID return errInvalidLoadBalancerID
} }
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnDeleteLoadBalancer(&loadBalancerGuid, &resultBuffer) hr := hcnDeleteLoadBalancer(&loadBalancerGUID, &resultBuffer)
if err := checkForErrors("hcnDeleteLoadBalancer", hr, resultBuffer); err != nil { if err := checkForErrors("hcnDeleteLoadBalancer", hr, resultBuffer); err != nil {
return err return err
} }
@ -186,12 +188,12 @@ func ListLoadBalancers() ([]HostComputeLoadBalancer, error) {
// ListLoadBalancersQuery makes a call to query the list of available loadBalancers. // ListLoadBalancersQuery makes a call to query the list of available loadBalancers.
func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer, error) { func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer, error) {
queryJson, err := json.Marshal(query) queryJSON, err := json.Marshal(query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
loadBalancers, err := enumerateLoadBalancers(string(queryJson)) loadBalancers, err := enumerateLoadBalancers(string(queryJSON))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -199,9 +201,9 @@ func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer,
} }
// GetLoadBalancerByID returns the LoadBalancer specified by Id. // GetLoadBalancerByID returns the LoadBalancer specified by Id.
func GetLoadBalancerByID(loadBalancerId string) (*HostComputeLoadBalancer, error) { func GetLoadBalancerByID(loadBalancerID string) (*HostComputeLoadBalancer, error) {
hcnQuery := defaultQuery() hcnQuery := defaultQuery()
mapA := map[string]string{"ID": loadBalancerId} mapA := map[string]string{"ID": loadBalancerID}
filter, err := json.Marshal(mapA) filter, err := json.Marshal(mapA)
if err != nil { if err != nil {
return nil, err return nil, err
@ -213,7 +215,7 @@ func GetLoadBalancerByID(loadBalancerId string) (*HostComputeLoadBalancer, error
return nil, err return nil, err
} }
if len(loadBalancers) == 0 { if len(loadBalancers) == 0 {
return nil, LoadBalancerNotFoundError{LoadBalancerId: loadBalancerId} return nil, LoadBalancerNotFoundError{LoadBalancerId: loadBalancerID}
} }
return &loadBalancers[0], err return &loadBalancers[0], err
} }

View File

@ -1,7 +1,10 @@
//go:build windows
package hcn package hcn
import ( import (
"encoding/json" "encoding/json"
"errors"
"os" "os"
"syscall" "syscall"
@ -27,7 +30,7 @@ type NamespaceResourceContainer struct {
type NamespaceResourceType string type NamespaceResourceType string
var ( var (
// NamespaceResourceTypeContainer are contianers associated with a Namespace. // NamespaceResourceTypeContainer are containers associated with a Namespace.
NamespaceResourceTypeContainer NamespaceResourceType = "Container" NamespaceResourceTypeContainer NamespaceResourceType = "Container"
// NamespaceResourceTypeEndpoint are endpoints associated with a Namespace. // NamespaceResourceTypeEndpoint are endpoints associated with a Namespace.
NamespaceResourceTypeEndpoint NamespaceResourceType = "Endpoint" NamespaceResourceTypeEndpoint NamespaceResourceType = "Endpoint"
@ -70,14 +73,14 @@ type ModifyNamespaceSettingRequest struct {
Settings json.RawMessage `json:",omitempty"` 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. // Open namespace.
var ( var (
namespaceHandle hcnNamespace namespaceHandle hcnNamespace
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenNamespace(&namespaceGuid, &namespaceHandle, &resultBuffer) hr := hcnOpenNamespace(&namespaceGUID, &namespaceHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -118,8 +121,8 @@ func enumerateNamespaces(query string) ([]HostComputeNamespace, error) {
} }
var outputNamespaces []HostComputeNamespace var outputNamespaces []HostComputeNamespace
for _, namespaceGuid := range namespaceIds { for _, namespaceGUID := range namespaceIds {
namespace, err := getNamespace(namespaceGuid, query) namespace, err := getNamespace(namespaceGUID, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -135,8 +138,8 @@ func createNamespace(settings string) (*HostComputeNamespace, error) {
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
namespaceGuid := guid.GUID{} namespaceGUID := guid.GUID{}
hr := hcnCreateNamespace(&namespaceGuid, settings, &namespaceHandle, &resultBuffer) hr := hcnCreateNamespace(&namespaceGUID, settings, &namespaceHandle, &resultBuffer)
if err := checkForErrors("hcnCreateNamespace", hr, resultBuffer); err != nil { if err := checkForErrors("hcnCreateNamespace", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -164,8 +167,8 @@ func createNamespace(settings string) (*HostComputeNamespace, error) {
return &outputNamespace, nil return &outputNamespace, nil
} }
func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace, error) { func modifyNamespace(namespaceID string, settings string) (*HostComputeNamespace, error) {
namespaceGuid, err := guid.FromString(namespaceId) namespaceGUID, err := guid.FromString(namespaceID)
if err != nil { if err != nil {
return nil, errInvalidNamespaceID return nil, errInvalidNamespaceID
} }
@ -175,7 +178,7 @@ func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenNamespace(&namespaceGuid, &namespaceHandle, &resultBuffer) hr := hcnOpenNamespace(&namespaceGUID, &namespaceHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -208,13 +211,13 @@ func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace
return &outputNamespace, nil return &outputNamespace, nil
} }
func deleteNamespace(namespaceId string) error { func deleteNamespace(namespaceID string) error {
namespaceGuid, err := guid.FromString(namespaceId) namespaceGUID, err := guid.FromString(namespaceID)
if err != nil { if err != nil {
return errInvalidNamespaceID return errInvalidNamespaceID
} }
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnDeleteNamespace(&namespaceGuid, &resultBuffer) hr := hcnDeleteNamespace(&namespaceGUID, &resultBuffer)
if err := checkForErrors("hcnDeleteNamespace", hr, resultBuffer); err != nil { if err := checkForErrors("hcnDeleteNamespace", hr, resultBuffer); err != nil {
return err return err
} }
@ -233,12 +236,12 @@ func ListNamespaces() ([]HostComputeNamespace, error) {
// ListNamespacesQuery makes a call to query the list of available namespaces. // ListNamespacesQuery makes a call to query the list of available namespaces.
func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error) { func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error) {
queryJson, err := json.Marshal(query) queryJSON, err := json.Marshal(query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
namespaces, err := enumerateNamespaces(string(queryJson)) namespaces, err := enumerateNamespaces(string(queryJSON))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -246,9 +249,9 @@ func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error)
} }
// GetNamespaceByID returns the Namespace specified by Id. // GetNamespaceByID returns the Namespace specified by Id.
func GetNamespaceByID(namespaceId string) (*HostComputeNamespace, error) { func GetNamespaceByID(namespaceID string) (*HostComputeNamespace, error) {
hcnQuery := defaultQuery() hcnQuery := defaultQuery()
mapA := map[string]string{"ID": namespaceId} mapA := map[string]string{"ID": namespaceID}
filter, err := json.Marshal(mapA) filter, err := json.Marshal(mapA)
if err != nil { if err != nil {
return nil, err return nil, err
@ -260,15 +263,15 @@ func GetNamespaceByID(namespaceId string) (*HostComputeNamespace, error) {
return nil, err return nil, err
} }
if len(namespaces) == 0 { if len(namespaces) == 0 {
return nil, NamespaceNotFoundError{NamespaceID: namespaceId} return nil, NamespaceNotFoundError{NamespaceID: namespaceID}
} }
return &namespaces[0], err return &namespaces[0], err
} }
// GetNamespaceEndpointIds returns the endpoints of the Namespace specified by Id. // GetNamespaceEndpointIds returns the endpoints of the Namespace specified by Id.
func GetNamespaceEndpointIds(namespaceId string) ([]string, error) { func GetNamespaceEndpointIds(namespaceID string) ([]string, error) {
namespace, err := GetNamespaceByID(namespaceId) namespace, err := GetNamespaceByID(namespaceID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -286,19 +289,19 @@ func GetNamespaceEndpointIds(namespaceId string) ([]string, error) {
} }
// GetNamespaceContainerIds returns the containers of the Namespace specified by Id. // GetNamespaceContainerIds returns the containers of the Namespace specified by Id.
func GetNamespaceContainerIds(namespaceId string) ([]string, error) { func GetNamespaceContainerIds(namespaceID string) ([]string, error) {
namespace, err := GetNamespaceByID(namespaceId) namespace, err := GetNamespaceByID(namespaceID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var containerIds []string var containerIds []string
for _, resource := range namespace.Resources { for _, resource := range namespace.Resources {
if resource.Type == "Container" { if resource.Type == "Container" {
var contaienrResource NamespaceResourceContainer var containerResource NamespaceResourceContainer
if err := json.Unmarshal([]byte(resource.Data), &contaienrResource); err != nil { if err := json.Unmarshal([]byte(resource.Data), &containerResource); err != nil {
return nil, err return nil, err
} }
containerIds = append(containerIds, contaienrResource.Id) containerIds = append(containerIds, containerResource.Id)
} }
} }
return containerIds, nil return containerIds, nil
@ -375,8 +378,9 @@ func (namespace *HostComputeNamespace) Sync() error {
} }
shimPath := runhcs.VMPipePath(cfg.HostUniqueID) shimPath := runhcs.VMPipePath(cfg.HostUniqueID)
if err := runhcs.IssueVMRequest(shimPath, &req); err != nil { if err := runhcs.IssueVMRequest(shimPath, &req); err != nil {
// The shim is likey gone. Simply ignore the sync as if it didn't exist. // The shim is likely 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 { 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 // Remove the reg key there is no point to try again
_ = cfg.Remove() _ = cfg.Remove()
return nil return nil
@ -394,15 +398,15 @@ func (namespace *HostComputeNamespace) Sync() error {
} }
// ModifyNamespaceSettings updates the Endpoints/Containers of a Namespace. // ModifyNamespaceSettings updates the Endpoints/Containers of a Namespace.
func ModifyNamespaceSettings(namespaceId string, request *ModifyNamespaceSettingRequest) error { func ModifyNamespaceSettings(namespaceID string, request *ModifyNamespaceSettingRequest) error {
logrus.Debugf("hcn::HostComputeNamespace::ModifyNamespaceSettings id=%s", namespaceId) logrus.Debugf("hcn::HostComputeNamespace::ModifyNamespaceSettings id=%s", namespaceID)
namespaceSettings, err := json.Marshal(request) namespaceSettings, err := json.Marshal(request)
if err != nil { if err != nil {
return err return err
} }
_, err = modifyNamespace(namespaceId, string(namespaceSettings)) _, err = modifyNamespace(namespaceID, string(namespaceSettings))
if err != nil { if err != nil {
return err return err
} }
@ -410,37 +414,37 @@ func ModifyNamespaceSettings(namespaceId string, request *ModifyNamespaceSetting
} }
// AddNamespaceEndpoint adds an endpoint to a Namespace. // AddNamespaceEndpoint adds an endpoint to a Namespace.
func AddNamespaceEndpoint(namespaceId string, endpointId string) error { func AddNamespaceEndpoint(namespaceID string, endpointID string) error {
logrus.Debugf("hcn::HostComputeEndpoint::AddNamespaceEndpoint id=%s", endpointId) logrus.Debugf("hcn::HostComputeEndpoint::AddNamespaceEndpoint id=%s", endpointID)
mapA := map[string]string{"EndpointId": endpointId} mapA := map[string]string{"EndpointId": endpointID}
settingsJson, err := json.Marshal(mapA) settingsJSON, err := json.Marshal(mapA)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyNamespaceSettingRequest{ requestMessage := &ModifyNamespaceSettingRequest{
ResourceType: NamespaceResourceTypeEndpoint, ResourceType: NamespaceResourceTypeEndpoint,
RequestType: RequestTypeAdd, RequestType: RequestTypeAdd,
Settings: settingsJson, Settings: settingsJSON,
} }
return ModifyNamespaceSettings(namespaceId, requestMessage) return ModifyNamespaceSettings(namespaceID, requestMessage)
} }
// RemoveNamespaceEndpoint removes an endpoint from a Namespace. // RemoveNamespaceEndpoint removes an endpoint from a Namespace.
func RemoveNamespaceEndpoint(namespaceId string, endpointId string) error { func RemoveNamespaceEndpoint(namespaceID string, endpointID string) error {
logrus.Debugf("hcn::HostComputeNamespace::RemoveNamespaceEndpoint id=%s", endpointId) logrus.Debugf("hcn::HostComputeNamespace::RemoveNamespaceEndpoint id=%s", endpointID)
mapA := map[string]string{"EndpointId": endpointId} mapA := map[string]string{"EndpointId": endpointID}
settingsJson, err := json.Marshal(mapA) settingsJSON, err := json.Marshal(mapA)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyNamespaceSettingRequest{ requestMessage := &ModifyNamespaceSettingRequest{
ResourceType: NamespaceResourceTypeEndpoint, ResourceType: NamespaceResourceTypeEndpoint,
RequestType: RequestTypeRemove, RequestType: RequestTypeRemove,
Settings: settingsJson, Settings: settingsJSON,
} }
return ModifyNamespaceSettings(namespaceId, requestMessage) return ModifyNamespaceSettings(namespaceID, requestMessage)
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -70,6 +72,7 @@ type NetworkFlags uint32
const ( const (
None NetworkFlags = 0 None NetworkFlags = 0
EnableNonPersistent NetworkFlags = 8 EnableNonPersistent NetworkFlags = 8
DisableHostPort NetworkFlags = 1024
) )
// HostComputeNetwork represents a network // HostComputeNetwork represents a network
@ -110,14 +113,14 @@ type PolicyNetworkRequest struct {
Policies []NetworkPolicy `json:",omitempty"` Policies []NetworkPolicy `json:",omitempty"`
} }
func getNetwork(networkGuid guid.GUID, query string) (*HostComputeNetwork, error) { func getNetwork(networkGUID guid.GUID, query string) (*HostComputeNetwork, error) {
// Open network. // Open network.
var ( var (
networkHandle hcnNetwork networkHandle hcnNetwork
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer) hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -164,8 +167,8 @@ func enumerateNetworks(query string) ([]HostComputeNetwork, error) {
} }
var outputNetworks []HostComputeNetwork var outputNetworks []HostComputeNetwork
for _, networkGuid := range networkIds { for _, networkGUID := range networkIds {
network, err := getNetwork(networkGuid, query) network, err := getNetwork(networkGUID, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -181,8 +184,8 @@ func createNetwork(settings string) (*HostComputeNetwork, error) {
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
networkGuid := guid.GUID{} networkGUID := guid.GUID{}
hr := hcnCreateNetwork(&networkGuid, settings, &networkHandle, &resultBuffer) hr := hcnCreateNetwork(&networkGUID, settings, &networkHandle, &resultBuffer)
if err := checkForErrors("hcnCreateNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnCreateNetwork", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -216,8 +219,8 @@ func createNetwork(settings string) (*HostComputeNetwork, error) {
return &outputNetwork, nil return &outputNetwork, nil
} }
func modifyNetwork(networkId string, settings string) (*HostComputeNetwork, error) { func modifyNetwork(networkID string, settings string) (*HostComputeNetwork, error) {
networkGuid, err := guid.FromString(networkId) networkGUID, err := guid.FromString(networkID)
if err != nil { if err != nil {
return nil, errInvalidNetworkID return nil, errInvalidNetworkID
} }
@ -227,7 +230,7 @@ func modifyNetwork(networkId string, settings string) (*HostComputeNetwork, erro
resultBuffer *uint16 resultBuffer *uint16
propertiesBuffer *uint16 propertiesBuffer *uint16
) )
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer) hr := hcnOpenNetwork(&networkGUID, &networkHandle, &resultBuffer)
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
return nil, err return nil, err
} }
@ -266,13 +269,13 @@ func modifyNetwork(networkId string, settings string) (*HostComputeNetwork, erro
return &outputNetwork, nil return &outputNetwork, nil
} }
func deleteNetwork(networkId string) error { func deleteNetwork(networkID string) error {
networkGuid, err := guid.FromString(networkId) networkGUID, err := guid.FromString(networkID)
if err != nil { if err != nil {
return errInvalidNetworkID return errInvalidNetworkID
} }
var resultBuffer *uint16 var resultBuffer *uint16
hr := hcnDeleteNetwork(&networkGuid, &resultBuffer) hr := hcnDeleteNetwork(&networkGUID, &resultBuffer)
if err := checkForErrors("hcnDeleteNetwork", hr, resultBuffer); err != nil { if err := checkForErrors("hcnDeleteNetwork", hr, resultBuffer); err != nil {
return err return err
} }
@ -291,12 +294,12 @@ func ListNetworks() ([]HostComputeNetwork, error) {
// ListNetworksQuery makes a call to query the list of available networks. // ListNetworksQuery makes a call to query the list of available networks.
func ListNetworksQuery(query HostComputeQuery) ([]HostComputeNetwork, error) { func ListNetworksQuery(query HostComputeQuery) ([]HostComputeNetwork, error) {
queryJson, err := json.Marshal(query) queryJSON, err := json.Marshal(query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
networks, err := enumerateNetworks(string(queryJson)) networks, err := enumerateNetworks(string(queryJSON))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -408,14 +411,14 @@ func (network *HostComputeNetwork) ModifyNetworkSettings(request *ModifyNetworkS
func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest) error { func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest) error {
logrus.Debugf("hcn::HostComputeNetwork::AddPolicy id=%s", network.Id) logrus.Debugf("hcn::HostComputeNetwork::AddPolicy id=%s", network.Id)
settingsJson, err := json.Marshal(networkPolicy) settingsJSON, err := json.Marshal(networkPolicy)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyNetworkSettingRequest{ requestMessage := &ModifyNetworkSettingRequest{
ResourceType: NetworkResourceTypePolicy, ResourceType: NetworkResourceTypePolicy,
RequestType: RequestTypeAdd, RequestType: RequestTypeAdd,
Settings: settingsJson, Settings: settingsJSON,
} }
return network.ModifyNetworkSettings(requestMessage) return network.ModifyNetworkSettings(requestMessage)
@ -425,14 +428,14 @@ func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest)
func (network *HostComputeNetwork) RemovePolicy(networkPolicy PolicyNetworkRequest) error { func (network *HostComputeNetwork) RemovePolicy(networkPolicy PolicyNetworkRequest) error {
logrus.Debugf("hcn::HostComputeNetwork::RemovePolicy id=%s", network.Id) logrus.Debugf("hcn::HostComputeNetwork::RemovePolicy id=%s", network.Id)
settingsJson, err := json.Marshal(networkPolicy) settingsJSON, err := json.Marshal(networkPolicy)
if err != nil { if err != nil {
return err return err
} }
requestMessage := &ModifyNetworkSettingRequest{ requestMessage := &ModifyNetworkSettingRequest{
ResourceType: NetworkResourceTypePolicy, ResourceType: NetworkResourceTypePolicy,
RequestType: RequestTypeRemove, RequestType: RequestTypeRemove,
Settings: settingsJson, Settings: settingsJSON,
} }
return network.ModifyNetworkSettings(requestMessage) return network.ModifyNetworkSettings(requestMessage)

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (
@ -292,7 +294,7 @@ const (
type SetPolicySetting struct { type SetPolicySetting struct {
Id string Id string
Name string Name string
Type SetPolicyType Type SetPolicyType `json:"PolicyType"`
Values string Values string
} }
@ -313,7 +315,7 @@ const (
ProtocolTypeICMPv6 ProtocolType = 58 ProtocolTypeICMPv6 ProtocolType = 58
) )
//L4ProxyPolicySetting applies proxy policy on network/endpoint // L4ProxyPolicySetting applies proxy policy on network/endpoint
type L4ProxyPolicySetting struct { type L4ProxyPolicySetting struct {
IP string `json:",omitempty"` IP string `json:",omitempty"`
Port string `json:",omitempty"` Port string `json:",omitempty"`

View File

@ -1,3 +1,5 @@
//go:build windows
package hcn package hcn
import ( import (

View File

@ -1,11 +1,14 @@
//go:build windows
package hcn package hcn
import ( import (
"fmt"
"sync" "sync"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/Microsoft/hcsshim/internal/log"
) )
var ( var (
@ -34,6 +37,7 @@ type SupportedFeatures struct {
TierAcl bool `json:"TierAcl"` TierAcl bool `json:"TierAcl"`
NetworkACL bool `json:"NetworkACL"` NetworkACL bool `json:"NetworkACL"`
NestedIpSet bool `json:"NestedIpSet"` NestedIpSet bool `json:"NestedIpSet"`
DisableHostPort bool `json:"DisableHostPort"`
} }
// AclFeatures are the supported ACL possibilities. // AclFeatures are the supported ACL possibilities.
@ -111,10 +115,11 @@ func getSupportedFeatures() (SupportedFeatures, error) {
features.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion) features.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion)
features.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion) features.NetworkACL = isFeatureSupported(globals.Version, NetworkACLPolicyVersion)
features.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion) features.NestedIpSet = isFeatureSupported(globals.Version, NestedIpSetVersion)
features.DisableHostPort = isFeatureSupported(globals.Version, DisableHostPortVersion)
logrus.WithFields(logrus.Fields{ log.L.WithFields(logrus.Fields{
"version": fmt.Sprintf("%+v", globals.Version), "version": globals.Version,
"supportedFeatures": fmt.Sprintf("%+v", features), "supportedFeatures": features,
}).Info("HCN feature check") }).Info("HCN feature check")
return features, nil return features, nil

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,17 @@
//go:build windows
// Shim for the Host Compute Service (HCS) to manage Windows Server // Shim for the Host Compute Service (HCS) to manage Windows Server
// containers and Hyper-V containers. // containers and Hyper-V containers.
package hcsshim package hcsshim
import ( import (
"syscall" "golang.org/x/sys/windows"
"github.com/Microsoft/hcsshim/internal/hcserror" "github.com/Microsoft/hcsshim/internal/hcserror"
) )
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go hcsshim.go //go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go hcsshim.go
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId //sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
@ -17,9 +19,9 @@ const (
// Specific user-visible exit codes // Specific user-visible exit codes
WaitErrExecFailed = 32767 WaitErrExecFailed = 32767
ERROR_GEN_FAILURE = hcserror.ERROR_GEN_FAILURE ERROR_GEN_FAILURE = windows.ERROR_GEN_FAILURE
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115) ERROR_SHUTDOWN_IN_PROGRESS = windows.ERROR_SHUTDOWN_IN_PROGRESS
WSAEINVAL = syscall.Errno(10022) WSAEINVAL = windows.WSAEINVAL
// Timeout on wait calls // Timeout on wait calls
TimeoutInfinite = 0xFFFFFFFF TimeoutInfinite = 0xFFFFFFFF

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (
@ -13,7 +15,7 @@ type HNSEndpointStats = hns.EndpointStats
// Namespace represents a Compartment. // Namespace represents a Compartment.
type Namespace = hns.Namespace type Namespace = hns.Namespace
//SystemType represents the type of the system on which actions are done // SystemType represents the type of the system on which actions are done
type SystemType string type SystemType string
// SystemType const // SystemType const

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (

View File

@ -1,14 +1,16 @@
//go:build windows
package hcsshim package hcsshim
import ( import (
"github.com/Microsoft/hcsshim/internal/hns" "github.com/Microsoft/hcsshim/internal/hns"
) )
// Subnet is assoicated with a network and represents a list // Subnet is associated with a network and represents a list
// of subnets available to the network // of subnets available to the network
type Subnet = hns.Subnet type Subnet = hns.Subnet
// MacPool is assoicated with a network and represents a list // MacPool is associated with a network and represents a list
// of macaddresses available to the network // of macaddresses available to the network
type MacPool = hns.MacPool type MacPool = hns.MacPool

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcsshim package hcsshim
import ( import (

View File

@ -0,0 +1 @@
package cni

View File

@ -1,3 +1,5 @@
//go:build windows
package cni package cni
import ( import (
@ -84,7 +86,7 @@ func (pnc *PersistedNamespaceConfig) Store() error {
} }
// Remove removes any persisted state associated with this config. If the config // Remove removes any persisted state associated with this config. If the config
// is not found in the registery `Remove` returns no error. // is not found in the registry `Remove` returns no error.
func (pnc *PersistedNamespaceConfig) Remove() error { func (pnc *PersistedNamespaceConfig) Remove() error {
if pnc.stored { if pnc.stored {
sk, err := regstate.Open(cniRoot, false) sk, err := regstate.Open(cniRoot, false)

View File

@ -1,3 +1,5 @@
//go:build windows
package cow package cow
import ( import (

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (

View File

@ -0,0 +1 @@
package hcs

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (
@ -51,6 +53,9 @@ var (
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value // ErrUnexpectedValue is an error encountered when hcs returns an invalid value
ErrUnexpectedValue = errors.New("unexpected value returned from hcs") ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
// ErrOperationDenied is an error when hcs attempts an operation that is explicitly denied
ErrOperationDenied = errors.New("operation denied")
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container // ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110) ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
@ -82,7 +87,7 @@ var (
// ErrProcessAlreadyStopped is returned by hcs if the process we're trying to kill has already been stopped. // ErrProcessAlreadyStopped is returned by hcs if the process we're trying to kill has already been stopped.
ErrProcessAlreadyStopped = syscall.Errno(0x8037011f) ErrProcessAlreadyStopped = syscall.Errno(0x8037011f)
// ErrInvalidHandle is an error that can be encountrered when querying the properties of a compute system when the handle to that // ErrInvalidHandle is an error that can be encountered when querying the properties of a compute system when the handle to that
// compute system has already been closed. // compute system has already been closed.
ErrInvalidHandle = syscall.Errno(0x6) ErrInvalidHandle = syscall.Errno(0x6)
) )
@ -152,33 +157,38 @@ func (e *HcsError) Error() string {
return s return s
} }
func (e *HcsError) Is(target error) bool {
return errors.Is(e.Err, target)
}
// unwrap isnt really needed, but helpful convince function
func (e *HcsError) Unwrap() error {
return e.Err
}
// Deprecated: net.Error.Temporary is deprecated.
func (e *HcsError) Temporary() bool { func (e *HcsError) Temporary() bool {
err, ok := e.Err.(net.Error) err := e.netError()
return ok && err.Temporary() //nolint:staticcheck return (err != nil) && err.Temporary()
} }
func (e *HcsError) Timeout() bool { func (e *HcsError) Timeout() bool {
err, ok := e.Err.(net.Error) err := e.netError()
return ok && err.Timeout() return (err != nil) && err.Timeout()
} }
// ProcessError is an error encountered in HCS during an operation on a Process object func (e *HcsError) netError() (err net.Error) {
type ProcessError struct { if errors.As(e.Unwrap(), &err) {
SystemID string return err
Pid int }
Op string return nil
Err error
Events []ErrorEvent
} }
var _ net.Error = &ProcessError{}
// SystemError is an error encountered in HCS during an operation on a Container object // SystemError is an error encountered in HCS during an operation on a Container object
type SystemError struct { type SystemError struct {
HcsError
ID string ID string
Op string
Err error
Events []ErrorEvent
} }
var _ net.Error = &SystemError{} var _ net.Error = &SystemError{}
@ -191,29 +201,32 @@ func (e *SystemError) Error() string {
return s return s
} }
func (e *SystemError) Temporary() bool {
err, ok := e.Err.(net.Error)
return ok && err.Temporary() //nolint:staticcheck
}
func (e *SystemError) Timeout() bool {
err, ok := e.Err.(net.Error)
return ok && err.Timeout()
}
func makeSystemError(system *System, op string, err error, events []ErrorEvent) error { func makeSystemError(system *System, op string, err error, events []ErrorEvent) error {
// Don't double wrap errors // Don't double wrap errors
if _, ok := err.(*SystemError); ok { var e *SystemError
if errors.As(err, &e) {
return err return err
} }
return &SystemError{ return &SystemError{
ID: system.ID(), ID: system.ID(),
HcsError: HcsError{
Op: op, Op: op,
Err: err, Err: err,
Events: events, Events: events,
},
} }
} }
// ProcessError is an error encountered in HCS during an operation on a Process object
type ProcessError struct {
HcsError
SystemID string
Pid int
}
var _ net.Error = &ProcessError{}
func (e *ProcessError) Error() string { func (e *ProcessError) Error() string {
s := fmt.Sprintf("%s %s:%d: %s", e.Op, e.SystemID, e.Pid, e.Err.Error()) s := fmt.Sprintf("%s %s:%d: %s", e.Op, e.SystemID, e.Pid, e.Err.Error())
for _, ev := range e.Events { for _, ev := range e.Events {
@ -222,27 +235,20 @@ func (e *ProcessError) Error() string {
return s return s
} }
func (e *ProcessError) Temporary() bool {
err, ok := e.Err.(net.Error)
return ok && err.Temporary() //nolint:staticcheck
}
func (e *ProcessError) Timeout() bool {
err, ok := e.Err.(net.Error)
return ok && err.Timeout()
}
func makeProcessError(process *Process, op string, err error, events []ErrorEvent) error { func makeProcessError(process *Process, op string, err error, events []ErrorEvent) error {
// Don't double wrap errors // Don't double wrap errors
if _, ok := err.(*ProcessError); ok { var e *ProcessError
if errors.As(err, &e) {
return err return err
} }
return &ProcessError{ return &ProcessError{
Pid: process.Pid(), Pid: process.Pid(),
SystemID: process.SystemID(), SystemID: process.SystemID(),
HcsError: HcsError{
Op: op, Op: op,
Err: err, Err: err,
Events: events, Events: events,
},
} }
} }
@ -251,41 +257,41 @@ func makeProcessError(process *Process, op string, err error, events []ErrorEven
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound. // will currently return true when the error is ErrElementNotFound.
func IsNotExist(err error) bool { func IsNotExist(err error) bool {
err = getInnerError(err) return IsAny(err, ErrComputeSystemDoesNotExist, ErrElementNotFound)
return err == ErrComputeSystemDoesNotExist ||
err == ErrElementNotFound
} }
// IsErrorInvalidHandle checks whether the error is the result of an operation carried // IsErrorInvalidHandle checks whether the error is the result of an operation carried
// out on a handle that is invalid/closed. This error popped up while trying to query // out on a handle that is invalid/closed. This error popped up while trying to query
// stats on a container in the process of being stopped. // stats on a container in the process of being stopped.
func IsErrorInvalidHandle(err error) bool { func IsErrorInvalidHandle(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrInvalidHandle)
return err == ErrInvalidHandle
} }
// IsAlreadyClosed checks if an error is caused by the Container or Process having been // IsAlreadyClosed checks if an error is caused by the Container or Process having been
// already closed by a call to the Close() method. // already closed by a call to the Close() method.
func IsAlreadyClosed(err error) bool { func IsAlreadyClosed(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrAlreadyClosed)
return err == ErrAlreadyClosed
} }
// IsPending returns a boolean indicating whether the error is that // IsPending returns a boolean indicating whether the error is that
// the requested operation is being completed in the background. // the requested operation is being completed in the background.
func IsPending(err error) bool { func IsPending(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrVmcomputeOperationPending)
return err == ErrVmcomputeOperationPending
} }
// IsTimeout returns a boolean indicating whether the error is caused by // IsTimeout returns a boolean indicating whether the error is caused by
// a timeout waiting for the operation to complete. // a timeout waiting for the operation to complete.
func IsTimeout(err error) bool { func IsTimeout(err error) bool {
if err, ok := err.(net.Error); ok && err.Timeout() { // HcsError and co. implement Timeout regardless of whether the errors they wrap do,
// so `errors.As(err, net.Error)`` will always be true.
// Using `errors.As(err.Unwrap(), net.Err)` wont work for general errors.
// So first check if there an `ErrTimeout` in the chain, then convert to a net error.
if errors.Is(err, ErrTimeout) {
return true return true
} }
err = getInnerError(err)
return err == ErrTimeout var nerr net.Error
return errors.As(err, &nerr) && nerr.Timeout()
} }
// IsAlreadyStopped returns a boolean indicating whether the error is caused by // IsAlreadyStopped returns a boolean indicating whether the error is caused by
@ -294,10 +300,7 @@ func IsTimeout(err error) bool {
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
// will currently return true when the error is ErrElementNotFound. // will currently return true when the error is ErrElementNotFound.
func IsAlreadyStopped(err error) bool { func IsAlreadyStopped(err error) bool {
err = getInnerError(err) return IsAny(err, ErrVmcomputeAlreadyStopped, ErrProcessAlreadyStopped, ErrElementNotFound)
return err == ErrVmcomputeAlreadyStopped ||
err == ErrProcessAlreadyStopped ||
err == ErrElementNotFound
} }
// IsNotSupported returns a boolean indicating whether the error is caused by // IsNotSupported returns a boolean indicating whether the error is caused by
@ -306,38 +309,28 @@ func IsAlreadyStopped(err error) bool {
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage // ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
// is thrown from the Platform // is thrown from the Platform
func IsNotSupported(err error) bool { func IsNotSupported(err error) bool {
err = getInnerError(err)
// If Platform doesn't recognize or support the request sent, below errors are seen // If Platform doesn't recognize or support the request sent, below errors are seen
return err == ErrVmcomputeInvalidJSON || return IsAny(err, ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported, ErrVmcomputeUnknownMessage)
err == ErrInvalidData ||
err == ErrNotSupported ||
err == ErrVmcomputeUnknownMessage
} }
// IsOperationInvalidState returns true when err is caused by // IsOperationInvalidState returns true when err is caused by
// `ErrVmcomputeOperationInvalidState`. // `ErrVmcomputeOperationInvalidState`.
func IsOperationInvalidState(err error) bool { func IsOperationInvalidState(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrVmcomputeOperationInvalidState)
return err == ErrVmcomputeOperationInvalidState
} }
// IsAccessIsDenied returns true when err is caused by // IsAccessIsDenied returns true when err is caused by
// `ErrVmcomputeOperationAccessIsDenied`. // `ErrVmcomputeOperationAccessIsDenied`.
func IsAccessIsDenied(err error) bool { func IsAccessIsDenied(err error) bool {
err = getInnerError(err) return errors.Is(err, ErrVmcomputeOperationAccessIsDenied)
return err == ErrVmcomputeOperationAccessIsDenied
} }
func getInnerError(err error) error { // IsAny is a vectorized version of [errors.Is], it returns true if err is one of targets.
switch pe := err.(type) { func IsAny(err error, targets ...error) bool {
case nil: for _, e := range targets {
return nil if errors.Is(err, e) {
case *HcsError: return true
err = pe.Err
case *SystemError:
err = pe.Err
case *ProcessError:
err = pe.Err
} }
return err }
return false
} }

View File

@ -1,3 +1,5 @@
//go:build windows
package hcs package hcs
import ( import (
@ -10,13 +12,16 @@ import (
"syscall" "syscall"
"time" "time"
"go.opencensus.io/trace"
"github.com/Microsoft/hcsshim/internal/cow"
hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
"github.com/Microsoft/hcsshim/internal/log" "github.com/Microsoft/hcsshim/internal/log"
"github.com/Microsoft/hcsshim/internal/oc" "github.com/Microsoft/hcsshim/internal/oc"
"github.com/Microsoft/hcsshim/internal/protocol/guestrequest"
"github.com/Microsoft/hcsshim/internal/vmcompute" "github.com/Microsoft/hcsshim/internal/vmcompute"
"go.opencensus.io/trace"
) )
// ContainerError is an error encountered in HCS
type Process struct { type Process struct {
handleLock sync.RWMutex handleLock sync.RWMutex
handle vmcompute.HcsProcess handle vmcompute.HcsProcess
@ -36,6 +41,8 @@ type Process struct {
waitError error waitError error
} }
var _ cow.Process = &Process{}
func newProcess(process vmcompute.HcsProcess, processID int, computeSystem *System) *Process { func newProcess(process vmcompute.HcsProcess, processID int, computeSystem *System) *Process {
return &Process{ return &Process{
handle: process, handle: process,
@ -45,35 +52,6 @@ func newProcess(process vmcompute.HcsProcess, processID int, computeSystem *Syst
} }
} }
type processModifyRequest struct {
Operation string
ConsoleSize *consoleSize `json:",omitempty"`
CloseHandle *closeHandle `json:",omitempty"`
}
type consoleSize struct {
Height uint16
Width uint16
}
type closeHandle struct {
Handle string
}
type processStatus struct {
ProcessID uint32
Exited bool
ExitCode uint32
LastWaitResult int32
}
const stdIn string = "StdIn"
const (
modifyConsoleSize string = "ConsoleSize"
modifyCloseHandle string = "CloseHandle"
)
// Pid returns the process ID of the process within the container. // Pid returns the process ID of the process within the container.
func (process *Process) Pid() int { func (process *Process) Pid() int {
return process.processID return process.processID
@ -85,14 +63,11 @@ func (process *Process) SystemID() string {
} }
func (process *Process) processSignalResult(ctx context.Context, err error) (bool, error) { func (process *Process) processSignalResult(ctx context.Context, err error) (bool, error) {
switch err { switch err { //nolint:errorlint
case nil: case nil:
return true, nil return true, nil
case ErrVmcomputeOperationInvalidState, ErrComputeSystemDoesNotExist, ErrElementNotFound: case ErrVmcomputeOperationInvalidState, ErrComputeSystemDoesNotExist, ErrElementNotFound:
select { if !process.stopped() {
case <-process.waitBlock:
// The process exit notification has already arrived.
default:
// The process should be gone, but we have not received the notification. // The process should be gone, but we have not received the notification.
// After a second, force unblock the process wait to work around a possible // After a second, force unblock the process wait to work around a possible
// deadlock in the HCS. // deadlock in the HCS.
@ -114,9 +89,9 @@ func (process *Process) processSignalResult(ctx context.Context, err error) (boo
// Signal signals the process with `options`. // Signal signals the process with `options`.
// //
// For LCOW `guestrequest.SignalProcessOptionsLCOW`. // For LCOW `guestresource.SignalProcessOptionsLCOW`.
// //
// For WCOW `guestrequest.SignalProcessOptionsWCOW`. // For WCOW `guestresource.SignalProcessOptionsWCOW`.
func (process *Process) Signal(ctx context.Context, options interface{}) (bool, error) { func (process *Process) Signal(ctx context.Context, options interface{}) (bool, error) {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
@ -152,6 +127,10 @@ func (process *Process) Kill(ctx context.Context) (bool, error) {
return false, makeProcessError(process, operation, ErrAlreadyClosed, nil) return false, makeProcessError(process, operation, ErrAlreadyClosed, nil)
} }
if process.stopped() {
return false, makeProcessError(process, operation, ErrProcessAlreadyStopped, nil)
}
if process.killSignalDelivered { if process.killSignalDelivered {
// A kill signal has already been sent to this process. Sending a second // A kill signal has already been sent to this process. Sending a second
// one offers no real benefit, as processes cannot stop themselves from // one offers no real benefit, as processes cannot stop themselves from
@ -233,7 +212,7 @@ func (process *Process) Kill(ctx context.Context) (bool, error) {
// call multiple times. // call multiple times.
func (process *Process) waitBackground() { func (process *Process) waitBackground() {
operation := "hcs::Process::waitBackground" operation := "hcs::Process::waitBackground"
ctx, span := trace.StartSpan(context.Background(), operation) ctx, span := oc.StartSpan(context.Background(), operation)
defer span.End() defer span.End()
span.AddAttributes( span.AddAttributes(
trace.StringAttribute("cid", process.SystemID()), trace.StringAttribute("cid", process.SystemID()),
@ -254,17 +233,17 @@ func (process *Process) waitBackground() {
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
// Make sure we didnt race with Close() here // Make sure we didn't race with Close() here
if process.handle != 0 { if process.handle != 0 {
propertiesJSON, resultJSON, err = vmcompute.HcsGetProcessProperties(ctx, process.handle) propertiesJSON, resultJSON, err = vmcompute.HcsGetProcessProperties(ctx, process.handle)
events := processHcsResult(ctx, resultJSON) events := processHcsResult(ctx, resultJSON)
if err != nil { if err != nil {
err = makeProcessError(process, operation, err, events) //nolint:ineffassign err = makeProcessError(process, operation, err, events)
} else { } else {
properties := &processStatus{} properties := &hcsschema.ProcessStatus{}
err = json.Unmarshal([]byte(propertiesJSON), properties) err = json.Unmarshal([]byte(propertiesJSON), properties)
if err != nil { if err != nil {
err = makeProcessError(process, operation, err, nil) //nolint:ineffassign err = makeProcessError(process, operation, err, nil)
} else { } else {
if properties.LastWaitResult != 0 { if properties.LastWaitResult != 0 {
log.G(ctx).WithField("wait-result", properties.LastWaitResult).Warning("non-zero last wait result") log.G(ctx).WithField("wait-result", properties.LastWaitResult).Warning("non-zero last wait result")
@ -286,12 +265,22 @@ func (process *Process) waitBackground() {
} }
// Wait waits for the process to exit. If the process has already exited returns // Wait waits for the process to exit. If the process has already exited returns
// the pervious error (if any). // the previous error (if any).
func (process *Process) Wait() error { func (process *Process) Wait() error {
<-process.waitBlock <-process.waitBlock
return process.waitError return process.waitError
} }
// Exited returns if the process has stopped
func (process *Process) stopped() bool {
select {
case <-process.waitBlock:
return true
default:
return false
}
}
// ResizeConsole resizes the console of the process. // ResizeConsole resizes the console of the process.
func (process *Process) ResizeConsole(ctx context.Context, width, height uint16) error { func (process *Process) ResizeConsole(ctx context.Context, width, height uint16) error {
process.handleLock.RLock() process.handleLock.RLock()
@ -302,10 +291,9 @@ func (process *Process) ResizeConsole(ctx context.Context, width, height uint16)
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
} }
modifyRequest := hcsschema.ProcessModifyRequest{
modifyRequest := processModifyRequest{ Operation: guestrequest.ModifyProcessConsoleSize,
Operation: modifyConsoleSize, ConsoleSize: &hcsschema.ConsoleSize{
ConsoleSize: &consoleSize{
Height: height, Height: height,
Width: width, Width: width,
}, },
@ -328,15 +316,13 @@ func (process *Process) ResizeConsole(ctx context.Context, width, height uint16)
// ExitCode returns the exit code of the process. The process must have // ExitCode returns the exit code of the process. The process must have
// already terminated. // already terminated.
func (process *Process) ExitCode() (int, error) { func (process *Process) ExitCode() (int, error) {
select { if !process.stopped() {
case <-process.waitBlock: return -1, makeProcessError(process, "hcs::Process::ExitCode", ErrInvalidProcessState, nil)
}
if process.waitError != nil { if process.waitError != nil {
return -1, process.waitError return -1, process.waitError
} }
return process.exitCode, nil return process.exitCode, nil
default:
return -1, makeProcessError(process, "hcs::Process::ExitCode", ErrInvalidProcessState, nil)
}
} }
// StdioLegacy returns the stdin, stdout, and stderr pipes, respectively. Closing // StdioLegacy returns the stdin, stdout, and stderr pipes, respectively. Closing
@ -344,7 +330,7 @@ func (process *Process) ExitCode() (int, error) {
// are the responsibility of the caller to close. // are the responsibility of the caller to close.
func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) { func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
operation := "hcs::Process::StdioLegacy" operation := "hcs::Process::StdioLegacy"
ctx, span := trace.StartSpan(context.Background(), operation) ctx, span := oc.StartSpan(context.Background(), operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -382,7 +368,7 @@ func (process *Process) StdioLegacy() (_ io.WriteCloser, _ io.ReadCloser, _ io.R
} }
// Stdio returns the stdin, stdout, and stderr pipes, respectively. // Stdio returns the stdin, stdout, and stderr pipes, respectively.
// To close them, close the process handle. // To close them, close the process handle, or use the `CloseStd*` functions.
func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) { func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) {
process.stdioLock.Lock() process.stdioLock.Lock()
defer process.stdioLock.Unlock() defer process.stdioLock.Unlock()
@ -391,20 +377,28 @@ func (process *Process) Stdio() (stdin io.Writer, stdout, stderr io.Reader) {
// CloseStdin closes the write side of the stdin pipe so that the process is // CloseStdin closes the write side of the stdin pipe so that the process is
// notified on the read side that there is no more data in stdin. // notified on the read side that there is no more data in stdin.
func (process *Process) CloseStdin(ctx context.Context) error { func (process *Process) CloseStdin(ctx context.Context) (err error) {
operation := "hcs::Process::CloseStdin"
ctx, span := trace.StartSpan(ctx, operation)
defer span.End()
defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes(
trace.StringAttribute("cid", process.SystemID()),
trace.Int64Attribute("pid", int64(process.processID)))
process.handleLock.RLock() process.handleLock.RLock()
defer process.handleLock.RUnlock() defer process.handleLock.RUnlock()
operation := "hcs::Process::CloseStdin"
if process.handle == 0 { if process.handle == 0 {
return makeProcessError(process, operation, ErrAlreadyClosed, nil) return makeProcessError(process, operation, ErrAlreadyClosed, nil)
} }
modifyRequest := processModifyRequest{ //HcsModifyProcess request to close stdin will fail if the process has already exited
Operation: modifyCloseHandle, if !process.stopped() {
CloseHandle: &closeHandle{ modifyRequest := hcsschema.ProcessModifyRequest{
Handle: stdIn, Operation: guestrequest.CloseProcessHandle,
CloseHandle: &hcsschema.CloseHandle{
Handle: guestrequest.STDInHandle,
}, },
} }
@ -418,19 +412,20 @@ func (process *Process) CloseStdin(ctx context.Context) error {
if err != nil { if err != nil {
return makeProcessError(process, operation, err, events) return makeProcessError(process, operation, err, events)
} }
}
process.stdioLock.Lock() process.stdioLock.Lock()
defer process.stdioLock.Unlock()
if process.stdin != nil { if process.stdin != nil {
process.stdin.Close() process.stdin.Close()
process.stdin = nil process.stdin = nil
} }
process.stdioLock.Unlock()
return nil return nil
} }
func (process *Process) CloseStdout(ctx context.Context) (err error) { func (process *Process) CloseStdout(ctx context.Context) (err error) {
ctx, span := trace.StartSpan(ctx, "hcs::Process::CloseStdout") //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, "hcs::Process::CloseStdout") //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -454,7 +449,7 @@ func (process *Process) CloseStdout(ctx context.Context) (err error) {
} }
func (process *Process) CloseStderr(ctx context.Context) (err error) { func (process *Process) CloseStderr(ctx context.Context) (err error) {
ctx, span := trace.StartSpan(ctx, "hcs::Process::CloseStderr") //nolint:ineffassign,staticcheck ctx, span := oc.StartSpan(ctx, "hcs::Process::CloseStderr") //nolint:ineffassign,staticcheck
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(
@ -473,7 +468,6 @@ func (process *Process) CloseStderr(ctx context.Context) (err error) {
if process.stderr != nil { if process.stderr != nil {
process.stderr.Close() process.stderr.Close()
process.stderr = nil process.stderr = nil
} }
return nil return nil
} }
@ -482,7 +476,7 @@ func (process *Process) CloseStderr(ctx context.Context) (err error) {
// or wait on it. // or wait on it.
func (process *Process) Close() (err error) { func (process *Process) Close() (err error) {
operation := "hcs::Process::Close" operation := "hcs::Process::Close"
ctx, span := trace.StartSpan(context.Background(), operation) ctx, span := oc.StartSpan(context.Background(), operation)
defer span.End() defer span.End()
defer func() { oc.SetSpanStatus(span, err) }() defer func() { oc.SetSpanStatus(span, err) }()
span.AddAttributes( span.AddAttributes(

View File

@ -1,3 +1,5 @@
//go:build windows
package schema1 package schema1
import ( import (
@ -101,7 +103,7 @@ type ContainerConfig struct {
HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM HvRuntime *HvRuntime `json:",omitempty"` // Hyper-V container settings. Used by Hyper-V containers only. Format ImagePath=%root%\BaseLayerID\UtilityVM
Servicing bool `json:",omitempty"` // True if this container is for servicing Servicing bool `json:",omitempty"` // True if this container is for servicing
AllowUnqualifiedDNSQuery bool `json:",omitempty"` // True to allow unqualified DNS name resolution AllowUnqualifiedDNSQuery bool `json:",omitempty"` // True to allow unqualified DNS name resolution
DNSSearchList string `json:",omitempty"` // Comma seperated list of DNS suffixes to use for name resolution DNSSearchList string `json:",omitempty"` // Comma separated list of DNS suffixes to use for name resolution
ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise. ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise.
TerminateOnLastHandleClosed bool `json:",omitempty"` // Should HCS terminate the container once all handles have been closed TerminateOnLastHandleClosed bool `json:",omitempty"` // Should HCS terminate the container once all handles have been closed
MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start

View File

@ -0,0 +1,25 @@
/*
* HCS API
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* API version: 2.5
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
*/
package hcsschema
const (
CimMountFlagNone uint32 = 0x0
CimMountFlagChildOnly uint32 = 0x1
CimMountFlagEnableDax uint32 = 0x2
CimMountFlagCacheFiles uint32 = 0x4
CimMountFlagCacheRegions uint32 = 0x8
)
type CimMount struct {
ImagePath string `json:"ImagePath,omitempty"`
FileSystemName string `json:"FileSystemName,omitempty"`
VolumeGuid string `json:"VolumeGuid,omitempty"`
MountFlags uint32 `json:"MountFlags,omitempty"`
}

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