summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--cmd/podman/common.go2
-rw-r--r--cmd/podman/shared/create.go6
-rw-r--r--cmd/podman/shared/pod.go56
-rw-r--r--docs/source/markdown/podman-create.1.md2
-rw-r--r--docs/source/markdown/podman-run.1.md2
-rw-r--r--go.mod22
-rw-r--r--go.sum29
-rw-r--r--libpod/container_inspect.go3
-rw-r--r--libpod/define/podstate.go19
-rw-r--r--libpod/pod_status.go59
-rw-r--r--libpod/runtime_ctr.go41
-rw-r--r--libpod/runtime_pod.go28
-rw-r--r--pkg/adapter/pods.go4
-rw-r--r--pkg/adapter/pods_remote.go4
-rw-r--r--pkg/api/Makefile8
-rw-r--r--pkg/api/handlers/containers.go53
-rw-r--r--pkg/api/handlers/containers_create.go (renamed from pkg/api/handlers/generic/containers_create.go)13
-rw-r--r--pkg/api/handlers/decoder.go91
-rw-r--r--pkg/api/handlers/events.go25
-rw-r--r--pkg/api/handlers/generic/config.go9
-rw-r--r--pkg/api/handlers/generic/containers.go80
-rw-r--r--pkg/api/handlers/generic/images.go73
-rw-r--r--pkg/api/handlers/generic/swagger.go4
-rw-r--r--pkg/api/handlers/handler.go9
-rw-r--r--pkg/api/handlers/images.go41
-rw-r--r--pkg/api/handlers/libpod/containers.go48
-rw-r--r--pkg/api/handlers/libpod/images.go78
-rw-r--r--pkg/api/handlers/libpod/pods.go53
-rw-r--r--pkg/api/handlers/swagger.go11
-rw-r--r--pkg/api/handlers/types.go14
-rw-r--r--pkg/api/handlers/utils/containers.go21
-rw-r--r--pkg/api/handlers/utils/errors.go22
-rw-r--r--pkg/api/handlers/utils/handler.go8
-rw-r--r--pkg/api/handlers/utils/images.go17
-rw-r--r--pkg/api/server/docs.go30
-rw-r--r--pkg/api/server/register_containers.go845
-rw-r--r--pkg/api/server/register_distribution.go2
-rw-r--r--pkg/api/server/register_events.go13
-rw-r--r--pkg/api/server/register_healthcheck.go2
-rw-r--r--pkg/api/server/register_images.go463
-rw-r--r--pkg/api/server/register_info.go8
-rw-r--r--pkg/api/server/register_pods.go238
-rw-r--r--pkg/api/server/register_volumes.go32
-rw-r--r--pkg/api/server/server.go48
-rw-r--r--pkg/api/server/swagger.go26
-rw-r--r--pkg/bindings/bindings.go9
-rw-r--r--pkg/util/camelcase/LICENSE.md (renamed from vendor/github.com/fatih/camelcase/LICENSE.md)0
-rw-r--r--pkg/util/camelcase/README.md (renamed from vendor/github.com/fatih/camelcase/README.md)0
-rw-r--r--pkg/util/camelcase/camelcase.go (renamed from vendor/github.com/fatih/camelcase/camelcase.go)5
-rw-r--r--test/e2e/config.go4
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/drivers/btrfs/btrfs.go7
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go3
-rw-r--r--vendor/github.com/containers/storage/go.mod6
-rw-r--r--vendor/github.com/containers/storage/go.sum10
-rw-r--r--vendor/github.com/containers/storage/pkg/config/config.go2
-rw-r--r--vendor/github.com/coreos/go-iptables/iptables/iptables.go29
-rw-r--r--vendor/github.com/fatih/camelcase/.travis.yml3
-rw-r--r--vendor/github.com/json-iterator/go/reflect_extension.go2
-rw-r--r--vendor/github.com/json-iterator/go/reflect_map.go10
-rw-r--r--vendor/github.com/json-iterator/go/reflect_struct_encoder.go1
-rw-r--r--vendor/github.com/klauspost/compress/huff0/bitwriter.go13
-rw-r--r--vendor/github.com/klauspost/compress/huff0/compress.go70
-rw-r--r--vendor/github.com/klauspost/compress/huff0/huff0.go7
-rw-r--r--vendor/github.com/klauspost/compress/zstd/README.md4
-rw-r--r--vendor/github.com/klauspost/compress/zstd/blockenc.go33
-rw-r--r--vendor/github.com/klauspost/compress/zstd/decoder.go29
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_dfast.go313
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_fast.go245
-rw-r--r--vendor/github.com/klauspost/compress/zstd/encoder.go71
-rw-r--r--vendor/github.com/mattn/go-shellwords/.travis.yml1
-rw-r--r--vendor/github.com/mattn/go-shellwords/README.md1
-rw-r--r--vendor/github.com/mattn/go-shellwords/shellwords.go6
-rw-r--r--vendor/github.com/pkg/errors/cause.go29
-rw-r--r--vendor/github.com/pkg/errors/errors.go26
-rw-r--r--vendor/github.com/pkg/errors/go113.go33
-rw-r--r--vendor/github.com/uber/jaeger-client-go/CHANGELOG.md28
-rw-r--r--vendor/github.com/uber/jaeger-client-go/Makefile8
-rw-r--r--vendor/github.com/uber/jaeger-client-go/README.md2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/config/config.go13
-rw-r--r--vendor/github.com/uber/jaeger-client-go/constants.go2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/internal/reporterstats/stats.go25
-rw-r--r--vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/reporter.go33
-rw-r--r--vendor/github.com/uber/jaeger-client-go/span.go77
-rw-r--r--vendor/github.com/uber/jaeger-client-go/span_context.go4
-rw-r--r--vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go272
-rw-r--r--vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go4
-rw-r--r--vendor/github.com/uber/jaeger-client-go/tracer.go1
-rw-r--r--vendor/github.com/uber/jaeger-client-go/tracer_options.go12
-rw-r--r--vendor/github.com/uber/jaeger-client-go/transport/http.go11
-rw-r--r--vendor/github.com/uber/jaeger-client-go/transport_udp.go61
-rw-r--r--vendor/github.com/uber/jaeger-client-go/utils/udp_client.go2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go1
-rw-r--r--vendor/github.com/vishvananda/netlink/.gitignore1
-rw-r--r--vendor/github.com/vishvananda/netlink/.travis.yml6
-rw-r--r--vendor/github.com/vishvananda/netlink/addr_linux.go105
-rw-r--r--vendor/github.com/vishvananda/netlink/bridge_linux.go9
-rw-r--r--vendor/github.com/vishvananda/netlink/class.go141
-rw-r--r--vendor/github.com/vishvananda/netlink/class_linux.go145
-rw-r--r--vendor/github.com/vishvananda/netlink/conntrack_linux.go119
-rw-r--r--vendor/github.com/vishvananda/netlink/devlink_linux.go272
-rw-r--r--vendor/github.com/vishvananda/netlink/filter.go110
-rw-r--r--vendor/github.com/vishvananda/netlink/filter_linux.go240
-rw-r--r--vendor/github.com/vishvananda/netlink/fou_linux.go6
-rw-r--r--vendor/github.com/vishvananda/netlink/genetlink_linux.go3
-rw-r--r--vendor/github.com/vishvananda/netlink/go.mod8
-rw-r--r--vendor/github.com/vishvananda/netlink/go.sum4
-rw-r--r--vendor/github.com/vishvananda/netlink/handle_linux.go2
-rw-r--r--vendor/github.com/vishvananda/netlink/handle_unspecified.go12
-rw-r--r--vendor/github.com/vishvananda/netlink/ioctl_linux.go10
-rw-r--r--vendor/github.com/vishvananda/netlink/link.go242
-rw-r--r--vendor/github.com/vishvananda/netlink/link_linux.go1120
-rw-r--r--vendor/github.com/vishvananda/netlink/neigh.go7
-rw-r--r--vendor/github.com/vishvananda/netlink/neigh_linux.go189
-rw-r--r--vendor/github.com/vishvananda/netlink/netlink.go3
-rw-r--r--vendor/github.com/vishvananda/netlink/netlink_unspecified.go12
-rw-r--r--vendor/github.com/vishvananda/netlink/netns_linux.go141
-rw-r--r--vendor/github.com/vishvananda/netlink/netns_unspecified.go19
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/bridge_linux.go4
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go40
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/devlink_linux.go40
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/link_linux.go72
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/nl_linux.go66
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go35
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/route_linux.go26
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/seg6_linux.go43
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go76
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/syscall.go11
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/tc_linux.go166
-rw-r--r--vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go62
-rw-r--r--vendor/github.com/vishvananda/netlink/protinfo.go4
-rw-r--r--vendor/github.com/vishvananda/netlink/protinfo_linux.go7
-rw-r--r--vendor/github.com/vishvananda/netlink/qdisc.go48
-rw-r--r--vendor/github.com/vishvananda/netlink/qdisc_linux.go69
-rw-r--r--vendor/github.com/vishvananda/netlink/rdma_link_linux.go264
-rw-r--r--vendor/github.com/vishvananda/netlink/route.go2
-rw-r--r--vendor/github.com/vishvananda/netlink/route_linux.go229
-rw-r--r--vendor/github.com/vishvananda/netlink/rule_linux.go2
-rw-r--r--vendor/github.com/vishvananda/netlink/socket_linux.go5
-rw-r--r--vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go6
-rw-r--r--vendor/github.com/vishvananda/netlink/xfrm_policy.go26
-rw-r--r--vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go19
-rw-r--r--vendor/github.com/vishvananda/netlink/xfrm_state.go6
-rw-r--r--vendor/github.com/vishvananda/netlink/xfrm_state_linux.go27
-rw-r--r--vendor/github.com/vishvananda/netns/go.mod3
-rw-r--r--vendor/github.com/vishvananda/netns/go.sum0
-rw-r--r--vendor/gopkg.in/yaml.v2/scannerc.go47
-rw-r--r--vendor/gopkg.in/yaml.v2/yamlh.go1
-rw-r--r--vendor/modules.txt31
151 files changed, 6620 insertions, 1939 deletions
diff --git a/README.md b/README.md
index 1c2744ceb..e7ab48fac 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
Libpod provides a library for applications looking to use the Container Pod concept,
popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes.
-* [Latest Version: 1.6.3](https://github.com/containers/libpod/releases/latest)
+* [Latest Version: 1.7.0](https://github.com/containers/libpod/releases/latest)
* [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master)
* [GoDoc: ![GoDoc](https://godoc.org/github.com/containers/libpod/libpod?status.svg)](https://godoc.org/github.com/containers/libpod/libpod)
* Automated continuous release downloads (including remote-client):
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index f3aff1d49..46feae90d 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -12,7 +12,7 @@ import (
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/sysinfo"
- "github.com/fatih/camelcase"
+ "github.com/containers/libpod/pkg/util/camelcase"
jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go
index 15d6bddbb..2f637694b 100644
--- a/cmd/podman/shared/create.go
+++ b/cmd/podman/shared/create.go
@@ -31,9 +31,9 @@ import (
"github.com/sirupsen/logrus"
)
-// seccompAnnotationKey is the key of the image annotation embedding a seccomp
+// seccompLabelKey is the key of the image annotation embedding a seccomp
// profile.
-const seccompAnnotationKey = "io.containers.seccomp.profile"
+const seccompLabelKey = "io.containers.seccomp.profile"
func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod.Runtime) (*libpod.Container, *cc.CreateConfig, error) {
var (
@@ -709,7 +709,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
// SECCOMP
if data != nil {
- if value, exists := data.Annotations[seccompAnnotationKey]; exists {
+ if value, exists := labels[seccompLabelKey]; exists {
secConfig.SeccompProfileFromImage = value
}
}
diff --git a/cmd/podman/shared/pod.go b/cmd/podman/shared/pod.go
index d8d69c8fc..7b0b497fc 100644
--- a/cmd/podman/shared/pod.go
+++ b/cmd/podman/shared/pod.go
@@ -10,14 +10,8 @@ import (
"github.com/pkg/errors"
)
-const (
- PodStateStopped = "Stopped"
- PodStateRunning = "Running"
- PodStatePaused = "Paused"
- PodStateExited = "Exited"
- PodStateErrored = "Error"
- PodStateCreated = "Created"
-)
+// TODO GetPodStatus and CreatePodStatusResults should removed once the adapter
+// and shared packages are reworked. It has now been duplicated in libpod proper.
// GetPodStatus determines the status of the pod based on the
// statuses of the containers in the pod.
@@ -25,7 +19,7 @@ const (
func GetPodStatus(pod *libpod.Pod) (string, error) {
ctrStatuses, err := pod.Status()
if err != nil {
- return PodStateErrored, err
+ return define.PodStateErrored, err
}
return CreatePodStatusResults(ctrStatuses)
}
@@ -33,45 +27,45 @@ func GetPodStatus(pod *libpod.Pod) (string, error) {
func CreatePodStatusResults(ctrStatuses map[string]define.ContainerStatus) (string, error) {
ctrNum := len(ctrStatuses)
if ctrNum == 0 {
- return PodStateCreated, nil
+ return define.PodStateCreated, nil
}
statuses := map[string]int{
- PodStateStopped: 0,
- PodStateRunning: 0,
- PodStatePaused: 0,
- PodStateCreated: 0,
- PodStateErrored: 0,
+ define.PodStateStopped: 0,
+ define.PodStateRunning: 0,
+ define.PodStatePaused: 0,
+ define.PodStateCreated: 0,
+ define.PodStateErrored: 0,
}
for _, ctrStatus := range ctrStatuses {
switch ctrStatus {
case define.ContainerStateExited:
fallthrough
case define.ContainerStateStopped:
- statuses[PodStateStopped]++
+ statuses[define.PodStateStopped]++
case define.ContainerStateRunning:
- statuses[PodStateRunning]++
+ statuses[define.PodStateRunning]++
case define.ContainerStatePaused:
- statuses[PodStatePaused]++
+ statuses[define.PodStatePaused]++
case define.ContainerStateCreated, define.ContainerStateConfigured:
- statuses[PodStateCreated]++
+ statuses[define.PodStateCreated]++
default:
- statuses[PodStateErrored]++
+ statuses[define.PodStateErrored]++
}
}
switch {
- case statuses[PodStateRunning] > 0:
- return PodStateRunning, nil
- case statuses[PodStatePaused] == ctrNum:
- return PodStatePaused, nil
- case statuses[PodStateStopped] == ctrNum:
- return PodStateExited, nil
- case statuses[PodStateStopped] > 0:
- return PodStateStopped, nil
- case statuses[PodStateErrored] > 0:
- return PodStateErrored, nil
+ case statuses[define.PodStateRunning] > 0:
+ return define.PodStateRunning, nil
+ case statuses[define.PodStatePaused] == ctrNum:
+ return define.PodStatePaused, nil
+ case statuses[define.PodStateStopped] == ctrNum:
+ return define.PodStateExited, nil
+ case statuses[define.PodStateStopped] > 0:
+ return define.PodStateStopped, nil
+ case statuses[define.PodStateErrored] > 0:
+ return define.PodStateErrored, nil
default:
- return PodStateCreated, nil
+ return define.PodStateCreated, nil
}
}
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 7f0c2260c..0e641f3a3 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -679,7 +679,7 @@ of the container is assumed to be managed externally.
**--seccomp-policy**=*policy*
-Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" annotation in the container image and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
+Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
Note that this feature is experimental and may change in the future.
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 2b1452b53..512a382a6 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -700,7 +700,7 @@ Note: On `SELinux` systems, the rootfs needs the correct label, which is by defa
**--seccomp-policy**=*policy*
-Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" annotation in the container image and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
+Specify the policy to select the seccomp profile. If set to *image*, Podman will look for a "io.podman.seccomp.profile" label in the container-image config and use its value as a seccomp profile. Otherwise, Podman will follow the *default* policy by applying the default profile unless specified otherwise via *--security-opt seccomp* as described below.
Note that this feature is experimental and may change in the future.
diff --git a/go.mod b/go.mod
index 54af7fda4..c4e6d64bf 100644
--- a/go.mod
+++ b/go.mod
@@ -9,12 +9,12 @@ require (
github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784
- github.com/containernetworking/plugins v0.8.2
+ github.com/containernetworking/plugins v0.8.5
github.com/containers/buildah v1.13.1
- github.com/containers/conmon v2.0.9+incompatible
+ github.com/containers/conmon v2.0.10+incompatible
github.com/containers/image/v5 v5.1.0
github.com/containers/psgo v1.4.0
- github.com/containers/storage v1.15.5
+ github.com/containers/storage v1.15.7
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/cri-o/ocicni v0.1.1-0.20190920040751-deac903fd99b
@@ -29,7 +29,7 @@ require (
github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect
github.com/elazarl/goproxy/ext v0.0.0-20190911111923-ecfe977594f1 // indirect
github.com/etcd-io/bbolt v1.3.3
- github.com/fatih/camelcase v1.0.0
+ github.com/fatih/camelcase v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.4.7
github.com/ghodss/yaml v1.0.0
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e
@@ -40,7 +40,7 @@ require (
github.com/gorilla/schema v1.1.0
github.com/hashicorp/go-multierror v1.0.0
github.com/hpcloud/tail v1.0.0
- github.com/json-iterator/go v1.1.8
+ github.com/json-iterator/go v1.1.9
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
@@ -51,7 +51,7 @@ require (
github.com/opencontainers/runtime-tools v0.9.0
github.com/opencontainers/selinux v1.3.0
github.com/opentracing/opentracing-go v1.1.0
- github.com/pkg/errors v0.9.0
+ github.com/pkg/errors v0.9.1
github.com/pkg/profile v1.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0
github.com/rootless-containers/rootlesskit v0.7.1
@@ -61,10 +61,10 @@ require (
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.4.0
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
- github.com/uber/jaeger-client-go v2.20.1+incompatible
+ github.com/uber/jaeger-client-go v2.22.1+incompatible
github.com/uber/jaeger-lib v0.0.0-20190122222657-d036253de8f5 // indirect
github.com/varlink/go v0.0.0-20190502142041-0f1d566d194b
- github.com/vishvananda/netlink v1.0.0
+ github.com/vishvananda/netlink v1.1.0
go.uber.org/atomic v1.4.0 // indirect
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
@@ -72,9 +72,9 @@ require (
golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2
google.golang.org/appengine v1.6.1 // indirect
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 // indirect
- gopkg.in/yaml.v2 v2.2.7
- k8s.io/api v0.17.0
- k8s.io/apimachinery v0.17.0
+ gopkg.in/yaml.v2 v2.2.8
+ k8s.io/api v0.17.2
+ k8s.io/apimachinery v0.17.2
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a // indirect
)
diff --git a/go.sum b/go.sum
index de7791f47..cf0cf98ac 100644
--- a/go.sum
+++ b/go.sum
@@ -73,6 +73,8 @@ github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784 h1:rqUVL
github.com/containernetworking/cni v0.7.2-0.20190904153231-83439463f784/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/containernetworking/plugins v0.8.2 h1:5lnwfsAYO+V7yXhysJKy3E1A2Gy9oVut031zfdOzI9w=
github.com/containernetworking/plugins v0.8.2/go.mod h1:TxALKWZpWL79BC3GOYKJzzXr7U8R23PdhwaLp6F3adc=
+github.com/containernetworking/plugins v0.8.5 h1:pCvEMrFf7yzJI8+/D/7jkvE96KD52b7/Eu+jpahihy8=
+github.com/containernetworking/plugins v0.8.5/go.mod h1:UZ2539umj8djuRQmBxuazHeJbYrLV8BSBejkk+she6o=
github.com/containers/buildah v1.12.0 h1:bi/8ACl8qobazwfYgNze5y+aRuBIG+R7lMStFbnDOxE=
github.com/containers/buildah v1.12.0/go.mod h1:yzPuQ/mJTPsfSLCyBPbeaoXgBLanjnf36M2cDzyckMg=
github.com/containers/buildah v1.13.1 h1:EdhllQxXmOZ56mGFf68AkrpIj9XtEkkGq0WaPWFuGM0=
@@ -83,6 +85,8 @@ github.com/containers/common v0.0.7 h1:eKYZLKfJ2d/RNDgecLDFv45cHb4imYzIcrQHx1Y02
github.com/containers/common v0.0.7/go.mod h1:lhWV3MLhO1+KGE2x6v9+K38MxpjXGso+edmpkFnCOqI=
github.com/containers/conmon v2.0.9+incompatible h1:YcEgk0Ny1WBdH35M2LKe2cG6FiQqzDdVaURw84XvS7A=
github.com/containers/conmon v2.0.9+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
+github.com/containers/conmon v2.0.10+incompatible h1:EiwL41r5vx8SxG+dyUmbJ3baV9GUWjijPOdCkzM6gWU=
+github.com/containers/conmon v2.0.10+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.0.0 h1:arnXgbt1ucsC/ndtSpiQY87rA0UjhF+/xQnPzqdBDn4=
github.com/containers/image/v5 v5.0.0/go.mod h1:MgiLzCfIeo8lrHi+4Lb8HP+rh513sm0Mlk6RrhjFOLY=
github.com/containers/image/v5 v5.1.0 h1:5FjAvPJniamuNNIQHkh4PnsL+n+xzs6Aonzaz5dqTEo=
@@ -103,10 +107,14 @@ github.com/containers/storage v1.15.4 h1:eiUtV9MOTnPHibO18nDRI+aDhKudY7WmAiJdyVM
github.com/containers/storage v1.15.4/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
github.com/containers/storage v1.15.5 h1:dBZx9yRFHod9c8FVaXlVtRqr2cmlAhpl+9rt87cE7J4=
github.com/containers/storage v1.15.5/go.mod h1:v0lq/3f+cXH3Y/HiDaFYRR0zilwDve7I4W7U5xQxvF8=
+github.com/containers/storage v1.15.7 h1:ecPmv2y/qpxeSTHZ147jQLO6to8wDn8yUPtDCZlz0H4=
+github.com/containers/storage v1.15.7/go.mod h1:gLZIp+/hP8nFn9tLS0uJlnk4h1tSoDu3oS2eFiaIqkE=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-iptables v0.4.2 h1:KH0EwId05JwWIfb96gWvkiT2cbuOu8ygqUaB+yPAwIg=
github.com/coreos/go-iptables v0.4.2/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
+github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@@ -282,6 +290,8 @@ github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62F
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/juju/errors v0.0.0-20180806074554-22422dad46e1/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20190613124551-e81189438503/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
@@ -295,6 +305,8 @@ github.com/klauspost/compress v1.8.1 h1:oygt2ychZFHOB6M9gUgajzgKrwRgHbGC77NwA4CO
github.com/klauspost/compress v1.8.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.4 h1:xhvAeUPQ2drNUhKtrGdTGNvV9nNafHMUkRyLkzxJoB4=
github.com/klauspost/compress v1.9.4/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.9.7 h1:hYW1gP94JUmAhBtJ+LNz5My+gBobDxPR1iVuKug26aA=
+github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
@@ -321,6 +333,8 @@ github.com/mattn/go-shellwords v1.0.5 h1:JhhFTIOslh5ZsPrpa3Wdg8bF0WI3b44EMblmU9w
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+github.com/mattn/go-shellwords v1.0.7 h1:KqhVjVZomx2puPACkj9vrGFqnp42Htvo9SEAWePHKOs=
+github.com/mattn/go-shellwords v1.0.7/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
@@ -409,6 +423,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k=
github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.4.0 h1:uCmaf4vVbWAOZz36k1hrQD7ijGRzLwaME8Am/7a4jZI=
github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -488,6 +504,8 @@ github.com/theckman/go-flock v0.7.1/go.mod h1:kjuth3y9VJ2aNlkNEO99G/8lp9fMIKaGyB
github.com/u-root/u-root v5.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY=
github.com/uber/jaeger-client-go v2.20.1+incompatible h1:HgqpYBng0n7tLJIlyT4kPCIv5XgCsF+kai1NnnrJzEU=
github.com/uber/jaeger-client-go v2.20.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
+github.com/uber/jaeger-client-go v2.22.1+incompatible h1:NHcubEkVbahf9t3p75TOCR83gdUHXjRJvjoBh1yACsM=
+github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v0.0.0-20190122222657-d036253de8f5 h1:CwmGyzHTzCqCdZJkWR0A7ucZXgrCY7spRcpvm7ci//s=
github.com/uber/jaeger-lib v0.0.0-20190122222657-d036253de8f5/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
@@ -507,10 +525,14 @@ github.com/vbauerster/mpb/v4 v4.11.1/go.mod h1:vMLa1J/ZKC83G2lB/52XpqT+ZZtFG4aZO
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM=
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
+github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc h1:R83G5ikgLMxrBvLh22JhdfI8K6YXEPHx5P03Uu3DRs4=
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f h1:nBX3nTcmxEtHSERBJaIo1Qa26VwRaopnZmfDQUXsF4I=
github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b h1:6cLsL+2FW6dRAdl5iMtHgRogVCff0QpRi9653YmdcJA=
@@ -595,6 +617,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -675,6 +698,8 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v0.0.0-20190624233834-05ebafbffc79/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
@@ -685,11 +710,15 @@ k8s.io/api v0.0.0-20190813020757-36bff7324fb7 h1:4uJOjRn9kWq4AqJRE8+qzmAy+lJd9rh
k8s.io/api v0.0.0-20190813020757-36bff7324fb7/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58=
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
+k8s.io/api v0.17.2 h1:NF1UFXcKN7/OOv1uxdRz3qfra8AHsPav5M93hlV9+Dc=
+k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010 h1:pyoq062NftC1y/OcnbSvgolyZDJ8y4fmUPWMkdA6gfU=
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8=
k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo=
k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
+k8s.io/apimachinery v0.17.2 h1:hwDQQFbdRlpnnsR64Asdi55GyCaIP/3WQpMmbNBeWr4=
+k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
k8s.io/client-go v0.0.0-20170217214107-bcde30fb7eae/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/client-go v0.0.0-20181219152756-3dd551c0f083 h1:+Qf/nITucAbm09aIdxvoA+7X0BwaXmQGVoR8k7Ynk9o=
k8s.io/client-go v0.0.0-20181219152756-3dd551c0f083/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 01f2d93bd..641bc8a91 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -1014,6 +1014,9 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
hostConfig.ShmSize = c.config.ShmSize
hostConfig.Runtime = "oci"
+ // Default CPUShares is 1024, but we may overwrite below.
+ hostConfig.CpuShares = 1024
+
// This is very expensive to initialize.
// So we don't want to initialize it unless we absolutely have to - IE,
// there are things that require a major:minor to path translation.
diff --git a/libpod/define/podstate.go b/libpod/define/podstate.go
new file mode 100644
index 000000000..2b59aabfb
--- /dev/null
+++ b/libpod/define/podstate.go
@@ -0,0 +1,19 @@
+package define
+
+const (
+ // PodStateCreated indicates the pod is created but has not been started
+ PodStateCreated = "Created"
+ // PodStateErrored indicates the pod is in an errored state where
+ // information about it can no longer be retrieved
+ PodStateErrored = "Error"
+ // PodStateExited indicates the pod ran but has been stopped
+ PodStateExited = "Exited"
+ // PodStatePaused indicates the pod has been paused
+ PodStatePaused = "Paused"
+ // PodStateRunning indicates that one or more of the containers in
+ // the pod is running
+ PodStateRunning = "Running"
+ // PodStateStopped indicates all of the containers belonging to the pod
+ // are stopped.
+ PodStateStopped = "Stopped"
+)
diff --git a/libpod/pod_status.go b/libpod/pod_status.go
new file mode 100644
index 000000000..3a44c4457
--- /dev/null
+++ b/libpod/pod_status.go
@@ -0,0 +1,59 @@
+package libpod
+
+import "github.com/containers/libpod/libpod/define"
+
+// GetPodStatus determines the status of the pod based on the
+// statuses of the containers in the pod.
+// Returns a string representation of the pod status
+func (p *Pod) GetPodStatus() (string, error) {
+ ctrStatuses, err := p.Status()
+ if err != nil {
+ return define.PodStateErrored, err
+ }
+ return CreatePodStatusResults(ctrStatuses)
+}
+
+func CreatePodStatusResults(ctrStatuses map[string]define.ContainerStatus) (string, error) {
+ ctrNum := len(ctrStatuses)
+ if ctrNum == 0 {
+ return define.PodStateCreated, nil
+ }
+ statuses := map[string]int{
+ define.PodStateStopped: 0,
+ define.PodStateRunning: 0,
+ define.PodStatePaused: 0,
+ define.PodStateCreated: 0,
+ define.PodStateErrored: 0,
+ }
+ for _, ctrStatus := range ctrStatuses {
+ switch ctrStatus {
+ case define.ContainerStateExited:
+ fallthrough
+ case define.ContainerStateStopped:
+ statuses[define.PodStateStopped]++
+ case define.ContainerStateRunning:
+ statuses[define.PodStateRunning]++
+ case define.ContainerStatePaused:
+ statuses[define.PodStatePaused]++
+ case define.ContainerStateCreated, define.ContainerStateConfigured:
+ statuses[define.PodStateCreated]++
+ default:
+ statuses[define.PodStateErrored]++
+ }
+ }
+
+ switch {
+ case statuses[define.PodStateRunning] > 0:
+ return define.PodStateRunning, nil
+ case statuses[define.PodStatePaused] == ctrNum:
+ return define.PodStatePaused, nil
+ case statuses[define.PodStateStopped] == ctrNum:
+ return define.PodStateExited, nil
+ case statuses[define.PodStateStopped] > 0:
+ return define.PodStateStopped, nil
+ case statuses[define.PodStateErrored] > 0:
+ return define.PodStateErrored, nil
+ default:
+ return define.PodStateCreated, nil
+ }
+}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index de7cfd3b8..e8952967d 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -836,3 +836,44 @@ func (r *Runtime) GetLatestContainer() (*Container, error) {
}
return ctrs[lastCreatedIndex], nil
}
+
+// PruneContainers removes stopped and exited containers from localstorage. A set of optional filters
+// can be provided to be more granular.
+func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int64, map[string]error, error) {
+ pruneErrors := make(map[string]error)
+ prunedContainers := make(map[string]int64)
+ // We add getting the exited and stopped containers via a filter
+ containerStateFilter := func(c *Container) bool {
+ if c.PodID() != "" {
+ return false
+ }
+ state, err := c.State()
+ if err != nil {
+ logrus.Error(err)
+ return false
+ }
+ if state == define.ContainerStateStopped || state == define.ContainerStateExited {
+ return true
+ }
+ return false
+ }
+ filterFuncs = append(filterFuncs, containerStateFilter)
+ delContainers, err := r.GetContainers(filterFuncs...)
+ if err != nil {
+ return nil, nil, err
+ }
+ for _, c := range delContainers {
+ ctr := c
+ size, err := ctr.RWSize()
+ if err != nil {
+ pruneErrors[ctr.ID()] = err
+ continue
+ }
+ err = r.RemoveContainer(context.Background(), ctr, false, false)
+ pruneErrors[ctr.ID()] = err
+ if err != nil {
+ prunedContainers[ctr.ID()] = size
+ }
+ }
+ return prunedContainers, pruneErrors, nil
+}
diff --git a/libpod/runtime_pod.go b/libpod/runtime_pod.go
index 66f9b10c9..e1dc31391 100644
--- a/libpod/runtime_pod.go
+++ b/libpod/runtime_pod.go
@@ -182,3 +182,31 @@ func (r *Runtime) GetRunningPods() ([]*Pod, error) {
}
return runningPods, nil
}
+
+// PrunePods removes unused pods and their containers from local storage.
+// If force is given, then running pods are also included in the pruning.
+func (r *Runtime) PrunePods() (map[string]error, error) {
+ response := make(map[string]error)
+ states := []string{define.PodStateStopped, define.PodStateExited}
+ filterFunc := func(p *Pod) bool {
+ state, _ := p.GetPodStatus()
+ for _, status := range states {
+ if state == status {
+ return true
+ }
+ }
+ return false
+ }
+ pods, err := r.Pods(filterFunc)
+ if err != nil {
+ return nil, err
+ }
+ if len(pods) < 1 {
+ return response, nil
+ }
+ for _, pod := range pods {
+ err := r.removePod(context.TODO(), pod, true, false)
+ response[pod.ID()] = err
+ }
+ return response, nil
+}
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
index 5891c361f..f89fc7011 100644
--- a/pkg/adapter/pods.go
+++ b/pkg/adapter/pods.go
@@ -58,9 +58,9 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal
}
logrus.Debugf("Setting maximum rm workers to %d", maxWorkers)
- states := []string{shared.PodStateStopped, shared.PodStateExited}
+ states := []string{define.PodStateStopped, define.PodStateExited}
if cli.Force {
- states = append(states, shared.PodStateRunning)
+ states = append(states, define.PodStateRunning)
}
pods, err := r.GetPodsByStatus(states)
diff --git a/pkg/adapter/pods_remote.go b/pkg/adapter/pods_remote.go
index 16d34769e..5ef1a9216 100644
--- a/pkg/adapter/pods_remote.go
+++ b/pkg/adapter/pods_remote.go
@@ -540,9 +540,9 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal
ok = []string{}
failures = map[string]error{}
)
- states := []string{shared.PodStateStopped, shared.PodStateExited}
+ states := []string{define.PodStateStopped, define.PodStateExited}
if cli.Force {
- states = append(states, shared.PodStateRunning)
+ states = append(states, define.PodStateRunning)
}
ids, err := iopodman.GetPodsByStatus().Call(r.Conn, states)
diff --git a/pkg/api/Makefile b/pkg/api/Makefile
index 915f0b9b3..f564b6516 100644
--- a/pkg/api/Makefile
+++ b/pkg/api/Makefile
@@ -2,12 +2,12 @@ export GO111MODULE=off
SWAGGER_OUT ?= swagger.yaml
+validate: ${SWAGGER_OUT}
+ swagger validate ${SWAGGER_OUT}
+
.PHONY: ${SWAGGER_OUT}
${SWAGGER_OUT}:
# generate doesn't remove file on error
rm -f ${SWAGGER_OUT}
- swagger generate spec -o ${SWAGGER_OUT} -w ./
+ swagger generate spec -o ${SWAGGER_OUT} -i tags.yaml -w ./
-# TODO: when pass validation move it under swagger.
-validate:
- swagger validate ${SWAGGER_OUT}
diff --git a/pkg/api/handlers/containers.go b/pkg/api/handlers/containers.go
index 6b09321a0..b5c78ce53 100644
--- a/pkg/api/handlers/containers.go
+++ b/pkg/api/handlers/containers.go
@@ -2,6 +2,7 @@ package handlers
import (
"fmt"
+ "github.com/docker/docker/api/types"
"net/http"
"github.com/containers/libpod/libpod"
@@ -192,3 +193,55 @@ func RestartContainer(w http.ResponseWriter, r *http.Request) {
// Success
utils.WriteResponse(w, http.StatusNoContent, "")
}
+
+func PruneContainers(w http.ResponseWriter, r *http.Request) {
+ var (
+ delContainers []string
+ space int64
+ )
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+
+ query := struct {
+ Filters map[string][]string `schema:"filter"`
+ }{}
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ filterFuncs, err := utils.GenerateFilterFuncsFromMap(runtime, query.Filters)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+
+ // Libpod response differs
+ if utils.IsLibpodRequest(r) {
+ var response []LibpodContainersPruneReport
+ for ctrID, size := range prunedContainers {
+ response = append(response, LibpodContainersPruneReport{ID: ctrID, SpaceReclaimed: size})
+ }
+ for ctrID, err := range pruneErrors {
+ response = append(response, LibpodContainersPruneReport{ID: ctrID, PruneError: err.Error()})
+ }
+ utils.WriteResponse(w, http.StatusOK, response)
+ return
+ }
+ for ctrID, size := range prunedContainers {
+ if pruneErrors[ctrID] == nil {
+ space += size
+ delContainers = append(delContainers, ctrID)
+ }
+ }
+ report := types.ContainersPruneReport{
+ ContainersDeleted: delContainers,
+ SpaceReclaimed: uint64(space),
+ }
+ utils.WriteResponse(w, http.StatusOK, report)
+}
diff --git a/pkg/api/handlers/generic/containers_create.go b/pkg/api/handlers/containers_create.go
index f98872690..4781b23bc 100644
--- a/pkg/api/handlers/generic/containers_create.go
+++ b/pkg/api/handlers/containers_create.go
@@ -1,4 +1,4 @@
-package generic
+package handlers
import (
"encoding/json"
@@ -10,7 +10,6 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
image2 "github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/namespaces"
createconfig "github.com/containers/libpod/pkg/spec"
@@ -25,7 +24,7 @@ import (
func CreateContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
- input := handlers.CreateContainerConfig{}
+ input := CreateContainerConfig{}
query := struct {
Name string `schema:"name"`
}{
@@ -40,7 +39,9 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
-
+ if len(input.HostConfig.Links) > 0 {
+ utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter"))
+ }
newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "NewFromLocal()"))
@@ -72,13 +73,13 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
}
response := ContainerCreateResponse{
- Id: ctr.ID(),
+ ID: ctr.ID(),
Warnings: []string{}}
utils.WriteResponse(w, http.StatusCreated, response)
}
-func makeCreateConfig(input handlers.CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) {
+func makeCreateConfig(input CreateContainerConfig, newImage *image2.Image) (createconfig.CreateConfig, error) {
var (
err error
init bool
diff --git a/pkg/api/handlers/decoder.go b/pkg/api/handlers/decoder.go
new file mode 100644
index 000000000..890d77ecc
--- /dev/null
+++ b/pkg/api/handlers/decoder.go
@@ -0,0 +1,91 @@
+package handlers
+
+import (
+ "encoding/json"
+ "reflect"
+ "time"
+
+ "github.com/gorilla/schema"
+ "github.com/sirupsen/logrus"
+)
+
+// NewAPIDecoder returns a configured schema.Decoder
+func NewAPIDecoder() *schema.Decoder {
+ _ = ParseDateTime
+
+ d := schema.NewDecoder()
+ d.IgnoreUnknownKeys(true)
+ d.RegisterConverter(map[string][]string{}, convertUrlValuesString)
+ d.RegisterConverter(time.Time{}, convertTimeString)
+ return d
+}
+
+// On client:
+// v := map[string][]string{
+// "dangling": {"true"},
+// }
+//
+// payload, err := jsoniter.MarshalToString(v)
+// if err != nil {
+// panic(err)
+// }
+// payload = url.QueryEscape(payload)
+func convertUrlValuesString(query string) reflect.Value {
+ f := map[string][]string{}
+
+ err := json.Unmarshal([]byte(query), &f)
+ if err != nil {
+ logrus.Infof("convertUrlValuesString: Failed to Unmarshal %s: %s", query, err.Error())
+ }
+
+ return reflect.ValueOf(f)
+}
+
+// isZero() can be used to determine if parsing failed.
+func convertTimeString(query string) reflect.Value {
+ var (
+ err error
+ t time.Time
+ )
+
+ for _, f := range []string{
+ time.UnixDate,
+ time.ANSIC,
+ time.RFC1123,
+ time.RFC1123Z,
+ time.RFC3339,
+ time.RFC3339Nano,
+ time.RFC822,
+ time.RFC822Z,
+ time.RFC850,
+ time.RubyDate,
+ time.Stamp,
+ time.StampMicro,
+ time.StampMilli,
+ time.StampNano,
+ } {
+ t, err = time.Parse(f, query)
+ if err == nil {
+ return reflect.ValueOf(t)
+ }
+
+ if _, isParseError := err.(*time.ParseError); isParseError {
+ // Try next format
+ continue
+ } else {
+ break
+ }
+ }
+
+ // We've exhausted all formats, or something bad happened
+ if err != nil {
+ logrus.Infof("convertTimeString: Failed to parse %s: %s", query, err.Error())
+ }
+ return reflect.ValueOf(time.Time{})
+}
+
+// ParseDateTime is a helper function to aid in parsing different Time/Date formats
+// isZero() can be used to determine if parsing failed.
+func ParseDateTime(query string) time.Time {
+ return convertTimeString(query).Interface().(time.Time)
+}
diff --git a/pkg/api/handlers/events.go b/pkg/api/handlers/events.go
index 900efa3da..44bf35254 100644
--- a/pkg/api/handlers/events.go
+++ b/pkg/api/handlers/events.go
@@ -1,9 +1,10 @@
package handlers
import (
- "encoding/json"
"fmt"
"net/http"
+ "strings"
+ "time"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/pkg/errors"
@@ -11,30 +12,24 @@ import (
func GetEvents(w http.ResponseWriter, r *http.Request) {
query := struct {
- Since string `json:"since"`
- Until string `json:"until"`
- Filters string `json:"filters"`
+ Since time.Time `schema:"since"`
+ Until time.Time `schema:"until"`
+ Filters map[string][]string `schema:"filters"`
}{}
if err := decodeQuery(r, &query); err != nil {
utils.Error(w, "Failed to parse parameters", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
}
- var filters = map[string][]string{}
- if found := hasVar(r, "filters"); found {
- if err := json.Unmarshal([]byte(query.Filters), &filters); err != nil {
- utils.BadRequest(w, "filters", query.Filters, err)
- return
+ var libpodFilters = []string{}
+ if _, found := r.URL.Query()["filters"]; found {
+ for k, v := range query.Filters {
+ libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
}
}
- var libpodFilters = make([]string, len(filters))
- for k, v := range filters {
- libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
- }
-
libpodEvents, err := getRuntime(r).GetEvents(libpodFilters)
if err != nil {
- utils.BadRequest(w, "filters", query.Filters, err)
+ utils.BadRequest(w, "filters", strings.Join(r.URL.Query()["filters"], ", "), err)
return
}
diff --git a/pkg/api/handlers/generic/config.go b/pkg/api/handlers/generic/config.go
deleted file mode 100644
index f715d25eb..000000000
--- a/pkg/api/handlers/generic/config.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package generic
-
-// ContainerCreateResponse is the response struct for creating a container
-type ContainerCreateResponse struct {
- // ID of the container created
- Id string `json:"Id"`
- // Warnings during container creation
- Warnings []string `json:"Warnings"`
-}
diff --git a/pkg/api/handlers/generic/containers.go b/pkg/api/handlers/generic/containers.go
index 5a0a51fd7..8dc73ae14 100644
--- a/pkg/api/handlers/generic/containers.go
+++ b/pkg/api/handlers/generic/containers.go
@@ -1,7 +1,6 @@
package generic
import (
- "context"
"encoding/binary"
"fmt"
"net/http"
@@ -11,12 +10,10 @@ import (
"time"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/logs"
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/util"
- "github.com/docker/docker/api/types"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -47,14 +44,40 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
}
func ListContainers(w http.ResponseWriter, r *http.Request) {
+ var (
+ containers []*libpod.Container
+ err error
+ )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
-
- containers, err := runtime.GetAllContainers()
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ All bool `schema:"all"`
+ Limit int `schema:"limit"`
+ Size bool `schema:"size"`
+ Filters map[string][]string `schema:"filters"`
+ }{
+ // override any golang type defaults
+ }
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+ if query.All {
+ containers, err = runtime.GetAllContainers()
+ } else {
+ containers, err = runtime.GetRunningContainers()
+ }
if err != nil {
utils.InternalServerError(w, err)
return
}
-
+ if _, found := mux.Vars(r)["limit"]; found {
+ last := query.Limit
+ if len(containers) > last {
+ containers = containers[len(containers)-last:]
+ }
+ }
+ // TODO filters still need to be applied
infoData, err := runtime.Info()
if err != nil {
utils.InternalServerError(w, errors.Wrapf(err, "Failed to obtain system info"))
@@ -125,51 +148,6 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) {
})
}
-func PruneContainers(w http.ResponseWriter, r *http.Request) {
- runtime := r.Context().Value("runtime").(*libpod.Runtime)
-
- containers, err := runtime.GetAllContainers()
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
-
- deletedContainers := []string{}
- var spaceReclaimed uint64
- for _, ctnr := range containers {
- // Only remove stopped or exit'ed containers.
- state, err := ctnr.State()
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- switch state {
- case define.ContainerStateStopped, define.ContainerStateExited:
- default:
- continue
- }
-
- deletedContainers = append(deletedContainers, ctnr.ID())
- cSize, err := ctnr.RootFsSize()
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- spaceReclaimed += uint64(cSize)
-
- err = runtime.RemoveContainer(context.Background(), ctnr, false, false)
- if err != nil && !(errors.Cause(err) == define.ErrCtrRemoved) {
- utils.InternalServerError(w, err)
- return
- }
- }
- report := types.ContainersPruneReport{
- ContainersDeleted: deletedContainers,
- SpaceReclaimed: spaceReclaimed,
- }
- utils.WriteResponse(w, http.StatusOK, report)
-}
-
func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
diff --git a/pkg/api/handlers/generic/images.go b/pkg/api/handlers/generic/images.go
index 395f64064..ba1cf47b4 100644
--- a/pkg/api/handlers/generic/images.go
+++ b/pkg/api/handlers/generic/images.go
@@ -6,7 +6,6 @@ import (
"io/ioutil"
"net/http"
"os"
- "strconv"
"strings"
"github.com/containers/buildah"
@@ -16,12 +15,10 @@ import (
"github.com/containers/libpod/pkg/api/handlers"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/util"
- "github.com/containers/storage"
"github.com/docker/docker/api/types"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
func ExportImage(w http.ResponseWriter, r *http.Request) {
@@ -59,17 +56,14 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
}
func PruneImages(w http.ResponseWriter, r *http.Request) {
- // 200 no error
- // 500 internal
var (
- dangling bool = true
- err error
+ filters []string
)
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
query := struct {
- filters map[string]string
+ Filters map[string][]string `schema:"filters"`
}{
// This is where you can override the golang default value for one of fields
}
@@ -79,61 +73,24 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
return
}
- // FIXME This is likely wrong due to it not being a map[string][]string
-
- // until ts is not supported on podman prune
- if len(query.filters["until"]) > 0 {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "until is not supported yet"))
- return
- }
- // labels are not supported on podman prune
- if len(query.filters["label"]) > 0 {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "labelis not supported yet"))
- return
- }
-
- if len(query.filters["dangling"]) > 0 {
- dangling, err = strconv.ParseBool(query.filters["dangling"])
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "processing dangling filter"))
- return
+ idr := []types.ImageDeleteResponseItem{}
+ for k, v := range query.Filters {
+ for _, val := range v {
+ filters = append(filters, fmt.Sprintf("%s=%s", k, val))
}
}
- idr := []types.ImageDeleteResponseItem{}
- //
- // This code needs to be migrated to libpod to work correctly. I could not
- // work my around the information docker needs with the existing prune in libpod.
- //
- pruneImages, err := runtime.ImageRuntime().GetPruneImages(!dangling, []image2.ImageFilter{})
+ pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), false, filters)
if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to get images to prune"))
+ utils.InternalServerError(w, err)
return
}
- for _, p := range pruneImages {
- repotags, err := p.RepoTags()
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to get repotags for image"))
- return
- }
- if err := p.Remove(r.Context(), true); err != nil {
- if errors.Cause(err) == storage.ErrImageUsedByContainer {
- logrus.Warnf("Failed to prune image %s as it is in use: %v", p.ID(), err)
- continue
- }
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to prune image"))
- return
- }
- // newimageevent is not export therefore we cannot record the event. this will be fixed
- // when the prune is fixed in libpod
- // defer p.newImageEvent(events.Prune)
- response := types.ImageDeleteResponseItem{
- Deleted: fmt.Sprintf("sha256:%s", p.ID()), // I ack this is not ideal
- }
- if len(repotags) > 0 {
- response.Untagged = repotags[0]
- }
- idr = append(idr, response)
+ for _, p := range pruneCids {
+ idr = append(idr, types.ImageDeleteResponseItem{
+ Deleted: p,
+ })
}
+
+ //FIXME/TODO to do this exacty correct, pruneimages needs to return idrs and space-reclaimed, then we are golden
ipr := types.ImagesPruneReport{
ImagesDeleted: idr,
SpaceReclaimed: 1, // TODO we cannot supply this right now
@@ -343,8 +300,6 @@ func GetImage(w http.ResponseWriter, r *http.Request) {
}
func GetImages(w http.ResponseWriter, r *http.Request) {
- // 200 ok
- // 500 internal
images, err := utils.GetImages(w, r)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed get images"))
diff --git a/pkg/api/handlers/generic/swagger.go b/pkg/api/handlers/generic/swagger.go
index 27e1fc18d..bfe527c41 100644
--- a/pkg/api/handlers/generic/swagger.go
+++ b/pkg/api/handlers/generic/swagger.go
@@ -1,11 +1,13 @@
package generic
+import "github.com/containers/libpod/pkg/api/handlers"
+
// Create container
// swagger:response ContainerCreateResponse
type swagCtrCreateResponse struct {
// in:body
Body struct {
- ContainerCreateResponse
+ handlers.ContainerCreateResponse
}
}
diff --git a/pkg/api/handlers/handler.go b/pkg/api/handlers/handler.go
index 4f303f6ab..d60a5b239 100644
--- a/pkg/api/handlers/handler.go
+++ b/pkg/api/handlers/handler.go
@@ -15,10 +15,11 @@ func getVar(r *http.Request, k string) string {
return mux.Vars(r)[k]
}
-func hasVar(r *http.Request, k string) bool {
- _, found := mux.Vars(r)[k]
- return found
-}
+// func hasVar(r *http.Request, k string) bool {
+// _, found := mux.Vars(r)[k]
+// return found
+// }
+
func getName(r *http.Request) string {
return getVar(r, "name")
}
diff --git a/pkg/api/handlers/images.go b/pkg/api/handlers/images.go
index b4acdc312..3f66a63c8 100644
--- a/pkg/api/handlers/images.go
+++ b/pkg/api/handlers/images.go
@@ -3,7 +3,6 @@ package handlers
import (
"fmt"
"io"
- "io/ioutil"
"net/http"
"os"
"strconv"
@@ -127,46 +126,6 @@ func GetImage(r *http.Request, name string) (*image.Image, error) {
return runtime.ImageRuntime().NewFromLocal(name)
}
-func LoadImage(w http.ResponseWriter, r *http.Request) {
- decoder := r.Context().Value("decoder").(*schema.Decoder)
- runtime := r.Context().Value("runtime").(*libpod.Runtime)
-
- query := struct {
- //quiet bool # quiet is currently unused
- }{
- // This is where you can override the golang default value for one of fields
- }
-
- if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
- return
- }
-
- var (
- err error
- writer io.Writer
- )
- f, err := ioutil.TempFile("", "api_load.tar")
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile"))
- return
- }
- if err := SaveFromBody(f, r); err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file"))
- return
- }
- id, err := runtime.LoadImage(r.Context(), "", f.Name(), writer, "")
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to load image"))
- return
- }
- utils.WriteResponse(w, http.StatusOK, struct {
- Stream string `json:"stream"`
- }{
- Stream: fmt.Sprintf("Loaded image: %s\n", id),
- })
-}
-
func SaveFromBody(f *os.File, r *http.Request) error { // nolint
if _, err := io.Copy(f, r.Body); err != nil {
return err
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index e16a4ea1f..db1cf26ff 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -1,7 +1,9 @@
package libpod
import (
+ "fmt"
"net/http"
+ "strconv"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
@@ -17,8 +19,6 @@ func StopContainer(w http.ResponseWriter, r *http.Request) {
}
func ContainerExists(w http.ResponseWriter, r *http.Request) {
- // 404 no such container
- // 200 ok
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := mux.Vars(r)["name"]
_, err := runtime.LookupContainer(name)
@@ -46,12 +46,18 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
utils.RemoveContainer(w, r, query.Force, query.Vols)
}
func ListContainers(w http.ResponseWriter, r *http.Request) {
+ var (
+ filters []string
+ )
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- Filter []string `schema:"filter"`
- Last int `schema:"last"`
- Size bool `schema:"size"`
- Sync bool `schema:"sync"`
+ All bool `schema:"all"`
+ Filter map[string][]string `schema:"filter"`
+ Last int `schema:"last"`
+ Namespace bool `schema:"namespace"`
+ Pod bool `schema:"pod"`
+ Size bool `schema:"size"`
+ Sync bool `schema:"sync"`
}{
// override any golang type defaults
}
@@ -63,15 +69,22 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
}
runtime := r.Context().Value("runtime").(*libpod.Runtime)
opts := shared.PsOptions{
- All: true,
+ All: query.All,
Last: query.Last,
Size: query.Size,
Sort: "",
- Namespace: true,
+ Namespace: query.Namespace,
+ Pod: query.Pod,
Sync: query.Sync,
}
-
- pss, err := shared.GetPsContainerOutput(runtime, opts, query.Filter, 2)
+ if len(query.Filter) > 0 {
+ for k, v := range query.Filter {
+ for _, val := range v {
+ filters = append(filters, fmt.Sprintf("%s=%s", k, val))
+ }
+ }
+ }
+ pss, err := shared.GetPsContainerOutput(runtime, opts, filters, 2)
if err != nil {
utils.InternalServerError(w, err)
}
@@ -117,19 +130,12 @@ func KillContainer(w http.ResponseWriter, r *http.Request) {
}
func WaitContainer(w http.ResponseWriter, r *http.Request) {
- _, err := utils.WaitContainer(w, r)
+ exitCode, err := utils.WaitContainer(w, r)
if err != nil {
utils.InternalServerError(w, err)
return
}
- utils.WriteResponse(w, http.StatusNoContent, "")
-}
-
-func PruneContainers(w http.ResponseWriter, r *http.Request) {
- // TODO Needs rebase to get filers; Also would be handy to define
- // an actual libpod container prune method.
- // force
- // filters
+ utils.WriteResponse(w, http.StatusOK, strconv.Itoa(int(exitCode)))
}
func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
@@ -139,10 +145,6 @@ func LogsFromContainer(w http.ResponseWriter, r *http.Request) {
// tail string
}
-func CreateContainer(w http.ResponseWriter, r *http.Request) {
-
-}
-
func UnmountContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := mux.Vars(r)["name"]
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 0d4e220a8..9f0876618 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -1,9 +1,12 @@
package libpod
import (
+ "fmt"
+ "io"
"io/ioutil"
"net/http"
"os"
+ "strconv"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/api/handlers"
@@ -42,12 +45,12 @@ func ImageExists(w http.ResponseWriter, r *http.Request) {
func ImageTree(w http.ResponseWriter, r *http.Request) {
// tree is a bit of a mess ... logic is in adapter and therefore not callable from here. needs rework
- //name := mux.Vars(r)["name"]
- //_, layerInfoMap, _, err := s.Runtime.Tree(name)
- //if err != nil {
+ // name := mux.Vars(r)["name"]
+ // _, layerInfoMap, _, err := s.Runtime.Tree(name)
+ // if err != nil {
// Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "Failed to find image information for %q", name))
// return
- //}
+ // }
// it is not clear to me how to deal with this given all the processing of the image
// is in main. we need to discuss how that really should be and return something useful.
handlers.UnsupportedHandler(w, r)
@@ -90,13 +93,14 @@ func GetImages(w http.ResponseWriter, r *http.Request) {
}
func PruneImages(w http.ResponseWriter, r *http.Request) {
- // 200 ok
- // 500 internal
+ var (
+ all bool
+ err error
+ )
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- All bool `schema:"all"`
- Filters []string `schema:"filters"`
+ Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}
@@ -106,7 +110,19 @@ func PruneImages(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
- cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, query.Filters)
+
+ var libpodFilters = []string{}
+ if _, found := r.URL.Query()["filters"]; found {
+ all, err = strconv.ParseBool(query.Filters["all"][0])
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ for k, v := range query.Filters {
+ libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", k, v[0]))
+ }
+ }
+ cids, err := runtime.ImageRuntime().PruneImages(r.Context(), all, libpodFilters)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
return
@@ -163,3 +179,47 @@ func ExportImage(w http.ResponseWriter, r *http.Request) {
defer os.Remove(tmpfile.Name())
utils.WriteResponse(w, http.StatusOK, rdr)
}
+
+func ImportImage(w http.ResponseWriter, r *http.Request) {
+ // TODO this is basically wrong
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+
+ query := struct {
+ Changes map[string]string `json:"changes"`
+ Message string `json:"message"`
+ Quiet bool `json:"quiet"`
+ }{
+ // This is where you can override the golang default value for one of fields
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ var (
+ err error
+ writer io.Writer
+ )
+ f, err := ioutil.TempFile("", "api_load.tar")
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to create tempfile"))
+ return
+ }
+ if err := handlers.SaveFromBody(f, r); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to write temporary file"))
+ return
+ }
+ id, err := runtime.LoadImage(r.Context(), "", f.Name(), writer, "")
+ //id, err := runtime.Import(r.Context())
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "failed to load image"))
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, struct {
+ Stream string `json:"stream"`
+ }{
+ Stream: fmt.Sprintf("Loaded image: %s\n", id),
+ })
+}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 14f8e8de7..50d763338 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -108,7 +108,7 @@ func Pods(w http.ResponseWriter, r *http.Request) {
)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- filters []string `schema:"filters"`
+ Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}
@@ -117,10 +117,12 @@ func Pods(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
- if len(query.filters) > 0 {
+
+ if _, found := r.URL.Query()["filters"]; found {
utils.Error(w, "filters are not implemented yet", http.StatusInternalServerError, define.ErrNotImplemented)
return
}
+
pods, err := runtime.GetAllPods()
if err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
@@ -164,7 +166,7 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
decoder = r.Context().Value("decoder").(*schema.Decoder)
)
query := struct {
- timeout int `schema:"t"`
+ Timeout int `schema:"t"`
}{
// override any golang type defaults
}
@@ -207,8 +209,8 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
return
}
- if query.timeout > 0 {
- _, stopError = pod.StopWithTimeout(r.Context(), false, query.timeout)
+ if query.Timeout > 0 {
+ _, stopError = pod.StopWithTimeout(r.Context(), false, query.Timeout)
} else {
_, stopError = pod.Stop(r.Context(), false)
}
@@ -266,7 +268,7 @@ func PodDelete(w http.ResponseWriter, r *http.Request) {
decoder = r.Context().Value("decoder").(*schema.Decoder)
)
query := struct {
- force bool `schema:"force"`
+ Force bool `schema:"force"`
}{
// override any golang type defaults
}
@@ -282,7 +284,7 @@ func PodDelete(w http.ResponseWriter, r *http.Request) {
utils.PodNotFound(w, name, err)
return
}
- if err := runtime.RemovePod(r.Context(), pod, true, query.force); err != nil {
+ if err := runtime.RemovePod(r.Context(), pod, true, query.Force); err != nil {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
@@ -307,43 +309,14 @@ func PodRestart(w http.ResponseWriter, r *http.Request) {
func PodPrune(w http.ResponseWriter, r *http.Request) {
var (
- err error
- pods []*libpod.Pod
runtime = r.Context().Value("runtime").(*libpod.Runtime)
- decoder = r.Context().Value("decoder").(*schema.Decoder)
)
- query := struct {
- force bool `schema:"force"`
- }{
- // override any golang type defaults
- }
-
- if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
- return
- }
-
- if query.force {
- pods, err = runtime.GetAllPods()
- if err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
- } else {
- // TODO We need to make a libpod.PruneVolumes or this code will be a mess. Volumes
- // already does this right. It will also help clean this code path up with less
- // conditionals. We do this when we integrate with libpod again.
- utils.Error(w, "not implemented", http.StatusInternalServerError, errors.New("not implemented"))
+ pruned, err := runtime.PrunePods()
+ if err != nil {
+ utils.InternalServerError(w, err)
return
}
- for _, p := range pods {
- if err := runtime.RemovePod(r.Context(), p, true, query.force); err != nil {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
- return
- }
- }
- utils.WriteResponse(w, http.StatusNoContent, "")
+ utils.WriteResponse(w, http.StatusOK, pruned)
}
func PodPause(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/api/handlers/swagger.go b/pkg/api/handlers/swagger.go
index 0db4e19b6..faae98798 100644
--- a/pkg/api/handlers/swagger.go
+++ b/pkg/api/handlers/swagger.go
@@ -58,6 +58,13 @@ type swagContainerPruneReport struct {
Body []ContainersPruneReport
}
+// Prune containers
+// swagger:response DocsLibpodPruneResponse
+type swagLibpodContainerPruneReport struct {
+ // in: body
+ Body []LibpodContainersPruneReport
+}
+
// Inspect container
// swagger:response DocsContainerInspectResponse
type swagContainerInspectResponse struct {
@@ -96,9 +103,7 @@ type swagLibpodInspectContainerResponse struct {
// swagger:response ListPodsResponse
type swagListPodsResponse struct {
// in:body
- Body struct {
- libpod.PodInspect
- }
+ Body []libpod.PodInspect
}
// Inspect pod
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 2526a3317..33cf1e95d 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -43,6 +43,12 @@ type ContainersPruneReport struct {
docker.ContainersPruneReport
}
+type LibpodContainersPruneReport struct {
+ ID string `json:"id"`
+ SpaceReclaimed int64 `json:"space"`
+ PruneError string `json:"error"`
+}
+
type Info struct {
docker.Info
BuildahVersion string
@@ -531,3 +537,11 @@ func portsToPortSet(input map[string]struct{}) (nat.PortSet, error) {
}
return ports, nil
}
+
+// ContainerCreateResponse is the response struct for creating a container
+type ContainerCreateResponse struct {
+ // ID of the container created
+ ID string `json:"id"`
+ // Warnings during container creation
+ Warnings []string `json:"Warnings"`
+}
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index 64d3d378a..2c986db3a 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -6,6 +6,7 @@ import (
"syscall"
"time"
+ "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/gorilla/mux"
@@ -83,7 +84,7 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
}
if len(query.Condition) > 0 {
- return 0, errors.Errorf("the condition parameter is not supported")
+ UnSupportedParameter("condition")
}
name := mux.Vars(r)["name"]
@@ -101,3 +102,21 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
}
return con.Wait()
}
+
+// GenerateFilterFuncsFromMap is used to generate un-executed functions that can be used to filter
+// containers. It is specifically designed for the RESTFUL API input.
+func GenerateFilterFuncsFromMap(r *libpod.Runtime, filters map[string][]string) ([]libpod.ContainerFilter, error) {
+ var (
+ filterFuncs []libpod.ContainerFilter
+ )
+ for k, v := range filters {
+ for _, val := range v {
+ f, err := shared.GenerateContainerFilterFuncs(k, val, r)
+ if err != nil {
+ return filterFuncs, err
+ }
+ filterFuncs = append(filterFuncs, f)
+ }
+ }
+ return filterFuncs, nil
+}
diff --git a/pkg/api/handlers/utils/errors.go b/pkg/api/handlers/utils/errors.go
index b6f125c58..9d2081cd8 100644
--- a/pkg/api/handlers/utils/errors.go
+++ b/pkg/api/handlers/utils/errors.go
@@ -27,34 +27,34 @@ func Error(w http.ResponseWriter, apiMessage string, code int, err error) {
WriteJSON(w, code, em)
}
-func VolumeNotFound(w http.ResponseWriter, nameOrId string, err error) {
+func VolumeNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchVolume {
InternalServerError(w, err)
}
- msg := fmt.Sprintf("No such volume: %s", nameOrId)
+ msg := fmt.Sprintf("No such volume: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
-func ContainerNotFound(w http.ResponseWriter, nameOrId string, err error) {
+func ContainerNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchCtr {
InternalServerError(w, err)
}
- msg := fmt.Sprintf("No such container: %s", nameOrId)
+ msg := fmt.Sprintf("No such container: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
-func ImageNotFound(w http.ResponseWriter, nameOrId string, err error) {
+func ImageNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchImage {
InternalServerError(w, err)
}
- msg := fmt.Sprintf("No such image: %s", nameOrId)
+ msg := fmt.Sprintf("No such image: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
-func PodNotFound(w http.ResponseWriter, nameOrId string, err error) {
+func PodNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchPod {
InternalServerError(w, err)
}
- msg := fmt.Sprintf("No such pod: %s", nameOrId)
+ msg := fmt.Sprintf("No such pod: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
@@ -73,9 +73,11 @@ func BadRequest(w http.ResponseWriter, key string, value string, err error) {
}
type ErrorModel struct {
- // root cause
+ // API root cause formatted for automated parsing
+ // example: API root cause
Because string `json:"cause"`
- // error message
+ // human error message, formatted for a human to read
+ // example: human error message
Message string `json:"message"`
}
diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go
index 2fd9bffba..f2ce26f1a 100644
--- a/pkg/api/handlers/utils/handler.go
+++ b/pkg/api/handlers/utils/handler.go
@@ -51,3 +51,11 @@ func WriteJSON(w http.ResponseWriter, code int, value interface{}) {
logrus.Errorf("unable to write json: %q", err)
}
}
+
+func FilterMapToString(filters map[string][]string) (string, error) {
+ f, err := json.Marshal(filters)
+ if err != nil {
+ return "", err
+ }
+ return string(f), nil
+}
diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go
index 9445298ca..2b651584a 100644
--- a/pkg/api/handlers/utils/images.go
+++ b/pkg/api/handlers/utils/images.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
+ "github.com/gorilla/mux"
"github.com/gorilla/schema"
)
@@ -15,17 +16,23 @@ func GetImages(w http.ResponseWriter, r *http.Request) ([]*image.Image, error) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
query := struct {
- //all bool # all is currently unused
- filters []string
- //digests bool # digests is currently unused
+ All bool
+ Filters map[string][]string `schema:"filters"`
+ Digests bool
}{
// This is where you can override the golang default value for one of fields
}
+ // TODO I think all is implemented with a filter?
+
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
return nil, err
}
- filters := query.filters
- if len(filters) < 1 {
+ var filters = []string{}
+ if _, found := mux.Vars(r)["digests"]; found && query.Digests {
+ UnSupportedParameter("digests")
+ }
+
+ if _, found := r.URL.Query()["filters"]; found {
filters = append(filters, fmt.Sprintf("reference=%s", ""))
}
return runtime.ImageRuntime().GetImagesWithFilters(filters)
diff --git a/pkg/api/server/docs.go b/pkg/api/server/docs.go
new file mode 100644
index 000000000..c989c7927
--- /dev/null
+++ b/pkg/api/server/docs.go
@@ -0,0 +1,30 @@
+// Package api Provides a container compatible interface. (Experimental)
+//
+// This documentation describes the HTTP Libpod interface. It is to be considered
+// only as experimental as this point. The endpoints, parameters, inputs, and
+// return values can all change.
+//
+// Terms Of Service:
+//
+// Schemes: http, https
+// Host: podman.io
+// BasePath: /
+// Version: 0.0.1
+// License: Apache-2.0 https://opensource.org/licenses/Apache-2.0
+// Contact: Podman <podman@lists.podman.io> https://podman.io/community/
+//
+// InfoExtensions:
+// x-logo:
+// - url: https://raw.githubusercontent.com/containers/libpod/master/logo/podman-logo.png
+// - altText: "Podman logo"
+//
+// Produces:
+// - application/json
+// - text/plain
+// - text/html
+//
+// Consumes:
+// - application/json
+// - application/x-tar
+// swagger:meta
+package server
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index 833bb5197..abae81c38 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -23,25 +23,39 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// type: string
// description: container name
// responses:
- // '201':
- // $ref: "#/responses/ContainerCreateResponse"
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '409':
- // "$ref": "#/responses/ConflictError"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/create"), APIHandler(s.Context, generic.CreateContainer)).Methods(http.MethodPost)
+ // 201:
+ // $ref: "#/responses/ContainerCreateResponse"
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 409:
+ // $ref: "#/responses/ConflictError"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/create"), APIHandler(s.Context, handlers.CreateContainer)).Methods(http.MethodPost)
// swagger:operation GET /containers/json compat listContainers
// ---
- // tags:
- // - containers (compat)
+ // tags:
+ // - containers (compat)
// summary: List containers
// description: Returns a list of containers
// parameters:
// - in: query
+ // name: all
+ // type: boolean
+ // default: false
+ // description: Return all containers. By default, only running containers are shown
+ // - in: query
+ // name: limit
+ // description: Return this number of most recently created containers, including non-running ones.
+ // type: integer
+ // - in: query
+ // name: size
+ // type: boolean
+ // default: false
+ // description: Return the size of container as fields SizeRw and SizeRootFs.
+ // - in: query
// name: filters
// type: string
// description: |
@@ -63,17 +77,17 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // "$ref": "#/responses/DocsListContainer"
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 200:
+ // $ref: "#/responses/DocsListContainer"
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 500:
+ // $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/containers/json"), APIHandler(s.Context, generic.ListContainers)).Methods(http.MethodGet)
// swagger:operation POST /containers/prune compat pruneContainers
// ---
- // tags:
- // - containers (compat)
+ // tags:
+ // - containers (compat)
// summary: Delete stopped containers
// description: Remove containers not in use
// parameters:
@@ -87,76 +101,78 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // "$ref": "#/responses/DocsContainerPruneReport"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/prune"), APIHandler(s.Context, generic.PruneContainers)).Methods(http.MethodPost)
- // swagger:operation DELETE /containers/{nameOrID} compat removeContainer
+ // 200:
+ // $ref: "#/responses/DocsContainerPruneReport"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/prune"), APIHandler(s.Context, handlers.PruneContainers)).Methods(http.MethodPost)
+ // swagger:operation DELETE /containers/{name} compat removeContainer
// ---
- // tags:
- // - containers (compat)
+ // tags:
+ // - containers (compat)
// summary: Remove a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: force
- // type: bool
+ // type: boolean
// default: false
// description: If the container is running, kill it before removing it.
// - in: query
// name: v
- // type: bool
+ // type: boolean
// default: false
// description: Remove the volumes associated with the container.
// - in: query
// name: link
- // type: bool
+ // type: boolean
// description: not supported
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '409':
- // "$ref": "#/responses/ConflictError"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}"), APIHandler(s.Context, generic.RemoveContainer)).Methods(http.MethodDelete)
- // swagger:operation GET /containers/{nameOrID}/json compat getContainer
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 409:
+ // $ref: "#/responses/ConflictError"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}"), APIHandler(s.Context, generic.RemoveContainer)).Methods(http.MethodDelete)
+ // swagger:operation GET /containers/{name}/json compat getContainer
// ---
- // tags:
- // - containers (compat)
+ // tags:
+ // - containers (compat)
// summary: Inspect container
// description: Return low-level information about a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or id of the container
// - in: query
// name: size
- // type: bool
+ // type: boolean
// default: false
// description: include the size of the container
// produces:
// - application/json
// responses:
- // '200':
- // "$ref": "#/responses/DocsContainerInspectResponse"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/json"), APIHandler(s.Context, generic.GetContainer)).Methods(http.MethodGet)
- // swagger:operation post /containers/{nameOrID}/kill compat killcontainer
+ // 200:
+ // $ref: "#/responses/DocsContainerInspectResponse"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/json"), APIHandler(s.Context, generic.GetContainer)).Methods(http.MethodGet)
+ // swagger:operation post /containers/{name}/kill compat killcontainer
// ---
// tags:
// - containers (compat)
@@ -164,26 +180,29 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Signal to send to the container as an integer or string (e.g. SIGINT)
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: signal
- // type: int
+ // type: string
+ // default: TERM
// description: signal to be sent to container
+ // default: SIGKILL
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '409':
- // "$ref": "#/responses/ConflictError"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/kill"), APIHandler(s.Context, generic.KillContainer)).Methods(http.MethodPost)
- // swagger:operation GET /containers/{nameOrID}/logs compat LogsFromContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 409:
+ // $ref: "#/responses/ConflictError"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/kill"), APIHandler(s.Context, generic.KillContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{name}/logs compat LogsFromContainer
// ---
// tags:
// - containers (compat)
@@ -191,20 +210,21 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Get stdout and stderr logs from a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: follow
- // type: bool
+ // type: boolean
// description: Keep connection after returning logs.
// - in: query
// name: stdout
- // type: bool
+ // type: boolean
// description: not supported
// - in: query
// name: stderr
- // type: bool
+ // type: boolean
// description: not supported?
// - in: query
// name: since
@@ -216,7 +236,7 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Only return logs before this time, as a UNIX timestamp
// - in: query
// name: timestamps
- // type: bool
+ // type: boolean
// default: false
// description: Add timestamps to every log line
// - in: query
@@ -227,14 +247,14 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: logs returned as a stream in response body.
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/logs"), APIHandler(s.Context, generic.LogsFromContainer)).Methods(http.MethodGet)
- // swagger:operation POST /containers/{nameOrID}/pause compat pauseContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/logs"), APIHandler(s.Context, generic.LogsFromContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{name}/pause compat pauseContainer
// ---
// tags:
// - containers (compat)
@@ -242,71 +262,75 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Use the cgroups freezer to suspend all processes in a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/pause"), APIHandler(s.Context, handlers.PauseContainer)).Methods(http.MethodPost)
- r.HandleFunc(VersionedPath("/containers/{name:..*}/rename"), APIHandler(s.Context, handlers.UnsupportedHandler)).Methods(http.MethodPost)
- // swagger:operation POST /containers/{nameOrID}/restart compat restartContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/pause"), APIHandler(s.Context, handlers.PauseContainer)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/containers/{name}/rename"), APIHandler(s.Context, handlers.UnsupportedHandler)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{name}/restart compat restartContainer
// ---
// tags:
// - containers (compat)
// summary: Restart container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: t
- // type: int
+ // type: integer
// description: timeout before sending kill signal to container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/restart"), APIHandler(s.Context, handlers.RestartContainer)).Methods(http.MethodPost)
- // swagger:operation POST /containers/{nameOrID}/start compat startContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/restart"), APIHandler(s.Context, handlers.RestartContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{name}/start compat startContainer
// ---
// tags:
// - containers (compat)
// summary: Start a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: detachKeys
// type: string
- // description: needs description
+ // description: "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _."
+ // default: ctrl-p,ctrl-q
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '304':
- // "$ref": "#/responses/ContainerAlreadyStartedError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/start"), APIHandler(s.Context, handlers.StartContainer)).Methods(http.MethodPost)
- // swagger:operation GET /containers/{nameOrID}/stats compat statsContainer
+ // 304:
+ // $ref: "#/responses/ContainerAlreadyStartedError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/start"), APIHandler(s.Context, handlers.StartContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{name}/stats compat statsContainer
// ---
// tags:
// - containers (compat)
@@ -314,58 +338,62 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: This returns a live stream of a container’s resource usage statistics.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: stream
- // type: bool
+ // type: boolean
// default: true
// description: Stream the output
// produces:
// - application/json
// responses:
- // '200':
- // description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/stats"), APIHandler(s.Context, generic.StatsContainer)).Methods(http.MethodGet)
- // swagger:operation POST /containers/{nameOrID}/stop compat stopContainer
+ // 200:
+ // description: OK
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/stats"), APIHandler(s.Context, generic.StatsContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{name}/stop compat stopContainer
// ---
// tags:
// - containers (compat)
// summary: Stop a container
+ // description: Stop a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: t
- // type: int
+ // type: integer
// description: number of seconds to wait before killing container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '304':
- // "$ref": "#/responses/ContainerAlreadyStoppedError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/stop"), APIHandler(s.Context, handlers.StopContainer)).Methods(http.MethodPost)
- // swagger:operation GET /containers/{nameOrID}/top compat topContainer
+ // 304:
+ // $ref: "#/responses/ContainerAlreadyStoppedError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/stop"), APIHandler(s.Context, handlers.StopContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /containers/{name}/top compat topContainer
// ---
// tags:
// - containers (compat)
// summary: List processes running inside a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -375,14 +403,14 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // "ref": "#/responses/DockerTopResponse"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
- // swagger:operation POST /containers/{nameOrID}/unpause compat unpauseContainer
+ // 200:
+ // $ref: "#/responses/DockerTopResponse"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /containers/{name}/unpause compat unpauseContainer
// ---
// tags:
// - containers (compat)
@@ -390,20 +418,21 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Resume a paused container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/unpause"), APIHandler(s.Context, handlers.UnpauseContainer)).Methods(http.MethodPost)
- // swagger:operation POST /containers/{nameOrID}/wait compat waitContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/unpause"), APIHandler(s.Context, handlers.UnpauseContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{name}/wait compat waitContainer
// ---
// tags:
// - containers (compat)
@@ -411,24 +440,25 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Block until a container stops, then returns the exit code.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: condition
// type: string
- // description: Wait until the container reaches the given condition
+ // description: not supported
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// $ref: "#/responses/ContainerWaitResponse"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/wait"), APIHandler(s.Context, generic.WaitContainer)).Methods(http.MethodPost)
- // swagger:operation POST /containers/{nameOrID}/attach compat attach
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/wait"), APIHandler(s.Context, generic.WaitContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{name}/attach compat attach
// ---
// tags:
// - containers (compat)
@@ -436,7 +466,8 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Hijacks the connection to forward the container's standard streams to the client.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -447,42 +478,42 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - in: query
// name: logs
// required: false
- // type: bool
+ // type: boolean
// description: Not yet supported
// - in: query
// name: stream
// required: false
- // type: bool
+ // type: boolean
// default: true
// description: If passed, must be set to true; stream=false is not yet supported
// - in: query
// name: stdout
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDOUT
// - in: query
// name: stderr
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDERR
// - in: query
// name: stdin
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDIN
// produces:
// - application/json
// responses:
- // '101':
+ // 101:
// description: No error, connection has been hijacked for transporting streams.
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/attach"), APIHandler(s.Context, handlers.AttachContainer)).Methods(http.MethodPost)
- // swagger:operation POST /containers/{nameOrID}/resize compat resize
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/attach"), APIHandler(s.Context, handlers.AttachContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /containers/{name}/resize compat resize
// ---
// tags:
// - containers (compat)
@@ -490,64 +521,109 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Resize the terminal attached to a container (for use with Attach).
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: h
- // type: int
+ // type: integer
// required: false
// description: Height to set for the terminal, in characters
// - in: query
// name: w
- // type: int
+ // type: integer
// required: false
// description: Width to set for the terminal, in characters
// produces:
// - application/json
// responses:
- // '200':
- // description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/containers/{name:..*}/resize"), APIHandler(s.Context, handlers.ResizeContainer)).Methods(http.MethodPost)
+ // 200:
+ // $ref: "#/responses/ok"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/containers/{name}/resize"), APIHandler(s.Context, handlers.ResizeContainer)).Methods(http.MethodPost)
/*
libpod endpoints
*/
- r.HandleFunc(VersionedPath("/libpod/containers/create"), APIHandler(s.Context, libpod.CreateContainer)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/create"), APIHandler(s.Context, handlers.CreateContainer)).Methods(http.MethodPost)
// swagger:operation GET /libpod/containers/json libpod libpodListContainers
// ---
// tags:
// - containers
// summary: List containers
// description: Returns a list of containers
+ // parameters:
+ // - in: query
+ // name: all
+ // type: boolean
+ // default: false
+ // description: Return all containers. By default, only running containers are shown
+ // - in: query
+ // name: limit
+ // description: Return this number of most recently created containers, including non-running ones.
+ // type: integer
+ // - in: query
+ // name: namespace
+ // type: boolean
+ // description: Include namespace information
+ // default: false
+ // - in: query
+ // name: pod
+ // type: boolean
+ // default: false
+ // description: Include Pod ID and Name if applicable
+ // - in: query
+ // name: size
+ // type: boolean
+ // default: false
+ // description: Return the size of container as fields SizeRw and SizeRootFs.
+ // - in: query
+ // name: sync
+ // type: boolean
+ // default: false
+ // description: Sync container state with OCI runtime
+ // - in: query
+ // name: filters
+ // type: string
+ // description: |
+ // Returns a list of containers.
+ // - ancestor=(<image-name>[:<tag>], <image id>, or <image@digest>)
+ // - before=(<container id> or <container name>)
+ // - expose=(<port>[/<proto>]|<startport-endport>/[<proto>])
+ // - exited=<int> containers with exit code of <int>
+ // - health=(starting|healthy|unhealthy|none)
+ // - id=<ID> a container's ID
+ // - is-task=(true|false)
+ // - label=key or label="key=value" of a container label
+ // - name=<name> a container's name
+ // - network=(<network id> or <network name>)
+ // - publish=(<port>[/<proto>]|<startport-endport>/[<proto>])
+ // - since=(<container id> or <container name>)
+ // - status=(created|restarting|running|removing|paused|exited|dead)
+ // - volume=(<volume name> or <mount point destination>)
// produces:
// - application/json
// responses:
- // '200':
- // schema:
- // "$ref": "#/responses/LibpodListContainersResponse"
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 200:
+ // $ref: "#/responses/LibpodListContainersResponse"
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 500:
+ // $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/json"), APIHandler(s.Context, libpod.ListContainers)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/containers/prune libpod libpodPruneContainers
+ // swagger:operation POST /libpod/containers/prune libpod libpodPruneContainers
// ---
// tags:
- // - containers
- // summary: Prune unused containers
- // description: Remove stopped and exited containers
+ // - containers
+ // summary: Delete stopped containers
+ // description: Remove containers not in use
// parameters:
// - in: query
- // name: force
- // type: bool
- // description: something
- // - in: query
// name: filters
// type: string
// description: |
@@ -557,11 +633,11 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // description: to be determined
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/prune"), APIHandler(s.Context, libpod.PruneContainers)).Methods(http.MethodPost)
+ // 200:
+ // $ref: "#/responses/DocsLibpodPruneResponse"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/prune"), APIHandler(s.Context, handlers.PruneContainers)).Methods(http.MethodPost)
// swagger:operation GET /libpod/containers/showmounted libpod showMounterContainers
// ---
// tags:
@@ -571,48 +647,50 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: mounted containers
// schema:
// type: object
// additionalProperties:
// type: string
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 500:
+ // $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/showmounted"), APIHandler(s.Context, libpod.ShowMountedContainers)).Methods(http.MethodGet)
- // swagger:operation DELETE /libpod/containers/json libpod libpodRemoveContainer
+ // swagger:operation DELETE /libpod/containers/{name} libpod libpodRemoveContainer
// ---
// tags:
// - containers
// summary: Delete container
+ // description: Delete container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: force
- // type: bool
+ // type: boolean
// description: need something
// - in: query
// name: v
- // type: bool
+ // type: boolean
// description: delete volumes
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '409':
- // "$ref": "#/responses/ConflictError"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}"), APIHandler(s.Context, libpod.RemoveContainer)).Methods(http.MethodDelete)
- // swagger:operation GET /libpod/containers/{nameOrID}/json libpod libpodGetContainer
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 409:
+ // $ref: "#/responses/ConflictError"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}"), APIHandler(s.Context, libpod.RemoveContainer)).Methods(http.MethodDelete)
+ // swagger:operation GET /libpod/containers/{name}/json libpod libpodGetContainer
// ---
// tags:
// - containers
@@ -620,24 +698,25 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Return low-level information about a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: size
- // type: bool
+ // type: boolean
// description: display filesystem usage
// produces:
// - application/json
// responses:
- // '200':
- // "$ref": "#/responses/LibpodInspectContainerResponse"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/json"), APIHandler(s.Context, libpod.GetContainer)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/containers/{nameOrID}/kill libpod libpodKillContainer
+ // 200:
+ // $ref: "#/responses/LibpodInspectContainerResponse"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/json"), APIHandler(s.Context, libpod.GetContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{name}/kill libpod libpodKillContainer
// ---
// tags:
// - containers
@@ -645,27 +724,28 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: send a signal to a container, defaults to killing the container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: signal
- // type: int
- // default: 15
- // description: signal to be sent to container
+ // type: string
+ // default: TERM
+ // description: signal to be sent to container, either by integer or SIG_ name
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '409':
- // "$ref": "#/responses/ConflictError"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/kill"), APIHandler(s.Context, libpod.KillContainer)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/containers/{nameOrID}/mount libpod mountContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 409:
+ // $ref: "#/responses/ConflictError"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/kill"), APIHandler(s.Context, libpod.KillContainer)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/containers/{name}/mount libpod mountContainer
// ---
// tags:
// - containers
@@ -673,46 +753,48 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Mount a container to the filesystem
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: mounted container
// schema:
// description: id
// type: string
// example: /var/lib/containers/storage/overlay/f3f693bd88872a1e3193f4ebb925f4c282e8e73aadb8ab3e7492754dda3a02a4/merged
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/mount"), APIHandler(s.Context, libpod.MountContainer)).Methods(http.MethodPost)
- // swagger:operation GET /libpod/containers/{nameOrID}/unmount libpod unmountContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/mount"), APIHandler(s.Context, libpod.MountContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/unmount libpod libpodUnmountContainer
// ---
// tags:
// - containers
// summary: Unmount a container
// description: Unmount a container from the filesystem
+ // produces:
+ // - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
- // produces:
- // - application/json
// responses:
- // '204':
- // description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/unmount"), APIHandler(s.Context, libpod.UnmountContainer)).Methods(http.MethodPost)
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/logs"), APIHandler(s.Context, libpod.LogsFromContainer)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/containers/{nameOrID}/pause libpod libpodPauseContainer
+ // 204:
+ // description: ok
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/unmount"), APIHandler(s.Context, libpod.UnmountContainer)).Methods(http.MethodPost)
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/logs"), APIHandler(s.Context, libpod.LogsFromContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{name}/pause libpod libpodPauseContainer
// ---
// tags:
// - containers
@@ -720,70 +802,74 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Use the cgroups freezer to suspend all processes in a container.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 404:
+ // "$ref": "#/responses/NoSuchContainer"
+ // 500:
+ // "$ref": "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/pause"), APIHandler(s.Context, handlers.PauseContainer)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/containers/{nameOrID}/restart libpod libpodRestartContainer
+ // swagger:operation POST /libpod/containers/{name}/restart libpod libpodRestartContainer
// ---
// tags:
// - containers
// summary: Restart a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: t
- // type: int
+ // type: integer
// description: timeout before sending kill signal to container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/restart"), APIHandler(s.Context, handlers.RestartContainer)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/containers/{nameOrID}/start libpod libpodStartContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/restart"), APIHandler(s.Context, handlers.RestartContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/start libpod libpodStartContainer
// ---
// tags:
// - containers
// summary: Start a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: detachKeys
// type: string
- // description: needs description
+ // description: "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _."
+ // default: ctrl-p,ctrl-q
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '304':
- // "$ref": "#/responses/ContainerAlreadyStartedError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/start"), APIHandler(s.Context, handlers.StartContainer)).Methods(http.MethodPost)
- // swagger:operation GET /libpod/containers/{nameOrID}/stats libpod statsContainer
+ // 304:
+ // $ref: "#/responses/ContainerAlreadyStartedError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/start"), APIHandler(s.Context, handlers.StartContainer)).Methods(http.MethodPost)
+ // swagger:operation GET /libpod/containers/{name}/stats libpod libpodStatsContainer
// ---
// tags:
// - containers
@@ -791,99 +877,102 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: This returns a live stream of a container’s resource usage statistics.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: stream
- // type: bool
+ // type: boolean
// default: true
// description: Stream the output
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/stats"), APIHandler(s.Context, generic.StatsContainer)).Methods(http.MethodGet)
- // swagger:operation GET /libpod/containers/{nameOrID}/top libpod libpodTopContainer
- //
- // List processes running inside a container. Note
- //
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/stats"), APIHandler(s.Context, generic.StatsContainer)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/containers/{name}/top libpod libpodTopContainer
// ---
// tags:
// - containers
+ // summary: List processes
+ // description: List processes running inside a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
- // description: the name or ID of the container
+ // description: |
+ // Name of container to query for processes
+ // (As of version 1.xx)
// - in: query
// name: stream
- // type: bool
+ // type: boolean
// default: true
// description: Stream the output
+ // - in: query
// name: ps_args
// type: string
+ // default: -ef
// description: arguments to pass to ps such as aux. Requires ps(1) to be installed in the container if no ps(1) compatible AIX descriptors are used.
// produces:
// - application/json
// responses:
- // '200':
- // "ref": "#/responses/DockerTopResponse"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/containers/{nameOrID}/unpause libpod libpodUnpauseContainer
+ // 200:
+ // $ref: "#/responses/DockerTopResponse"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/top"), APIHandler(s.Context, handlers.TopContainer)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{name}/unpause libpod libpodUnpauseContainer
// ---
// tags:
// - containers
// summary: Unpause Container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/unpause"), APIHandler(s.Context, handlers.UnpauseContainer)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/containers/{nameOrID}/wait libpod libpodWaitContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/unpause"), APIHandler(s.Context, handlers.UnpauseContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/wait libpod libpodWaitContainer
// ---
// tags:
// - containers
// summary: Wait on a container to exit
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
- // - in: query
- // name: condition
- // type: string
- // description: Wait until the container reaches the given condition
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/wait"), APIHandler(s.Context, libpod.WaitContainer)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/containers/{nameOrID}/exists libpod containerExists
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/wait"), APIHandler(s.Context, libpod.WaitContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/exists libpod containerExists
// ---
// tags:
// - containers
@@ -891,46 +980,48 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Quick way to determine if a container exists by name or ID
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: container exists
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/exists"), APIHandler(s.Context, libpod.ContainerExists)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/containers/{nameOrID}/stop libpod libpodStopContainer
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/exists"), APIHandler(s.Context, libpod.ContainerExists)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/containers/{name}/stop libpod libpodStopContainer
// ---
// tags:
// - containers
// summary: Stop a container
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: t
- // type: int
+ // type: integer
// description: number of seconds to wait before killing container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: no error
- // '304':
- // "$ref": "#/responses/ContainerAlreadyStoppedError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/stop"), APIHandler(s.Context, handlers.StopContainer)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/containers/{nameOrID}/attach libpod attach
+ // 304:
+ // $ref: "#/responses/ContainerAlreadyStoppedError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/stop"), APIHandler(s.Context, handlers.StopContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/attach libpod libpodAttach
// ---
// tags:
// - containers
@@ -938,7 +1029,8 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Hijacks the connection to forward the container's standard streams to the client.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -949,42 +1041,42 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// - in: query
// name: logs
// required: false
- // type: bool
+ // type: boolean
// description: Not yet supported
// - in: query
// name: stream
// required: false
- // type: bool
+ // type: boolean
// default: true
// description: If passed, must be set to true; stream=false is not yet supported
// - in: query
// name: stdout
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDOUT
// - in: query
// name: stderr
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDERR
// - in: query
// name: stdin
// required: false
- // type: bool
+ // type: boolean
// description: Attach to container STDIN
// produces:
// - application/json
// responses:
- // '101':
+ // 101:
// description: No error, connection has been hijacked for transporting streams.
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/attach"), APIHandler(s.Context, handlers.AttachContainer)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/containers/{nameOrID}/resize libpod resize
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/attach"), APIHandler(s.Context, handlers.AttachContainer)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/containers/{name}/resize libpod libpodResize
// ---
// tags:
// - containers
@@ -992,28 +1084,29 @@ func (s *APIServer) RegisterContainersHandlers(r *mux.Router) error {
// description: Resize the terminal attached to a container (for use with Attach).
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: h
- // type: int
+ // type: integer
// required: false
// description: Height to set for the terminal, in characters
// - in: query
// name: w
- // type: int
+ // type: integer
// required: false
// description: Width to set for the terminal, in characters
// produces:
// - application/json
// responses:
- // '200':
- // description: no error
- // '404':
- // "$ref": "#/responses/NoSuchContainer"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/resize"), APIHandler(s.Context, handlers.ResizeContainer)).Methods(http.MethodPost)
+ // 200:
+ // $ref: "#/responses/ok"
+ // 404:
+ // $ref: "#/responses/NoSuchContainer"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/containers/{name}/resize"), APIHandler(s.Context, handlers.ResizeContainer)).Methods(http.MethodPost)
return nil
}
diff --git a/pkg/api/server/register_distribution.go b/pkg/api/server/register_distribution.go
index 23820b4a7..b0ac61fb8 100644
--- a/pkg/api/server/register_distribution.go
+++ b/pkg/api/server/register_distribution.go
@@ -6,6 +6,6 @@ import (
)
func (s *APIServer) RegisterDistributionHandlers(r *mux.Router) error {
- r.HandleFunc(VersionedPath("/distribution/{name:..*}/json"), handlers.UnsupportedHandler)
+ r.HandleFunc(VersionedPath("/distribution/{name}/json"), handlers.UnsupportedHandler)
return nil
}
diff --git a/pkg/api/server/register_events.go b/pkg/api/server/register_events.go
index 56cf96de1..a32244f4d 100644
--- a/pkg/api/server/register_events.go
+++ b/pkg/api/server/register_events.go
@@ -8,24 +8,29 @@ import (
func (s *APIServer) RegisterEventsHandlers(r *mux.Router) error {
// swagger:operation GET /events system getEvents
// ---
+ // tags:
+ // - system
// summary: Returns events filtered on query parameters
+ // description: Returns events filtered on query parameters
// produces:
// - application/json
// parameters:
// - name: since
+ // type: string
// in: query
// description: start streaming events from this time
// - name: until
+ // type: string
// in: query
// description: stop streaming events later than this
// - name: filters
+ // type: string
// in: query
// description: JSON encoded map[string][]string of constraints
// responses:
- // "200":
- // description: OK
- // "500":
- // description: Failed
+ // 200:
+ // $ref: "#/responses/ok"
+ // 500:
// "$ref": "#/responses/InternalError"
r.Handle(VersionedPath("/events"), APIHandler(s.Context, handlers.GetEvents))
return nil
diff --git a/pkg/api/server/register_healthcheck.go b/pkg/api/server/register_healthcheck.go
index e4cc145d5..1286324f0 100644
--- a/pkg/api/server/register_healthcheck.go
+++ b/pkg/api/server/register_healthcheck.go
@@ -8,6 +8,6 @@ import (
)
func (s *APIServer) registerHealthCheckHandlers(r *mux.Router) error {
- r.Handle(VersionedPath("/libpod/containers/{name:..*}/runhealthcheck"), APIHandler(s.Context, libpod.RunHealthCheck)).Methods(http.MethodGet)
+ r.Handle(VersionedPath("/libpod/containers/{name}/runhealthcheck"), APIHandler(s.Context, libpod.RunHealthCheck)).Methods(http.MethodGet)
return nil
}
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 8ea079654..c59d3d379 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -11,11 +11,10 @@ import (
func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// swagger:operation POST /images/create compat createImage
- //
// ---
// tags:
// - images (compat)
- // summary: Create an image from an image
+ // summary: Create an image
// description: Create an image by either pulling it from a registry or importing it.
// produces:
// - application/json
@@ -25,53 +24,30 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// type: string
// description: needs description
// - in: query
- // name: tag
- // type: string
- // description: needs description
- // responses:
- // '200':
- // schema:
- // items:
- // $ref: "to be determined"
- // '404':
- // description: repo or image does not exist
- // schema:
- // $ref: "#/responses/InternalError"
- // '500':
- // description: unexpected error
- // schema:
- // $ref: '#/responses/GenericError'
- r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}")
- // swagger:operation POST /images/create compat createImage
- // ---
- // tags:
- // - images (compat)
- // summary: Create an image from Source
- // description: Create an image by either pulling it from a registry or importing it.
- // produces:
- // - application/json
- // parameters:
- // - in: query
// name: fromSrc
// type: string
// description: needs description
// - in: query
- // name: changes
- // type: to be determined
+ // name: tag
+ // type: string
// description: needs description
+ // - in: header
+ // name: X-Registry-Auth
+ // type: string
+ // description: A base64-encoded auth configuration.
+ // - in: body
+ // name: request
+ // schema:
+ // type: string
+ // description: Image content if fromSrc parameter was used
// responses:
- // '200':
- // schema:
- // items:
- // $ref: "to be determined"
- // '404':
- // description: repo or image does not exist
- // schema:
- // $ref: "#/responses/InternalError"
- // '500':
- // description: unexpected error
- // schema:
- // $ref: '#/responses/GenericError'
+ // 200:
+ // $ref: "#/responses/ok"
+ // 404:
+ // $ref: "#/responses/NoSuchImage"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromImage)).Methods(http.MethodPost).Queries("fromImage", "{fromImage}")
r.Handle(VersionedPath("/images/create"), APIHandler(s.Context, generic.CreateImageFromSrc)).Methods(http.MethodPost).Queries("fromSrc", "{fromSrc}")
// swagger:operation GET /images/json compat listImages
// ---
@@ -79,20 +55,36 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// - images (compat)
// summary: List Images
// description: Returns a list of images on the server. Note that it uses a different, smaller representation of an image than inspecting a single image.
+ // parameters:
+ // - name: all
+ // in: query
+ // description: "Show all images. Only images from a final layer (no children) are shown by default."
+ // type: boolean
+ // default: false
+ // - name: filters
+ // in: query
+ // description: |
+ // A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
+ // - `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
+ // - `dangling=true`
+ // - `label=key` or `label="key=value"` of an image label
+ // - `reference`=(`<image-name>[:<tag>]`)
+ // - `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
+ // type: string
+ // - name: digests
+ // in: query
+ // description: Not supported
+ // type: boolean
+ // default: false
// produces:
// - application/json
// responses:
- // '200':
- // schema:
- // type: array
- // items:
- // schema:
- // $ref: "#/responses/DockerImageSummary"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 200:
+ // $ref: "#/responses/DockerImageSummary"
+ // 500:
+ // $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/images/json"), APIHandler(s.Context, generic.GetImages)).Methods(http.MethodGet)
- // swagger:operation POST /images/load compat loadImage
- //
+ // swagger:operation POST /images/load compat importImage
// ---
// tags:
// - images (compat)
@@ -101,20 +93,21 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// parameters:
// - in: query
// name: quiet
- // type: bool
+ // type: boolean
// description: not supported
// - in: body
+ // name: request
// description: tarball of container image
- // type: string
- // format: binary
+ // schema:
+ // type: string
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: no error
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/images/load"), APIHandler(s.Context, handlers.LoadImage)).Methods(http.MethodPost)
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/load"), APIHandler(s.Context, libpod.ImportImage)).Methods(http.MethodPost)
// swagger:operation POST /images/prune compat pruneImages
// ---
// tags:
@@ -135,12 +128,10 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // schema:
- // items:
- // $ref: "#/responses/DocsImageDeleteResponse"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 200:
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // 500:
+ // $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/images/prune"), APIHandler(s.Context, generic.PruneImages)).Methods(http.MethodPost)
// swagger:operation GET /images/search compat searchImages
// ---
@@ -155,7 +146,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: term to search
// - in: query
// name: limit
- // type: int
+ // type: integer
// description: maximum number of results
// - in: query
// name: filters
@@ -168,39 +159,44 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // $ref: "#/responses/DocsSearchResponse"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 200:
+ // $ref: "#/responses/DocsSearchResponse"
+ // 500:
+ // $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/images/search"), APIHandler(s.Context, handlers.SearchImages)).Methods(http.MethodGet)
- // swagger:operation DELETE /images/{nameOrID} compat removeImage
+ // swagger:operation DELETE /images/{name} compat removeImage
// ---
// tags:
// - images (compat)
// summary: Remove Image
// description: Delete an image from local storage
// parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: name or ID of image to delete
// - in: query
// name: force
- // type: bool
+ // type: boolean
// description: remove the image even if used by containers or has other tags
// - in: query
// name: noprune
- // type: bool
+ // type: boolean
// description: not supported. will be logged as an invalid parameter if enabled
// produces:
// - application/json
// responses:
- // '200':
- // $ref: "#/responses/DocsImageDeleteResponse"
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '409':
- // $ref: '#/responses/ConflictError'
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/images/{name:..*}"), APIHandler(s.Context, handlers.RemoveImage)).Methods(http.MethodDelete)
- // swagger:operation GET /images/{nameOrID}/get compat exportImage
+ // 200:
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 409:
+ // $ref: '#/responses/ConflictError'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/name"), APIHandler(s.Context, handlers.RemoveImage)).Methods(http.MethodDelete)
+ // swagger:operation GET /images/{name}/get compat exportImage
// ---
// tags:
// - images (compat)
@@ -208,21 +204,22 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Export an image in tarball format
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: no error
// schema:
// type: string
// format: binary
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/images/{name:..*}/get"), APIHandler(s.Context, generic.ExportImage)).Methods(http.MethodGet)
- // swagger:operation GET /images/{nameOrID}/history compat imageHistory
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/images/{name}/get"), APIHandler(s.Context, generic.ExportImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/{name}/history compat imageHistory
// ---
// tags:
// - images (compat)
@@ -230,20 +227,21 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Return parent layers of an image.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// $ref: "#/responses/DocsHistory"
- // '404':
+ // 404:
// $ref: "#/responses/NoSuchImage"
- // '500':
+ // 500:
// $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/images/{name:..*}/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
- // swagger:operation GET /images/{nameOrID}/json compat inspectImage
+ r.Handle(VersionedPath("/images/{name}/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
+ // swagger:operation GET /images/{name}/json compat inspectImage
// ---
// tags:
// - images (compat)
@@ -251,20 +249,21 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Return low-level information about an image.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
- // $ref: "#/responses/DocsImageInspect"
- // '404':
- // $ref: "#/responses/NoSuchImage"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/images/{name:..*}/json"), APIHandler(s.Context, generic.GetImage))
- // swagger:operation POST /images/{nameOrID}/tag compat tagImage
+ // 200:
+ // $ref: "#/responses/DocsImageInspect"
+ // 404:
+ // $ref: "#/responses/NoSuchImage"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/images/{name}/json"), APIHandler(s.Context, generic.GetImage))
+ // swagger:operation POST /images/{name}/tag compat tagImage
// ---
// tags:
// - images (compat)
@@ -272,7 +271,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Tag an image so that it becomes part of a repository.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -296,7 +296,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// $ref: '#/responses/ConflictError'
// 500:
// $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/images/{name:..*}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/images/{name}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
// swagger:operation POST /commit/ compat commitContainer
// ---
// tags:
@@ -325,7 +325,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: author of the image
// - in: query
// name: pause
- // type: bool
+ // type: boolean
// description: pause the container before committing it
// - in: query
// name: changes
@@ -334,12 +334,12 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '201':
+ // 201:
// description: no error
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '500':
- // $ref: '#/responses/InternalError'
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 500:
+ // $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/commit"), APIHandler(s.Context, generic.CommitContainer)).Methods(http.MethodPost)
// swagger:operation POST /build images buildImage
@@ -534,23 +534,28 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// - application/json
// responses:
// 200:
- // description: OK (As of version 1.xx)
- // schema:
- // type: object
- // required:
- // - stream
- // properties:
- // stream:
- // type: string
- // example: |
- // (build details...)
- // Successfully built 8ba084515c724cbf90d447a63600c0a6
+ // description: OK (As of version 1.xx)
+ // schema:
+ // type: object
+ // required:
+ // - stream
+ // properties:
+ // stream:
+ // type: string
+ // description: output from build process
+ // example: |
+ // (build details...)
+ // Successfully built 8ba084515c724cbf90d447a63600c0a6
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 500:
+ // $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/build"), APIHandler(s.Context, handlers.BuildImage)).Methods(http.MethodPost)
/*
libpod endpoints
*/
- // swagger:operation POST /libpod/images/{nameOrID}/exists libpod libpodImageExists
+ // swagger:operation POST /libpod/images/{name}/exists libpod libpodImageExists
// ---
// tags:
// - images
@@ -558,21 +563,22 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Check if image exists in local store
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '204':
+ // 204:
// description: image exists
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/{name:..*}/exists"), APIHandler(s.Context, libpod.ImageExists))
- r.Handle(VersionedPath("/libpod/images/{name:..*}/tree"), APIHandler(s.Context, libpod.ImageTree))
- // swagger:operation GET /libpod/images/{nameOrID}/history libpod libpodImageHistory
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name}/exists"), APIHandler(s.Context, libpod.ImageExists))
+ r.Handle(VersionedPath("/libpod/images/{name}/tree"), APIHandler(s.Context, libpod.ImageTree))
+ // swagger:operation GET /libpod/images/{name}/history libpod libpodImageHistory
// ---
// tags:
// - images
@@ -580,36 +586,56 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Return parent layers of an image.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
- // schema:
- // items:
- // $ref: "#/responses/HistoryResponse"
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
+ // 200:
+ // $ref: "#/responses/DocsHistory"
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name}/history"), APIHandler(s.Context, handlers.HistoryImage)).Methods(http.MethodGet)
// swagger:operation GET /libpod/images/json libpod libpodListImages
// ---
// tags:
// - images
// summary: List Images
// description: Returns a list of images on the server
+ // parameters:
+ // - name: "all"
+ // in: "query"
+ // description: "Show all images. Only images from a final layer (no children) are shown by default."
+ // type: "boolean"
+ // default: false
+ // - name: "filters"
+ // in: "query"
+ // description: |
+ // A JSON encoded value of the filters (a `map[string][]string`) to process on the images list. Available filters:
+ // - `before`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
+ // - `dangling=true`
+ // - `label=key` or `label="key=value"` of an image label
+ // - `reference`=(`<image-name>[:<tag>]`)
+ // - `since`=(`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`)
+ // type: "string"
+ // - name: "digests"
+ // in: "query"
+ // description: Not supported
+ // type: "boolean"
+ // default: false
// produces:
// - application/json
// responses:
- // '200':
- // $ref: "#/responses/DockerImageSummary"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 200:
+ // $ref: "#/responses/DockerImageSummary"
+ // 500:
+ // $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/json"), APIHandler(s.Context, libpod.GetImages)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/images/load libpod libpodLoadImage
+ // swagger:operation POST /libpod/images/load libpod libpodImportImage
// ---
// tags:
// - images
@@ -618,20 +644,30 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// parameters:
// - in: query
// name: quiet
- // type: bool
+ // type: boolean
// description: not supported
+ // - in: query
+ // name: change
+ // description: "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR. JSON encoded string"
+ // type: string
+ // - in: query
+ // name: message
+ // description: Set commit message for imported image
+ // type: string
// - in: body
+ // name: request
// description: tarball of container image
- // type: string
- // format: binary
+ // required: true
+ // schema:
+ // type: string
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: no error
- // '500':
+ // 500:
// $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/load"), APIHandler(s.Context, handlers.LoadImage)).Methods(http.MethodPost)
+ r.Handle(VersionedPath("/libpod/images/load"), APIHandler(s.Context, libpod.ImportImage)).Methods(http.MethodPost)
// swagger:operation POST /libpod/images/prune libpod libpodPruneImages
// ---
// tags:
@@ -649,18 +685,13 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// (or `0`), all unused images are pruned.
// - `until=<string>` Prune images created before this timestamp. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon machine’s time.
// - `label` (`label=<key>`, `label=<key>=<value>`, `label!=<key>`, or `label!=<key>=<value>`) Prune images with (or without, in case `label!=...` is used) the specified labels.
- // - in: query
- // name: all
- // type: bool
- // description: prune all images
// produces:
// - application/json
// responses:
- // '200':
- // items:
- // $ref: "#/responses/DocsImageDeleteResponse"
- // '500':
- // $ref: '#/responses/InternalError'
+ // 200:
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // 500:
+ // $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/prune"), APIHandler(s.Context, libpod.PruneImages)).Methods(http.MethodPost)
// swagger:operation GET /libpod/images/search libpod libpodSearchImages
// ---
@@ -675,7 +706,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: term to search
// - in: query
// name: limit
- // type: int
+ // type: integer
// description: maximum number of results
// - in: query
// name: filters
@@ -688,37 +719,42 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '200':
- // schema:
- // items:
- // $ref: "#/responses/DocsSearchResponse"
- // '500':
+ // 200:
+ // $ref: "#/responses/DocsSearchResponse"
+ // 500:
// $ref: '#/responses/InternalError'
r.Handle(VersionedPath("/libpod/images/search"), APIHandler(s.Context, handlers.SearchImages)).Methods(http.MethodGet)
- // swagger:operation DELETE /libpod/images/{nameOrID} libpod libpodRemoveImage
+ // swagger:operation DELETE /libpod/images/{name} libpod libpodRemoveImage
// ---
// tags:
// - images
// summary: Remove Image
// description: Delete an image from local store
// parameters:
+ // - in: path
+ // name: name
+ // type: string
+ // required: true
+ // description: name or ID of image to delete
// - in: query
// name: force
- // type: bool
+ // type: boolean
// description: remove the image even if used by containers or has other tags
// produces:
// - application/json
// responses:
- // '200':
- // $ref: "#/responses/DocsImageDeleteResponse"
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '409':
- // $ref: '#/responses/ConflictError'
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/{name:..*}"), APIHandler(s.Context, handlers.RemoveImage)).Methods(http.MethodDelete)
- // swagger:operation GET /libpod/images/{nameOrID}/get libpod libpoodExportImage
+ // 200:
+ // $ref: "#/responses/DocsImageDeleteResponse"
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 409:
+ // $ref: '#/responses/ConflictError'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/name"), APIHandler(s.Context, handlers.RemoveImage)).Methods(http.MethodDelete)
+ // swagger:operation GET /libpod/images/{name}/get libpod libpoodExportImage
// ---
// tags:
// - images
@@ -726,33 +762,32 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Export an image as a tarball
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
// name: format
// type: string
// description: format for exported image
- // default: oci-archive
// - in: query
// name: compress
- // type: bool
+ // type: boolean
// description: use compression on image
- // default: false
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: no error
// schema:
// type: string
// format: binary
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/{name:..*}/get"), APIHandler(s.Context, libpod.ExportImage)).Methods(http.MethodGet)
- // swagger:operation GET /libpod/images/{nameOrID}/json libpod libpodInspectImage
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name}/get"), APIHandler(s.Context, libpod.ExportImage)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/images/{name}/json libpod libpodInspectImage
// ---
// tags:
// - images
@@ -760,20 +795,21 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Obtain low-level information about an image
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// produces:
// - application/json
// responses:
- // '200':
- // $ref: "#/responses/DocsLibpodInspectImageResponse"
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/{name:..*}/json"), APIHandler(s.Context, libpod.GetImage))
- // swagger:operation POST /libpod/images/{nameOrID}/tag libpod libpodTagImage
+ // 200:
+ // $ref: "#/responses/DocsLibpodInspectImageResponse"
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name}/json"), APIHandler(s.Context, libpod.GetImage))
+ // swagger:operation POST /libpod/images/{name}/tag libpod libpodTagImage
// ---
// tags:
// - images
@@ -781,7 +817,8 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// description: Tag an image so that it becomes part of a repository.
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the container
// - in: query
@@ -795,17 +832,17 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// produces:
// - application/json
// responses:
- // '201':
+ // 201:
// description: no error
- // '400':
- // $ref: '#/responses/BadParamError'
- // '404':
- // $ref: '#/responses/NoSuchImage'
- // '409':
- // $ref: '#/responses/ConflictError'
- // '500':
- // $ref: '#/responses/InternalError'
- r.Handle(VersionedPath("/libpod/images/{name:..*}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
+ // 400:
+ // $ref: '#/responses/BadParamError'
+ // 404:
+ // $ref: '#/responses/NoSuchImage'
+ // 409:
+ // $ref: '#/responses/ConflictError'
+ // 500:
+ // $ref: '#/responses/InternalError'
+ r.Handle(VersionedPath("/libpod/images/{name}/tag"), APIHandler(s.Context, handlers.TagImage)).Methods(http.MethodPost)
return nil
}
diff --git a/pkg/api/server/register_info.go b/pkg/api/server/register_info.go
index a7fb18721..8c50fed7f 100644
--- a/pkg/api/server/register_info.go
+++ b/pkg/api/server/register_info.go
@@ -10,15 +10,17 @@ import (
func (s *APIServer) registerInfoHandlers(r *mux.Router) error {
// swagger:operation GET /info libpod libpodGetInfo
// ---
+ // tags:
+ // - system
// summary: Get info
// description: Returns information on the system and libpod configuration
// produces:
// - application/json
// responses:
- // '200':
+ // 200:
// description: to be determined
- // '500':
- // "$ref": "#/responses/InternalError"
+ // 500:
+ // $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/info"), APIHandler(s.Context, generic.GetInfo)).Methods(http.MethodGet)
return nil
}
diff --git a/pkg/api/server/register_pods.go b/pkg/api/server/register_pods.go
index 4018cfbe8..5c7b51871 100644
--- a/pkg/api/server/register_pods.go
+++ b/pkg/api/server/register_pods.go
@@ -16,81 +16,79 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// parameters:
// - in: query
// name: filters
- // descriptions: needs description and plumbing for filters
+ // type: string
+ // description: needs description and plumbing for filters
// responses:
- // '200':
- // properties:
- // items:
- // $ref: "#/responses/ListPodsResponse"
- // type: array
- // '400':
- // $ref: "#/responses/BadParamError"
- // '500':
- // $ref: "#/responses/InternalError"
+ // 200:
+ // $ref: "#/responses/ListPodsResponse"
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 500:
+ // $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/json"), APIHandler(s.Context, libpod.Pods)).Methods(http.MethodGet)
r.Handle(VersionedPath("/libpod/pods/create"), APIHandler(s.Context, libpod.PodCreate)).Methods(http.MethodPost)
// swagger:operation POST /libpod/pods/prune pods PrunePods
// ---
// summary: Prune unused pods
- // parameters:
- // - in: query
- // name: force
- // description: force delete
- // type: bool
- // default: false
// produces:
// - application/json
// responses:
- // '204':
- // description: no error
- // '400':
- // $ref: "#/responses/BadParamError"
- // '500':
- // $ref: "#/responses/InternalError"
+ // 200:
+ // description: tbd
+ // schema:
+ // type: object
+ // additionalProperties:
+ // type: string
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 500:
+ // $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/prune"), APIHandler(s.Context, libpod.PodPrune)).Methods(http.MethodPost)
- // swagger:operation DELETE /libpod/pods/{nameOrID} pods removePod
+ // swagger:operation DELETE /libpod/pods/{name} pods removePod
// ---
// summary: Remove pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// - in: query
// name: force
- // type: bool
- // description: force delete
+ // type: boolean
+ // description : force removal of a running pod by first stopping all containers, then removing all containers in the pod
// responses:
- // '204':
- // description: no error
- // '400':
- // $ref: "#/responses/BadParamError"
- // '404':
- // $ref: "#/responses/NoSuchPod"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}"), APIHandler(s.Context, libpod.PodDelete)).Methods(http.MethodDelete)
- // swagger:operation GET /libpod/pods/{nameOrID}/json pods inspectPod
+ // 204:
+ // description: no error
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchPod"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name}"), APIHandler(s.Context, libpod.PodDelete)).Methods(http.MethodDelete)
+ // swagger:operation GET /libpod/pods/{name}/json pods inspectPod
// ---
// summary: Inspect pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// responses:
- // '200':
- // $ref: "#/responses/InspectPodResponse"
- // '404':
+ // 200:
+ // $ref: "#/responses/InspectPodResponse"
+ // 404:
// $ref: "#/responses/NoSuchPod"
- // '500':
+ // 500:
// $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}/json"), APIHandler(s.Context, libpod.PodInspect)).Methods(http.MethodGet)
- // swagger:operation GET /libpod/pods/{nameOrID}/exists pods podExists
+ r.Handle(VersionedPath("/libpod/pods/{name}/json"), APIHandler(s.Context, libpod.PodInspect)).Methods(http.MethodGet)
+ // swagger:operation GET /libpod/pods/{name}/exists pods podExists
// ---
// summary: Pod exists
// description: Check if a pod exists by name or ID
@@ -98,25 +96,27 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// responses:
- // '204':
- // description: pod exists
- // '404':
- // $ref: "#/responses/NoSuchPod"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}/exists"), APIHandler(s.Context, libpod.PodExists)).Methods(http.MethodGet)
- // swagger:operation POST /libpod/pods/{nameOrID}/kill pods killPod
+ // 204:
+ // description: pod exists
+ // 404:
+ // $ref: "#/responses/NoSuchPod"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name}/exists"), APIHandler(s.Context, libpod.PodExists)).Methods(http.MethodGet)
+ // swagger:operation POST /libpod/pods/{name}/kill pods killPod
// ---
// summary: Kill a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// - in: query
@@ -125,116 +125,122 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// description: signal to be sent to pod
// default: SIGKILL
// responses:
- // '204':
- // description: no error
- // '400':
- // $ref: "#/responses/BadParamError"
- // '404':
- // $ref: "#/responses/NoSuchPod"
- // '409':
- // $ref: "#/responses/ConflictError"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}/kill"), APIHandler(s.Context, libpod.PodKill)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/pods/{nameOrID}/pause pods pausePod
+ // 204:
+ // description: no error
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchPod"
+ // 409:
+ // $ref: "#/responses/ConflictError"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name}/kill"), APIHandler(s.Context, libpod.PodKill)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{name}/pause pods pausePod
// ---
// summary: Pause a pod
+ // description: Pause a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// responses:
- // '204':
- // description: no error
- // '404':
- // $ref: "#/responses/NoSuchPod"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}/pause"), APIHandler(s.Context, libpod.PodPause)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/pods/{nameOrID}/restart pods restartPod
+ // 204:
+ // description: no error
+ // 404:
+ // $ref: "#/responses/NoSuchPod"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name}/pause"), APIHandler(s.Context, libpod.PodPause)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{name}/restart pods restartPod
// ---
// summary: Restart a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// responses:
- // '204':
- // description: no error
- // '404':
- // $ref: "#/responses/NoSuchPod"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}/restart"), APIHandler(s.Context, libpod.PodRestart)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/pods/{nameOrID}/start pods startPod
+ // 204:
+ // description: no error
+ // 404:
+ // $ref: "#/responses/NoSuchPod"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name}/restart"), APIHandler(s.Context, libpod.PodRestart)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{name}/start pods startPod
// ---
// summary: Start a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// responses:
- // '204':
- // description: no error
- // '304':
- // $ref: "#/responses/PodAlreadyStartedError"
- // '404':
- // $ref: "#/responses/NoSuchPod"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}/start"), APIHandler(s.Context, libpod.PodStart)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/pods/{nameOrID}/stop pods stopPod
+ // 204:
+ // description: no error
+ // 304:
+ // $ref: "#/responses/PodAlreadyStartedError"
+ // 404:
+ // $ref: "#/responses/NoSuchPod"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name}/start"), APIHandler(s.Context, libpod.PodStart)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{name}/stop pods stopPod
// ---
// summary: Stop a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// - in: query
// name: t
- // type: int
+ // type: integer
// description: timeout
// responses:
- // '204':
- // description: no error
- // '304':
- // $ref: "#/responses/PodAlreadyStoppedError"
- // '400':
- // $ref: "#/responses/BadParamError"
- // '404':
- // $ref: "#/responses/NoSuchPod"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}/stop"), APIHandler(s.Context, libpod.PodStop)).Methods(http.MethodPost)
- // swagger:operation POST /libpod/pods/{nameOrID}/unpause pods unpausePod
+ // 204:
+ // description: no error
+ // 304:
+ // $ref: "#/responses/PodAlreadyStoppedError"
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchPod"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name}/stop"), APIHandler(s.Context, libpod.PodStop)).Methods(http.MethodPost)
+ // swagger:operation POST /libpod/pods/{name}/unpause pods unpausePod
// ---
// summary: Unpause a pod
// produces:
// - application/json
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the pod
// responses:
- // '204':
- // description: no error
- // '404':
- // $ref: "#/responses/NoSuchPod"
- // '500':
- // $ref: "#/responses/InternalError"
- r.Handle(VersionedPath("/libpod/pods/{name:..*}/unpause"), APIHandler(s.Context, libpod.PodUnpause)).Methods(http.MethodPost)
+ // 204:
+ // description: no error
+ // 404:
+ // $ref: "#/responses/NoSuchPod"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle(VersionedPath("/libpod/pods/{name}/unpause"), APIHandler(s.Context, libpod.PodUnpause)).Methods(http.MethodPost)
return nil
}
diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go
index 34138cfbf..d34c71238 100644
--- a/pkg/api/server/register_volumes.go
+++ b/pkg/api/server/register_volumes.go
@@ -31,12 +31,13 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error {
// '500':
// "$ref": "#/responses/InternalError"
r.Handle("/libpod/volumes/prune", APIHandler(s.Context, libpod.PruneVolumes)).Methods(http.MethodPost)
- // swagger:operation GET /volumes/{nameOrID}/json volumes inspectVolume
+ // swagger:operation GET /volumes/{name}/json volumes inspectVolume
// ---
// summary: Inspect volume
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the volume
// produces:
@@ -48,30 +49,31 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error {
// "$ref": "#/responses/NoSuchVolume"
// '500':
// "$ref": "#/responses/InternalError"
- r.Handle("/libpod/volumes/{name:..*}/json", APIHandler(s.Context, libpod.InspectVolume)).Methods(http.MethodGet)
- // swagger:operation DELETE /volumes/{nameOrID} volumes removeVolume
+ r.Handle("/libpod/volumes/{name}/json", APIHandler(s.Context, libpod.InspectVolume)).Methods(http.MethodGet)
+ // swagger:operation DELETE /volumes/{name} volumes removeVolume
// ---
// summary: Remove volume
// parameters:
// - in: path
- // name: nameOrID
+ // name: name
+ // type: string
// required: true
// description: the name or ID of the volume
// - in: query
// name: force
- // type: bool
+ // type: boolean
// description: force removal
// produces:
// - application/json
// responses:
- // '204':
- // description: no error
- // '400':
- // "$ref": "#/responses/BadParamError"
- // '404':
- // "$ref": "#/responses/NoSuchVolume"
- // '500':
- // "$ref": "#/responses/InternalError"
- r.Handle("/libpod/volumes/{name:..*}", APIHandler(s.Context, libpod.RemoveVolume)).Methods(http.MethodDelete)
+ // 204:
+ // description: no error
+ // 400:
+ // $ref: "#/responses/BadParamError"
+ // 404:
+ // $ref: "#/responses/NoSuchVolume"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.Handle("/libpod/volumes/{name}", APIHandler(s.Context, libpod.RemoveVolume)).Methods(http.MethodDelete)
return nil
}
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 69a44f21a..8c940763e 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -1,44 +1,3 @@
-// Package api Provides a container compatible interface.
-//
-// This documentation describes the HTTP Libpod interface. It is to be consider
-// only as experimental as this point. The endpoints, parameters, inputs, and
-// return values can all change.
-//
-// Schemes: http, https
-// Host: podman.io
-// BasePath: /
-// Version: 0.0.1
-// License: Apache-2.0 https://opensource.org/licenses/Apache-2.0
-// Contact: Podman <podman@lists.podman.io> https://podman.io/community/
-// InfoExtensions:
-// x-logo:
-// - url: https://raw.githubusercontent.com/containers/libpod/master/logo/podman-logo.png
-// - altText: "Podman logo"
-//
-// Consumes:
-// - application/json
-// - application/x-tar
-//
-// Produces:
-// - application/json
-// - text/plain
-// - text/html
-//
-// tags:
-// - name: containers
-// description: Actions related to containers
-// - name: images
-// description: Actions related to images
-// - name: pods
-// description: Actions related to pods
-// - name: volumes
-// description: Actions related to volumes
-// - name: containers (compat)
-// description: Actions related to containers for the compatibility endpoints
-// - name: images (compat)
-// description: Actions related to images for the compatibility endpoints
-//
-// swagger:meta
package server
import (
@@ -52,6 +11,7 @@ import (
"time"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/api/handlers"
"github.com/coreos/go-systemd/activation"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
@@ -112,7 +72,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
ReadTimeout: 20 * time.Second,
WriteTimeout: 2 * time.Minute,
},
- Decoder: schema.NewDecoder(),
+ Decoder: handlers.NewAPIDecoder(),
Context: nil,
Runtime: runtime,
Listener: *listener,
@@ -126,6 +86,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
})
ctx, cancelFn := context.WithCancel(context.Background())
+ server.CancelFunc = cancelFn
// TODO: Use ConnContext when ported to go 1.13
ctx = context.WithValue(ctx, "decoder", server.Decoder)
@@ -133,9 +94,6 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
ctx = context.WithValue(ctx, "shutdownFunc", server.Shutdown)
server.Context = ctx
- server.CancelFunc = cancelFn
- server.Decoder.IgnoreUnknownKeys(true)
-
router.NotFoundHandler = http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
// We can track user errors...
diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go
index dbf499ce7..5098390bc 100644
--- a/pkg/api/server/swagger.go
+++ b/pkg/api/server/swagger.go
@@ -41,7 +41,7 @@ type swagErrNoSuchPod struct {
}
}
-// Internal error
+// Internal server error
// swagger:response InternalError
type swagInternalError struct {
// in:body
@@ -50,16 +50,7 @@ type swagInternalError struct {
}
}
-// Generic error
-// swagger:response GenericError
-type swagGenericError struct {
- // in:body
- Body struct {
- utils.ErrorModel
- }
-}
-
-// Conflict error
+// Conflict error in operation
// swagger:response ConflictError
type swagConflictError struct {
// in:body
@@ -68,7 +59,7 @@ type swagConflictError struct {
}
}
-// Bad parameter
+// Bad parameter in request
// swagger:response BadParamError
type swagBadParamError struct {
// in:body
@@ -130,7 +121,12 @@ type swagListContainers struct {
}
}
-// To be determined
-// swagger:response tbd
-type swagTBD struct {
+// Success
+// swagger:response
+type ok struct {
+ // in:body
+ Body struct {
+ // example: OK
+ ok string
+ }
}
diff --git a/pkg/bindings/bindings.go b/pkg/bindings/bindings.go
new file mode 100644
index 000000000..e83c4a5e1
--- /dev/null
+++ b/pkg/bindings/bindings.go
@@ -0,0 +1,9 @@
+// Package bindings provides golang-based access
+// to the Podman REST API. Users can then interact with API endpoints
+// to manage containers, images, pods, etc.
+//
+// This package exposes a series of methods that allow users to firstly
+// create their connection with the API endpoints. Once the connection
+// is established, users can then manage the Podman container runtime.
+
+package bindings
diff --git a/vendor/github.com/fatih/camelcase/LICENSE.md b/pkg/util/camelcase/LICENSE.md
index aa4a536ca..aa4a536ca 100644
--- a/vendor/github.com/fatih/camelcase/LICENSE.md
+++ b/pkg/util/camelcase/LICENSE.md
diff --git a/vendor/github.com/fatih/camelcase/README.md b/pkg/util/camelcase/README.md
index 105a6ae33..105a6ae33 100644
--- a/vendor/github.com/fatih/camelcase/README.md
+++ b/pkg/util/camelcase/README.md
diff --git a/vendor/github.com/fatih/camelcase/camelcase.go b/pkg/util/camelcase/camelcase.go
index 02160c9a4..0a82d1005 100644
--- a/vendor/github.com/fatih/camelcase/camelcase.go
+++ b/pkg/util/camelcase/camelcase.go
@@ -55,7 +55,7 @@ func Split(src string) (entries []string) {
class := 0
// split into fields based on class of unicode character
for _, r := range src {
- switch true {
+ switch {
case unicode.IsLower(r):
class = 1
case unicode.IsUpper(r):
@@ -86,5 +86,6 @@ func Split(src string) (entries []string) {
entries = append(entries, string(s))
}
}
- return
+
+ return entries
}
diff --git a/test/e2e/config.go b/test/e2e/config.go
index 12d0e545e..96cc157be 100644
--- a/test/e2e/config.go
+++ b/test/e2e/config.go
@@ -19,8 +19,8 @@ var (
// The intention behind blocking all syscalls is to prevent
// regressions in the future. The required syscalls can vary
// depending on which runtime we're using.
- alpineSeccomp = "docker.io/libpod/alpine-with-seccomp:latest"
+ alpineSeccomp = "docker.io/libpod/alpine-with-seccomp:label"
// This image has a bogus/invalid seccomp profile which should
// yield a json error when being read.
- alpineBogusSeccomp = "docker.io/libpod/alpine-with-bogus-seccomp:latest"
+ alpineBogusSeccomp = "docker.io/libpod/alpine-with-bogus-seccomp:label"
)
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index d32434904..928b5d437 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.15.5
+1.15.8-dev
diff --git a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
index 1f719fa85..5be1639d0 100644
--- a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
+++ b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
@@ -627,7 +627,12 @@ func (d *Driver) Remove(id string) error {
d.updateQuotaStatus()
if err := subvolDelete(d.subvolumesDir(), id, d.quotaEnabled); err != nil {
- return err
+ if d.quotaEnabled {
+ return err
+ }
+ // If quota is not enabled, fallback to rmdir syscall to delete subvolumes.
+ // This would allow unprivileged user to delete their owned subvolumes
+ // in kernel >= 4.18 without user_subvol_rm_alowed mount option.
}
if err := system.EnsureRemoveAll(dir); err != nil {
return err
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index 16549e88b..25d885be9 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -142,8 +142,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
if opts.mountProgram == "" {
switch fsMagic {
case graphdriver.FsMagicAufs, graphdriver.FsMagicZfs, graphdriver.FsMagicOverlay, graphdriver.FsMagicEcryptfs:
- logrus.Errorf("'overlay' is not supported over %s", backingFs)
- return nil, errors.Wrapf(graphdriver.ErrIncompatibleFS, "'overlay' is not supported over %s", backingFs)
+ return nil, errors.Wrapf(graphdriver.ErrIncompatibleFS, "'overlay' is not supported over %s, a mount_program is required", backingFs)
}
}
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index 378b427de..b7a05a65b 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -7,15 +7,15 @@ require (
github.com/Microsoft/hcsshim v0.8.7
github.com/docker/docker v0.0.0-20171019062838-86f080cff091 // indirect
github.com/docker/go-units v0.4.0
- github.com/klauspost/compress v1.9.4
+ github.com/klauspost/compress v1.9.7
github.com/klauspost/cpuid v1.2.1 // indirect
github.com/klauspost/pgzip v1.2.1
- github.com/mattn/go-shellwords v1.0.6
+ github.com/mattn/go-shellwords v1.0.7
github.com/mistifyio/go-zfs v2.1.1+incompatible
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/runc v1.0.0-rc9
github.com/opencontainers/selinux v1.3.0
- github.com/pkg/errors v0.8.1
+ github.com/pkg/errors v0.9.1
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7
github.com/sirupsen/logrus v1.4.2
github.com/spf13/pflag v1.0.3 // indirect
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index f31828d2a..ffda0c42f 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -73,6 +73,10 @@ github.com/klauspost/compress v1.9.3 h1:hkFELABwacUEgBfiguNeQydKv3M9pawBq8o24Ypw
github.com/klauspost/compress v1.9.3/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.9.4 h1:xhvAeUPQ2drNUhKtrGdTGNvV9nNafHMUkRyLkzxJoB4=
github.com/klauspost/compress v1.9.4/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
+github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.9.7 h1:hYW1gP94JUmAhBtJ+LNz5My+gBobDxPR1iVuKug26aA=
+github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
@@ -83,6 +87,8 @@ github.com/mattn/go-shellwords v1.0.5 h1:JhhFTIOslh5ZsPrpa3Wdg8bF0WI3b44EMblmU9w
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+github.com/mattn/go-shellwords v1.0.7 h1:KqhVjVZomx2puPACkj9vrGFqnp42Htvo9SEAWePHKOs=
+github.com/mattn/go-shellwords v1.0.7/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mistifyio/go-zfs v2.1.1+incompatible h1:gAMO1HM9xBRONLHHYnu5iFsOJUiJdNZo6oqSENd4eW8=
github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 h1:7InQ7/zrOh6SlFjaXFubv0xX0HsuC9qJsdqm7bNQpYM=
@@ -108,6 +114,10 @@ github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOl
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k=
+github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/ffjson v0.0.0-20181028064349-e517b90714f7 h1:gGBSHPOU7g8YjTbhwn+lvFm2VDEhhA+PwDIlstkgSxE=
diff --git a/vendor/github.com/containers/storage/pkg/config/config.go b/vendor/github.com/containers/storage/pkg/config/config.go
index f3f855c32..9e1131823 100644
--- a/vendor/github.com/containers/storage/pkg/config/config.go
+++ b/vendor/github.com/containers/storage/pkg/config/config.go
@@ -236,7 +236,7 @@ func GetGraphDriverOptions(driverName string, options OptionsConfig) []string {
doptions = append(doptions, fmt.Sprintf("dm.xfs_nospace_max_retries=%s", options.Thinpool.XfsNoSpaceMaxRetries))
}
- case "overlay":
+ case "overlay", "overlay2":
if options.Overlay.IgnoreChownErrors != "" {
doptions = append(doptions, fmt.Sprintf("%s.ignore_chown_errors=%s", driverName, options.Overlay.IgnoreChownErrors))
} else if options.IgnoreChownErrors != "" {
diff --git a/vendor/github.com/coreos/go-iptables/iptables/iptables.go b/vendor/github.com/coreos/go-iptables/iptables/iptables.go
index 2ed875bb5..1074275b0 100644
--- a/vendor/github.com/coreos/go-iptables/iptables/iptables.go
+++ b/vendor/github.com/coreos/go-iptables/iptables/iptables.go
@@ -48,9 +48,13 @@ func (e *Error) Error() string {
// IsNotExist returns true if the error is due to the chain or rule not existing
func (e *Error) IsNotExist() bool {
- return e.ExitStatus() == 1 &&
- (e.msg == fmt.Sprintf("%s: Bad rule (does a matching rule exist in that chain?).\n", getIptablesCommand(e.proto)) ||
- e.msg == fmt.Sprintf("%s: No chain/target/match by that name.\n", getIptablesCommand(e.proto)))
+ if e.ExitStatus() != 1 {
+ return false
+ }
+ cmdIptables := getIptablesCommand(e.proto)
+ msgNoRuleExist := fmt.Sprintf("%s: Bad rule (does a matching rule exist in that chain?).\n", cmdIptables)
+ msgNoChainExist := fmt.Sprintf("%s: No chain/target/match by that name.\n", cmdIptables)
+ return strings.Contains(e.msg, msgNoRuleExist) || strings.Contains(e.msg, msgNoChainExist)
}
// Protocol to differentiate between IPv4 and IPv6
@@ -101,7 +105,13 @@ func NewWithProtocol(proto Protocol) (*IPTables, error) {
return nil, err
}
vstring, err := getIptablesVersionString(path)
+ if err != nil {
+ return nil, fmt.Errorf("could not get iptables version: %v", err)
+ }
v1, v2, v3, mode, err := extractIptablesVersion(vstring)
+ if err != nil {
+ return nil, fmt.Errorf("failed to extract iptables version from [%s]: %v", vstring, err)
+ }
checkPresent, waitPresent, randomFullyPresent := getIptablesCommandSupport(v1, v2, v3)
@@ -348,18 +358,6 @@ func (ipt *IPTables) executeList(args []string) ([]string, error) {
rules = rules[:len(rules)-1]
}
- // nftables mode doesn't return an error code when listing a non-existent
- // chain. Patch that up.
- if len(rules) == 0 && ipt.mode == "nf_tables" {
- v := 1
- return nil, &Error{
- cmd: exec.Cmd{Args: args},
- msg: fmt.Sprintf("%s: No chain/target/match by that name.\n", getIptablesCommand(ipt.proto)),
- proto: ipt.proto,
- exitStatus: &v,
- }
- }
-
for i, rule := range rules {
rules[i] = filterRuleOutput(rule)
}
@@ -437,6 +435,7 @@ func (ipt *IPTables) runWithOutput(args []string, stdout io.Writer) error {
}
ul, err := fmu.tryLock()
if err != nil {
+ syscall.Close(fmu.fd)
return err
}
defer ul.Unlock()
diff --git a/vendor/github.com/fatih/camelcase/.travis.yml b/vendor/github.com/fatih/camelcase/.travis.yml
deleted file mode 100644
index 3489e3871..000000000
--- a/vendor/github.com/fatih/camelcase/.travis.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-language: go
-go: 1.x
-
diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go
index e27e8d191..80320cd64 100644
--- a/vendor/github.com/json-iterator/go/reflect_extension.go
+++ b/vendor/github.com/json-iterator/go/reflect_extension.go
@@ -341,7 +341,7 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor {
if ctx.onlyTaggedField && !hastag && !field.Anonymous() {
continue
}
- if tag == "-" {
+ if tag == "-" || field.Name() == "_" {
continue
}
tagParts := strings.Split(tag, ",")
diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go
index 08e9a3912..9e2b623fe 100644
--- a/vendor/github.com/json-iterator/go/reflect_map.go
+++ b/vendor/github.com/json-iterator/go/reflect_map.go
@@ -290,16 +290,17 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteObjectStart()
mapIter := encoder.mapType.UnsafeIterate(ptr)
subStream := stream.cfg.BorrowStream(nil)
+ subStream.Attachment = stream.Attachment
subIter := stream.cfg.BorrowIterator(nil)
keyValues := encodedKeyValues{}
for mapIter.HasNext() {
- subStream.buf = make([]byte, 0, 64)
key, elem := mapIter.UnsafeNext()
+ subStreamIndex := subStream.Buffered()
encoder.keyEncoder.Encode(key, subStream)
if subStream.Error != nil && subStream.Error != io.EOF && stream.Error == nil {
stream.Error = subStream.Error
}
- encodedKey := subStream.Buffer()
+ encodedKey := subStream.Buffer()[subStreamIndex:]
subIter.ResetBytes(encodedKey)
decodedKey := subIter.ReadString()
if stream.indention > 0 {
@@ -310,7 +311,7 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
encoder.elemEncoder.Encode(elem, subStream)
keyValues = append(keyValues, encodedKV{
key: decodedKey,
- keyValue: subStream.Buffer(),
+ keyValue: subStream.Buffer()[subStreamIndex:],
})
}
sort.Sort(keyValues)
@@ -320,6 +321,9 @@ func (encoder *sortKeysMapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
}
stream.Write(keyValue.keyValue)
}
+ if subStream.Error != nil && stream.Error == nil {
+ stream.Error = subStream.Error
+ }
stream.WriteObjectEnd()
stream.cfg.ReturnStream(subStream)
stream.cfg.ReturnIterator(subIter)
diff --git a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go
index d0759cf64..152e3ef5a 100644
--- a/vendor/github.com/json-iterator/go/reflect_struct_encoder.go
+++ b/vendor/github.com/json-iterator/go/reflect_struct_encoder.go
@@ -200,6 +200,7 @@ type stringModeStringEncoder struct {
func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
tempStream := encoder.cfg.BorrowStream(nil)
+ tempStream.Attachment = stream.Attachment
defer encoder.cfg.ReturnStream(tempStream)
encoder.elemEncoder.Encode(ptr, tempStream)
stream.WriteString(string(tempStream.Buffer()))
diff --git a/vendor/github.com/klauspost/compress/huff0/bitwriter.go b/vendor/github.com/klauspost/compress/huff0/bitwriter.go
index ec0c3fc53..bda4021ef 100644
--- a/vendor/github.com/klauspost/compress/huff0/bitwriter.go
+++ b/vendor/github.com/klauspost/compress/huff0/bitwriter.go
@@ -38,7 +38,7 @@ func (b *bitWriter) addBits16Clean(value uint16, bits uint8) {
b.nBits += bits
}
-// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated.
+// encSymbol will add up to 16 bits. value may not contain more set bits than indicated.
// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
enc := ct[symbol]
@@ -46,6 +46,17 @@ func (b *bitWriter) encSymbol(ct cTable, symbol byte) {
b.nBits += enc.nBits
}
+// encTwoSymbols will add up to 32 bits. value may not contain more set bits than indicated.
+// It will not check if there is space for them, so the caller must ensure that it has flushed recently.
+func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) {
+ encA := ct[av]
+ encB := ct[bv]
+ sh := b.nBits & 63
+ combined := uint64(encA.val) | (uint64(encB.val) << (encA.nBits & 63))
+ b.bitContainer |= combined << sh
+ b.nBits += encA.nBits + encB.nBits
+}
+
// addBits16ZeroNC will add up to 16 bits.
// It will not check if there is space for them,
// so the caller must ensure that it has flushed recently.
diff --git a/vendor/github.com/klauspost/compress/huff0/compress.go b/vendor/github.com/klauspost/compress/huff0/compress.go
index 51e00aaeb..0843cb014 100644
--- a/vendor/github.com/klauspost/compress/huff0/compress.go
+++ b/vendor/github.com/klauspost/compress/huff0/compress.go
@@ -80,9 +80,12 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
if s.Reuse == ReusePolicyPrefer && canReuse {
keepTable := s.cTable
+ keepTL := s.actualTableLog
s.cTable = s.prevTable
+ s.actualTableLog = s.prevTableLog
s.Out, err = compressor(in)
s.cTable = keepTable
+ s.actualTableLog = keepTL
if err == nil && len(s.Out) < wantSize {
s.OutData = s.Out
return s.Out, true, nil
@@ -92,7 +95,6 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
}
// Calculate new table.
- s.optimalTableLog()
err = s.buildCTable()
if err != nil {
return nil, false, err
@@ -109,9 +111,15 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
if oldSize <= hSize+newSize || hSize+12 >= wantSize {
// Retain cTable even if we re-use.
keepTable := s.cTable
+ keepTL := s.actualTableLog
+
s.cTable = s.prevTable
+ s.actualTableLog = s.prevTableLog
s.Out, err = compressor(in)
+
+ // Restore ctable.
s.cTable = keepTable
+ s.actualTableLog = keepTL
if err != nil {
return nil, false, err
}
@@ -142,7 +150,7 @@ func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)
return nil, false, ErrIncompressible
}
// Move current table into previous.
- s.prevTable, s.cTable = s.cTable, s.prevTable[:0]
+ s.prevTable, s.prevTableLog, s.cTable = s.cTable, s.actualTableLog, s.prevTable[:0]
s.OutData = s.Out[len(s.OutTable):]
return s.Out, false, nil
}
@@ -163,28 +171,23 @@ func (s *Scratch) compress1xDo(dst, src []byte) ([]byte, error) {
for i := len(src) & 3; i > 0; i-- {
bw.encSymbol(cTable, src[n+i-1])
}
+ n -= 4
if s.actualTableLog <= 8 {
- n -= 4
for ; n >= 0; n -= 4 {
tmp := src[n : n+4]
// tmp should be len 4
bw.flush32()
- bw.encSymbol(cTable, tmp[3])
- bw.encSymbol(cTable, tmp[2])
- bw.encSymbol(cTable, tmp[1])
- bw.encSymbol(cTable, tmp[0])
+ bw.encTwoSymbols(cTable, tmp[3], tmp[2])
+ bw.encTwoSymbols(cTable, tmp[1], tmp[0])
}
} else {
- n -= 4
for ; n >= 0; n -= 4 {
tmp := src[n : n+4]
// tmp should be len 4
bw.flush32()
- bw.encSymbol(cTable, tmp[3])
- bw.encSymbol(cTable, tmp[2])
+ bw.encTwoSymbols(cTable, tmp[3], tmp[2])
bw.flush32()
- bw.encSymbol(cTable, tmp[1])
- bw.encSymbol(cTable, tmp[0])
+ bw.encTwoSymbols(cTable, tmp[1], tmp[0])
}
}
err := bw.close()
@@ -322,9 +325,26 @@ func (s *Scratch) canUseTable(c cTable) bool {
return true
}
+func (s *Scratch) validateTable(c cTable) bool {
+ if len(c) < int(s.symbolLen) {
+ return false
+ }
+ for i, v := range s.count[:s.symbolLen] {
+ if v != 0 {
+ if c[i].nBits == 0 {
+ return false
+ }
+ if c[i].nBits > s.actualTableLog {
+ return false
+ }
+ }
+ }
+ return true
+}
+
// minTableLog provides the minimum logSize to safely represent a distribution.
func (s *Scratch) minTableLog() uint8 {
- minBitsSrc := highBit32(uint32(s.br.remain()-1)) + 1
+ minBitsSrc := highBit32(uint32(s.br.remain())) + 1
minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2
if minBitsSrc < minBitsSymbols {
return uint8(minBitsSrc)
@@ -336,7 +356,7 @@ func (s *Scratch) minTableLog() uint8 {
func (s *Scratch) optimalTableLog() {
tableLog := s.TableLog
minBits := s.minTableLog()
- maxBitsSrc := uint8(highBit32(uint32(s.br.remain()-1))) - 2
+ maxBitsSrc := uint8(highBit32(uint32(s.br.remain()-1))) - 1
if maxBitsSrc < tableLog {
// Accuracy can be reduced
tableLog = maxBitsSrc
@@ -363,6 +383,7 @@ type cTableEntry struct {
const huffNodesMask = huffNodesLen - 1
func (s *Scratch) buildCTable() error {
+ s.optimalTableLog()
s.huffSort()
if cap(s.cTable) < maxSymbolValue+1 {
s.cTable = make([]cTableEntry, s.symbolLen, maxSymbolValue+1)
@@ -439,7 +460,7 @@ func (s *Scratch) buildCTable() error {
return fmt.Errorf("internal error: maxNbBits (%d) > tableLogMax (%d)", maxNbBits, tableLogMax)
}
var nbPerRank [tableLogMax + 1]uint16
- var valPerRank [tableLogMax + 1]uint16
+ var valPerRank [16]uint16
for _, v := range huffNode[:nonNullRank+1] {
nbPerRank[v.nbBits]++
}
@@ -455,16 +476,17 @@ func (s *Scratch) buildCTable() error {
}
// push nbBits per symbol, symbol order
- // TODO: changed `s.symbolLen` -> `nonNullRank+1` (micro-opt)
for _, v := range huffNode[:nonNullRank+1] {
s.cTable[v.symbol].nBits = v.nbBits
}
// assign value within rank, symbol order
- for n, val := range s.cTable[:s.symbolLen] {
- v := valPerRank[val.nBits]
- s.cTable[n].val = v
- valPerRank[val.nBits] = v + 1
+ t := s.cTable[:s.symbolLen]
+ for n, val := range t {
+ nbits := val.nBits & 15
+ v := valPerRank[nbits]
+ t[n].val = v
+ valPerRank[nbits] = v + 1
}
return nil
@@ -488,10 +510,12 @@ func (s *Scratch) huffSort() {
r := highBit32(v+1) & 31
rank[r].base++
}
- for n := 30; n > 0; n-- {
+ // maxBitLength is log2(BlockSizeMax) + 1
+ const maxBitLength = 18 + 1
+ for n := maxBitLength; n > 0; n-- {
rank[n-1].base += rank[n].base
}
- for n := range rank[:] {
+ for n := range rank[:maxBitLength] {
rank[n].current = rank[n].base
}
for n, c := range s.count[:s.symbolLen] {
@@ -510,7 +534,7 @@ func (s *Scratch) huffSort() {
}
func (s *Scratch) setMaxHeight(lastNonNull int) uint8 {
- maxNbBits := s.TableLog
+ maxNbBits := s.actualTableLog
huffNode := s.nodes[1 : huffNodesLen+1]
//huffNode = huffNode[: huffNodesLen]
diff --git a/vendor/github.com/klauspost/compress/huff0/huff0.go b/vendor/github.com/klauspost/compress/huff0/huff0.go
index 6bc23bbf0..53249df05 100644
--- a/vendor/github.com/klauspost/compress/huff0/huff0.go
+++ b/vendor/github.com/klauspost/compress/huff0/huff0.go
@@ -83,7 +83,7 @@ type Scratch struct {
MaxSymbolValue uint8
// TableLog will attempt to override the tablelog for the next block.
- // Must be <= 11.
+ // Must be <= 11 and >= 5.
TableLog uint8
// Reuse will specify the reuse policy
@@ -105,6 +105,7 @@ type Scratch struct {
maxCount int // count of the most probable symbol
clearCount bool // clear count
actualTableLog uint8 // Selected tablelog.
+ prevTableLog uint8 // Tablelog for previous table
prevTable cTable // Table used for previous compression.
cTable cTable // compression table
dt dTable // decompression table
@@ -127,8 +128,8 @@ func (s *Scratch) prepare(in []byte) (*Scratch, error) {
if s.TableLog == 0 {
s.TableLog = tableLogDefault
}
- if s.TableLog > tableLogMax {
- return nil, fmt.Errorf("tableLog (%d) > maxTableLog (%d)", s.TableLog, tableLogMax)
+ if s.TableLog > tableLogMax || s.TableLog < minTablelog {
+ return nil, fmt.Errorf(" invalid tableLog %d (%d -> %d)", s.TableLog, minTablelog, tableLogMax)
}
if s.MaxDecodedSize <= 0 || s.MaxDecodedSize > BlockSizeMax {
s.MaxDecodedSize = BlockSizeMax
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
index 52dc0aee3..bc977a302 100644
--- a/vendor/github.com/klauspost/compress/zstd/README.md
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -36,7 +36,7 @@ so as always, testing is recommended.
For now, a high speed (fastest) and medium-fast (default) compressor has been implemented.
The "Fastest" compression ratio is roughly equivalent to zstd level 1.
-The "Default" compression ration is roughly equivalent to zstd level 3 (default).
+The "Default" compression ratio is roughly equivalent to zstd level 3 (default).
In terms of speed, it is typically 2x as fast as the stdlib deflate/gzip in its fastest mode.
The compression ratio compared to stdlib is around level 3, but usually 3x as fast.
@@ -390,4 +390,4 @@ For sending files for reproducing errors use a service like [goobox](https://goo
For general feedback and experience reports, feel free to open an issue or write me on [Twitter](https://twitter.com/sh0dan).
-This package includes the excellent [`github.com/cespare/xxhash`](https://github.com/cespare/xxhash) package Copyright (c) 2016 Caleb Spare. \ No newline at end of file
+This package includes the excellent [`github.com/cespare/xxhash`](https://github.com/cespare/xxhash) package Copyright (c) 2016 Caleb Spare.
diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go
index 99eccda11..507757d52 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockenc.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go
@@ -299,6 +299,20 @@ func (b *blockEnc) encodeRaw(a []byte) {
}
}
+// encodeRaw can be used to set the output to a raw representation of supplied bytes.
+func (b *blockEnc) encodeRawTo(dst, src []byte) []byte {
+ var bh blockHeader
+ bh.setLast(b.last)
+ bh.setSize(uint32(len(src)))
+ bh.setType(blockTypeRaw)
+ dst = bh.appendTo(dst)
+ dst = append(dst, src...)
+ if debug {
+ println("Adding RAW block, length", len(src))
+ }
+ return dst
+}
+
// encodeLits can be used if the block is only litLen.
func (b *blockEnc) encodeLits(raw bool) error {
var bh blockHeader
@@ -324,18 +338,10 @@ func (b *blockEnc) encodeLits(raw bool) error {
if len(b.literals) >= 1024 {
// Use 4 Streams.
out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc)
- if len(out) > len(b.literals)-len(b.literals)>>4 {
- // Bail out of compression is too little.
- err = huff0.ErrIncompressible
- }
} else if len(b.literals) > 32 {
// Use 1 stream
single = true
out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc)
- if len(out) > len(b.literals)-len(b.literals)>>4 {
- // Bail out of compression is too little.
- err = huff0.ErrIncompressible
- }
} else {
err = huff0.ErrIncompressible
}
@@ -437,7 +443,7 @@ func fuzzFseEncoder(data []byte) int {
return 1
}
-// encode will encode the block and put the output in b.output.
+// encode will encode the block and append the output in b.output.
func (b *blockEnc) encode(raw bool) error {
if len(b.sequences) == 0 {
return b.encodeLits(raw)
@@ -451,6 +457,8 @@ func (b *blockEnc) encode(raw bool) error {
var lh literalsHeader
bh.setLast(b.last)
bh.setType(blockTypeCompressed)
+ // Store offset of the block header. Needed when we know the size.
+ bhOffset := len(b.output)
b.output = bh.appendTo(b.output)
var (
@@ -468,6 +476,7 @@ func (b *blockEnc) encode(raw bool) error {
} else {
err = huff0.ErrIncompressible
}
+
switch err {
case huff0.ErrIncompressible:
lh.setType(literalsBlockRaw)
@@ -735,18 +744,18 @@ func (b *blockEnc) encode(raw bool) error {
}
b.output = wr.out
- if len(b.output)-3 >= b.size {
+ if len(b.output)-3-bhOffset >= b.size {
// Maybe even add a bigger margin.
b.litEnc.Reuse = huff0.ReusePolicyNone
return errIncompressible
}
// Size is output minus block header.
- bh.setSize(uint32(len(b.output)) - 3)
+ bh.setSize(uint32(len(b.output)-bhOffset) - 3)
if debug {
println("Rewriting block header", bh)
}
- _ = bh.appendTo(b.output[:0])
+ _ = bh.appendTo(b.output[bhOffset:bhOffset])
b.coders.setPrev(llEnc, mlEnc, ofEnc)
return nil
}
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
index 1de94eef0..35a3cda91 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -388,6 +388,35 @@ func (d *Decoder) Close() {
d.current.err = ErrDecoderClosed
}
+// IOReadCloser returns the decoder as an io.ReadCloser for convenience.
+// Any changes to the decoder will be reflected, so the returned ReadCloser
+// can be reused along with the decoder.
+// io.WriterTo is also supported by the returned ReadCloser.
+func (d *Decoder) IOReadCloser() io.ReadCloser {
+ return closeWrapper{d: d}
+}
+
+// closeWrapper wraps a function call as a closer.
+type closeWrapper struct {
+ d *Decoder
+}
+
+// WriteTo forwards WriteTo calls to the decoder.
+func (c closeWrapper) WriteTo(w io.Writer) (n int64, err error) {
+ return c.d.WriteTo(w)
+}
+
+// Read forwards read calls to the decoder.
+func (c closeWrapper) Read(p []byte) (n int, err error) {
+ return c.d.Read(p)
+}
+
+// Close closes the decoder.
+func (c closeWrapper) Close() error {
+ c.d.Close()
+ return nil
+}
+
type decodeOutput struct {
d *blockDec
b []byte
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
index 2f41bcd0d..ee3b09b02 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
@@ -411,3 +411,316 @@ encodeLoop:
println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
}
}
+
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *doubleFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ const (
+ // Input margin is the number of bytes we read (8)
+ // and the maximum we will read ahead (2)
+ inputMargin = 8 + 2
+ minNonLiteralBlockSize = 16
+ )
+
+ // Protect against e.cur wraparound.
+ if e.cur > (1<<30)+e.maxMatchOff {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ for i := range e.longTable[:] {
+ e.longTable[i] = tableEntry{}
+ }
+ e.cur = e.maxMatchOff
+ }
+
+ s := int32(0)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ // Override src
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 1.
+ stepSize := int32(e.o.targetLength)
+ if stepSize == 0 {
+ stepSize++
+ }
+
+ const kSearchStrength = 8
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debug {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ var t int32
+ for {
+
+ nextHashS := hash5(cv, dFastShortTableBits)
+ nextHashL := hash8(cv, dFastLongTableBits)
+ candidateL := e.longTable[nextHashL]
+ candidateS := e.table[nextHashS]
+
+ const repOff = 1
+ repIndex := s - offset1 + repOff
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+
+ if len(blk.sequences) > 2 {
+ if load3232(src, repIndex) == uint32(cv>>(repOff*8)) {
+ // Consider history as well.
+ var seq seq
+ //length := 4 + e.matchlen(s+4+repOff, repIndex+4, src)
+ length := 4 + int32(matchLen(src[s+4+repOff:], src[repIndex+4:]))
+
+ seq.matchLen = uint32(length - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + repOff
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ tMin := s - e.maxMatchOff
+ if tMin < 0 {
+ tMin = 0
+ }
+ for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += length + repOff
+ nextEmit = s
+ if s >= sLimit {
+ if debug {
+ println("repeat ended", s, length)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ }
+ // Find the offsets of our two matches.
+ coffsetL := s - (candidateL.offset - e.cur)
+ coffsetS := s - (candidateS.offset - e.cur)
+
+ // Check if we have a long match.
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ if debug && s <= t {
+ panic("s <= t")
+ }
+ if debug && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debugMatches {
+ println("long match")
+ }
+ break
+ }
+
+ // Check if we have a short match.
+ if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val {
+ // found a regular match
+ // See if we can find a long match at s+1
+ const checkAt = 1
+ cv := load6432(src, s+checkAt)
+ nextHashL = hash8(cv, dFastLongTableBits)
+ candidateL = e.longTable[nextHashL]
+ coffsetL = s - (candidateL.offset - e.cur) + checkAt
+
+ // We can store it, since we have at least a 4 byte match.
+ e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)}
+ if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val {
+ // Found a long match, likely at least 8 bytes.
+ // Reference encoder checks all 8 bytes, we only check 4,
+ // but the likelihood of both the first 4 bytes and the hash matching should be enough.
+ t = candidateL.offset - e.cur
+ s += checkAt
+ if debugMatches {
+ println("long match (after short)")
+ }
+ break
+ }
+
+ t = candidateS.offset - e.cur
+ if debug && s <= t {
+ panic("s <= t")
+ }
+ if debug && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debug && t < 0 {
+ panic("t<0")
+ }
+ if debugMatches {
+ println("short match")
+ }
+ break
+ }
+
+ // No match found, move forward in input.
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+
+ // A 4-byte match has been found. Update recent offsets.
+ // We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debug && s <= t {
+ panic("s <= t")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ //l := e.matchlen(s+4, t+4, src) + 4
+ l := int32(matchLen(src[s+4:], src[t+4:])) + 4
+
+ // Extend backwards
+ tMin := s - e.maxMatchOff
+ if tMin < 0 {
+ tMin = 0
+ }
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+
+ // Index match start+1 (long) and start+2 (short)
+ index0 := s - l + 1
+ // Index match end-2 (long) and end-1 (short)
+ index1 := s - 2
+
+ cv0 := load6432(src, index0)
+ cv1 := load6432(src, index1)
+ te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)}
+ te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)}
+ e.longTable[hash8(cv0, dFastLongTableBits)] = te0
+ e.longTable[hash8(cv1, dFastLongTableBits)] = te1
+ cv0 >>= 8
+ cv1 >>= 8
+ te0.offset++
+ te1.offset++
+ te0.val = uint32(cv0)
+ te1.val = uint32(cv1)
+ e.table[hash5(cv0, dFastShortTableBits)] = te0
+ e.table[hash5(cv1, dFastShortTableBits)] = te1
+
+ cv = load6432(src, s)
+
+ if len(blk.sequences) <= 2 {
+ continue
+ }
+
+ // Check offset 2
+ for {
+ o2 := s - offset2
+ if load3232(src, o2) != uint32(cv) {
+ // Do regular search
+ break
+ }
+
+ // Store this, since we have it.
+ nextHashS := hash5(cv1>>8, dFastShortTableBits)
+ nextHashL := hash8(cv, dFastLongTableBits)
+
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ //l := 4 + e.matchlen(s+4, o2+4, src)
+ l := 4 + int32(matchLen(src[s+4:], src[o2+4:]))
+
+ entry := tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.longTable[nextHashL] = entry
+ e.table[nextHashS] = entry
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ // Finished
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ if debug {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
index 6f388de04..0bdddac5b 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_fast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
@@ -329,6 +329,246 @@ encodeLoop:
}
}
+// EncodeNoHist will encode a block with no history and no following blocks.
+// Most notable difference is that src will not be copied for history and
+// we do not need to check for max match length.
+func (e *fastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
+ const (
+ inputMargin = 8
+ minNonLiteralBlockSize = 1 + 1 + inputMargin
+ )
+ if debug {
+ if len(src) > maxBlockSize {
+ panic("src too big")
+ }
+ }
+ // Protect against e.cur wraparound.
+ if e.cur > (1<<30)+e.maxMatchOff {
+ for i := range e.table[:] {
+ e.table[i] = tableEntry{}
+ }
+ e.cur = e.maxMatchOff
+ }
+
+ s := int32(0)
+ blk.size = len(src)
+ if len(src) < minNonLiteralBlockSize {
+ blk.extraLits = len(src)
+ blk.literals = blk.literals[:len(src)]
+ copy(blk.literals, src)
+ return
+ }
+
+ sLimit := int32(len(src)) - inputMargin
+ // stepSize is the number of bytes to skip on every main loop iteration.
+ // It should be >= 2.
+ const stepSize = 2
+
+ // TEMPLATE
+ const hashLog = tableBits
+ // seems global, but would be nice to tweak.
+ const kSearchStrength = 8
+
+ // nextEmit is where in src the next emitLiteral should start from.
+ nextEmit := s
+ cv := load6432(src, s)
+
+ // Relative offsets
+ offset1 := int32(blk.recentOffsets[0])
+ offset2 := int32(blk.recentOffsets[1])
+
+ addLiterals := func(s *seq, until int32) {
+ if until == nextEmit {
+ return
+ }
+ blk.literals = append(blk.literals, src[nextEmit:until]...)
+ s.litLen = uint32(until - nextEmit)
+ }
+ if debug {
+ println("recent offsets:", blk.recentOffsets)
+ }
+
+encodeLoop:
+ for {
+ // t will contain the match offset when we find one.
+ // When existing the search loop, we have already checked 4 bytes.
+ var t int32
+
+ // We will not use repeat offsets across blocks.
+ // By not using them for the first 3 matches
+
+ for {
+ nextHash := hash6(cv, hashLog)
+ nextHash2 := hash6(cv>>8, hashLog)
+ candidate := e.table[nextHash]
+ candidate2 := e.table[nextHash2]
+ repIndex := s - offset1 + 2
+
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)}
+
+ if len(blk.sequences) > 2 && load3232(src, repIndex) == uint32(cv>>16) {
+ // Consider history as well.
+ var seq seq
+ // lenght := 4 + e.matchlen(s+6, repIndex+4, src)
+ lenght := 4 + int32(matchLen(src[s+6:], src[repIndex+4:]))
+
+ seq.matchLen = uint32(lenght - zstdMinMatch)
+
+ // We might be able to match backwards.
+ // Extend as long as we can.
+ start := s + 2
+ // We end the search early, so we don't risk 0 literals
+ // and have to do special offset treatment.
+ startLimit := nextEmit + 1
+
+ sMin := s - e.maxMatchOff
+ if sMin < 0 {
+ sMin = 0
+ }
+ for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] {
+ repIndex--
+ start--
+ seq.matchLen++
+ }
+ addLiterals(&seq, start)
+
+ // rep 0
+ seq.offset = 1
+ if debugSequences {
+ println("repeat sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ s += lenght + 2
+ nextEmit = s
+ if s >= sLimit {
+ if debug {
+ println("repeat ended", s, lenght)
+
+ }
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ continue
+ }
+ coffset0 := s - (candidate.offset - e.cur)
+ coffset1 := s - (candidate2.offset - e.cur) + 1
+ if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val {
+ // found a regular match
+ t = candidate.offset - e.cur
+ if debug && s <= t {
+ panic("s <= t")
+ }
+ if debug && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ break
+ }
+
+ if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val {
+ // found a regular match
+ t = candidate2.offset - e.cur
+ s++
+ if debug && s <= t {
+ panic("s <= t")
+ }
+ if debug && s-t > e.maxMatchOff {
+ panic("s - t >e.maxMatchOff")
+ }
+ if debug && t < 0 {
+ panic("t<0")
+ }
+ break
+ }
+ s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1))
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+ }
+ // A 4-byte match has been found. We'll later see if more than 4 bytes.
+ offset2 = offset1
+ offset1 = s - t
+
+ if debug && s <= t {
+ panic("s <= t")
+ }
+
+ // Extend the 4-byte match as long as possible.
+ //l := e.matchlenNoHist(s+4, t+4, src) + 4
+ l := int32(matchLen(src[s+4:], src[t+4:])) + 4
+
+ // Extend backwards
+ tMin := s - e.maxMatchOff
+ if tMin < 0 {
+ tMin = 0
+ }
+ for t > tMin && s > nextEmit && src[t-1] == src[s-1] {
+ s--
+ t--
+ l++
+ }
+
+ // Write our sequence.
+ var seq seq
+ seq.litLen = uint32(s - nextEmit)
+ seq.matchLen = uint32(l - zstdMinMatch)
+ if seq.litLen > 0 {
+ blk.literals = append(blk.literals, src[nextEmit:s]...)
+ }
+ // Don't use repeat offsets
+ seq.offset = uint32(s-t) + 3
+ s += l
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+ nextEmit = s
+ if s >= sLimit {
+ break encodeLoop
+ }
+ cv = load6432(src, s)
+
+ // Check offset 2
+ if o2 := s - offset2; len(blk.sequences) > 2 && load3232(src, o2) == uint32(cv) {
+ // We have at least 4 byte match.
+ // No need to check backwards. We come straight from a match
+ //l := 4 + e.matchlenNoHist(s+4, o2+4, src)
+ l := 4 + int32(matchLen(src[s+4:], src[o2+4:]))
+
+ // Store this, since we have it.
+ nextHash := hash6(cv, hashLog)
+ e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)}
+ seq.matchLen = uint32(l) - zstdMinMatch
+ seq.litLen = 0
+ // Since litlen is always 0, this is offset 1.
+ seq.offset = 1
+ s += l
+ nextEmit = s
+ if debugSequences {
+ println("sequence", seq, "next s:", s)
+ }
+ blk.sequences = append(blk.sequences, seq)
+
+ // Swap offset 1 and 2.
+ offset1, offset2 = offset2, offset1
+ if s >= sLimit {
+ break encodeLoop
+ }
+ // Prepare next loop.
+ cv = load6432(src, s)
+ }
+ }
+
+ if int(nextEmit) < len(src) {
+ blk.literals = append(blk.literals, src[nextEmit:]...)
+ blk.extraLits = len(src) - int(nextEmit)
+ }
+ if debug {
+ println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits)
+ }
+}
+
func (e *fastEncoder) addBlock(src []byte) int32 {
// check if we have space already
if len(e.hist)+len(src) > cap(e.hist) {
@@ -362,6 +602,11 @@ func (e *fastEncoder) UseBlock(enc *blockEnc) {
e.blk = enc
}
+func (e *fastEncoder) matchlenNoHist(s, t int32, src []byte) int32 {
+ // Extend the match to be as long as possible.
+ return int32(matchLen(src[s:], src[t:]))
+}
+
func (e *fastEncoder) matchlen(s, t int32, src []byte) int32 {
if debug {
if s < 0 {
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go
index f413042f4..366dd66bd 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder.go
@@ -29,6 +29,7 @@ type Encoder struct {
type encoder interface {
Encode(blk *blockEnc, src []byte)
+ EncodeNoHist(blk *blockEnc, src []byte)
Block() *blockEnc
CRC() *xxhash.Digest
AppendCRC([]byte) []byte
@@ -433,7 +434,8 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
}()
enc.Reset()
blk := enc.Block()
- single := len(src) > 1<<20
+ // Use single segments when above minimum window and below 1MB.
+ single := len(src) < 1<<20 && len(src) > MinWindowSize
if e.o.single != nil {
single = *e.o.single
}
@@ -454,25 +456,22 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
panic(err)
}
- for len(src) > 0 {
- todo := src
- if len(todo) > e.o.blockSize {
- todo = todo[:e.o.blockSize]
- }
- src = src[len(todo):]
+ if len(src) <= e.o.blockSize && len(src) <= maxBlockSize {
+ // Slightly faster with no history and everything in one block.
if e.o.crc {
- _, _ = enc.CRC().Write(todo)
+ _, _ = enc.CRC().Write(src)
}
blk.reset(nil)
- blk.pushOffsets()
- enc.Encode(blk, todo)
- if len(src) == 0 {
- blk.last = true
- }
- err := errIncompressible
+ blk.last = true
+ enc.EncodeNoHist(blk, src)
+
// If we got the exact same number of literals as input,
// assume the literals cannot be compressed.
- if len(blk.literals) != len(todo) || len(todo) != e.o.blockSize {
+ err := errIncompressible
+ oldout := blk.output
+ if len(blk.literals) != len(src) || len(src) != e.o.blockSize {
+ // Output directly to dst
+ blk.output = dst
err = blk.encode(e.o.noEntropy)
}
@@ -481,13 +480,49 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
if debug {
println("Storing incompressible block as raw")
}
- blk.encodeRaw(todo)
- blk.popOffsets()
+ dst = blk.encodeRawTo(dst, src)
case nil:
+ dst = blk.output
default:
panic(err)
}
- dst = append(dst, blk.output...)
+ blk.output = oldout
+ } else {
+ for len(src) > 0 {
+ todo := src
+ if len(todo) > e.o.blockSize {
+ todo = todo[:e.o.blockSize]
+ }
+ src = src[len(todo):]
+ if e.o.crc {
+ _, _ = enc.CRC().Write(todo)
+ }
+ blk.reset(nil)
+ blk.pushOffsets()
+ enc.Encode(blk, todo)
+ if len(src) == 0 {
+ blk.last = true
+ }
+ err := errIncompressible
+ // If we got the exact same number of literals as input,
+ // assume the literals cannot be compressed.
+ if len(blk.literals) != len(todo) || len(todo) != e.o.blockSize {
+ err = blk.encode(e.o.noEntropy)
+ }
+
+ switch err {
+ case errIncompressible:
+ if debug {
+ println("Storing incompressible block as raw")
+ }
+ dst = blk.encodeRawTo(dst, todo)
+ blk.popOffsets()
+ case nil:
+ dst = append(dst, blk.output...)
+ default:
+ panic(err)
+ }
+ }
}
if e.o.crc {
dst = enc.AppendCRC(dst)
diff --git a/vendor/github.com/mattn/go-shellwords/.travis.yml b/vendor/github.com/mattn/go-shellwords/.travis.yml
index 6294d337f..b2904bffc 100644
--- a/vendor/github.com/mattn/go-shellwords/.travis.yml
+++ b/vendor/github.com/mattn/go-shellwords/.travis.yml
@@ -11,4 +11,3 @@ script:
after_success:
- bash <(curl -s https://codecov.io/bash)
-
diff --git a/vendor/github.com/mattn/go-shellwords/README.md b/vendor/github.com/mattn/go-shellwords/README.md
index 9e1e65045..e91902f40 100644
--- a/vendor/github.com/mattn/go-shellwords/README.md
+++ b/vendor/github.com/mattn/go-shellwords/README.md
@@ -2,6 +2,7 @@
[![codecov](https://codecov.io/gh/mattn/go-shellwords/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-shellwords)
[![Build Status](https://travis-ci.org/mattn/go-shellwords.svg?branch=master)](https://travis-ci.org/mattn/go-shellwords)
+[![GoDoc](https://godoc.org/github.com/mattn/go-shellwords?status.svg)](http://godoc.org/github.com/mattn/go-shellwords)
Parse line as shell words.
diff --git a/vendor/github.com/mattn/go-shellwords/shellwords.go b/vendor/github.com/mattn/go-shellwords/shellwords.go
index 2dca7f136..ff5e73091 100644
--- a/vendor/github.com/mattn/go-shellwords/shellwords.go
+++ b/vendor/github.com/mattn/go-shellwords/shellwords.go
@@ -144,11 +144,17 @@ loop:
}
case '"':
if !singleQuoted && !dollarQuote {
+ if doubleQuoted && buf == "" {
+ got = true
+ }
doubleQuoted = !doubleQuoted
continue
}
case '\'':
if !doubleQuoted && !dollarQuote {
+ if singleQuoted && buf == "" {
+ got = true
+ }
singleQuoted = !singleQuoted
continue
}
diff --git a/vendor/github.com/pkg/errors/cause.go b/vendor/github.com/pkg/errors/cause.go
deleted file mode 100644
index 566f88bb0..000000000
--- a/vendor/github.com/pkg/errors/cause.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// +build !go1.13
-
-package errors
-
-// Cause recursively unwraps an error chain and returns the underlying cause of
-// the error, if possible. An error value has a cause if it implements the
-// following interface:
-//
-// type causer interface {
-// Cause() error
-// }
-//
-// If the error does not implement Cause, the original error will
-// be returned. If the error is nil, nil will be returned without further
-// investigation.
-func Cause(err error) error {
- type causer interface {
- Cause() error
- }
-
- for err != nil {
- cause, ok := err.(causer)
- if !ok {
- break
- }
- err = cause.Cause()
- }
- return err
-}
diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go
index a9840ecee..161aea258 100644
--- a/vendor/github.com/pkg/errors/errors.go
+++ b/vendor/github.com/pkg/errors/errors.go
@@ -260,3 +260,29 @@ func (w *withMessage) Format(s fmt.State, verb rune) {
io.WriteString(s, w.Error())
}
}
+
+// Cause returns the underlying cause of the error, if possible.
+// An error value has a cause if it implements the following
+// interface:
+//
+// type causer interface {
+// Cause() error
+// }
+//
+// If the error does not implement Cause, the original error will
+// be returned. If the error is nil, nil will be returned without further
+// investigation.
+func Cause(err error) error {
+ type causer interface {
+ Cause() error
+ }
+
+ for err != nil {
+ cause, ok := err.(causer)
+ if !ok {
+ break
+ }
+ err = cause.Cause()
+ }
+ return err
+}
diff --git a/vendor/github.com/pkg/errors/go113.go b/vendor/github.com/pkg/errors/go113.go
index ed0dc7a6d..be0d10d0c 100644
--- a/vendor/github.com/pkg/errors/go113.go
+++ b/vendor/github.com/pkg/errors/go113.go
@@ -36,36 +36,3 @@ func As(err error, target interface{}) bool { return stderrors.As(err, target) }
func Unwrap(err error) error {
return stderrors.Unwrap(err)
}
-
-// Cause recursively unwraps an error chain and returns the underlying cause of
-// the error, if possible. There are two ways that an error value may provide a
-// cause. First, the error may implement the following interface:
-//
-// type causer interface {
-// Cause() error
-// }
-//
-// Second, the error may return a non-nil value when passed as an argument to
-// the Unwrap function. This makes Cause forwards-compatible with Go 1.13 error
-// chains.
-//
-// If an error value satisfies both methods of unwrapping, Cause will use the
-// causer interface.
-//
-// If the error is nil, nil will be returned without further investigation.
-func Cause(err error) error {
- type causer interface {
- Cause() error
- }
-
- for err != nil {
- if cause, ok := err.(causer); ok {
- err = cause.Cause()
- } else if unwrapped := Unwrap(err); unwrapped != nil {
- err = unwrapped
- } else {
- break
- }
- }
- return err
-}
diff --git a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
index 5e7e9d5e5..818568b28 100644
--- a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
+++ b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
@@ -1,6 +1,34 @@
Changes by Version
==================
+2.22.1 (2020-01-16)
+-------------------
+
+- Increase UDP batch overhead to account for data loss metrics ([#488](https://github.com/jaegertracing/jaeger-client-go/pull/488)) -- Yuri Shkuro
+
+
+2.22.0 (2020-01-15)
+-------------------
+
+- Report data loss stats to Jaeger backend ([#482](https://github.com/jaegertracing/jaeger-client-go/pull/482)) -- Yuri Shkuro
+- Add limit on log records per span ([#483](https://github.com/jaegertracing/jaeger-client-go/pull/483)) -- Sokolov Yura
+
+
+2.21.1 (2019-12-20)
+-------------------
+
+- Update version correctly.
+
+
+2.21.0 (2019-12-20)
+-------------------
+
+- Clarify reporting error logs ([#469](https://github.com/jaegertracing/jaeger-client-go/pull/469)) -- Yuri Shkuro
+- Do not strip leading zeros from trace IDs ([#472](https://github.com/jaegertracing/jaeger-client-go/pull/472)) -- Yuri Shkuro
+- Chore (docs): fixed a couple of typos ([#475](https://github.com/jaegertracing/jaeger-client-go/pull/475)) -- Marc Bramaud
+- Support custom HTTP headers when reporting spans over HTTP ([#479](https://github.com/jaegertracing/jaeger-client-go/pull/479)) -- Albert Teoh
+
+
2.20.1 (2019-11-08)
-------------------
diff --git a/vendor/github.com/uber/jaeger-client-go/Makefile b/vendor/github.com/uber/jaeger-client-go/Makefile
index 0cfe6a5f6..d5e962ccf 100644
--- a/vendor/github.com/uber/jaeger-client-go/Makefile
+++ b/vendor/github.com/uber/jaeger-client-go/Makefile
@@ -83,8 +83,12 @@ cover-html: cover
test-examples:
make -C examples
+.PHONY: thrift
+thrift: idl-submodule thrift-compile
+
# TODO at the moment we're not generating tchan_*.go files
-thrift: idl-submodule thrift-image
+.PHONY: thrift-compile
+thrift-compile: thrift-image
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/agent.thrift
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/sampling.thrift
$(THRIFT) -o /data --gen go:$(THRIFT_GO_ARGS) --out /data/$(THRIFT_GEN_DIR) /data/idl/thrift/jaeger.thrift
@@ -99,10 +103,12 @@ thrift: idl-submodule thrift-image
rm -rf crossdock/thrift/*/*-remote
rm -rf thrift-gen/jaeger/collector.go
+.PHONY: idl-submodule
idl-submodule:
git submodule init
git submodule update
+.PHONY: thrift-image
thrift-image:
$(THRIFT) -version
diff --git a/vendor/github.com/uber/jaeger-client-go/README.md b/vendor/github.com/uber/jaeger-client-go/README.md
index a3366114d..0e4d9fc0b 100644
--- a/vendor/github.com/uber/jaeger-client-go/README.md
+++ b/vendor/github.com/uber/jaeger-client-go/README.md
@@ -45,7 +45,7 @@ and [config/example_test.go](./config/example_test.go).
### Environment variables
The tracer can be initialized with values coming from environment variables. None of the env vars are required
-and all of them can be overriden via direct setting of the property on the configuration object.
+and all of them can be overridden via direct setting of the property on the configuration object.
Property| Description
--- | ---
diff --git a/vendor/github.com/uber/jaeger-client-go/config/config.go b/vendor/github.com/uber/jaeger-client-go/config/config.go
index a0c32d804..44e93533c 100644
--- a/vendor/github.com/uber/jaeger-client-go/config/config.go
+++ b/vendor/github.com/uber/jaeger-client-go/config/config.go
@@ -134,6 +134,10 @@ type ReporterConfig struct {
// Password instructs reporter to include a password for basic http authentication when sending spans to
// jaeger-collector. Can be set by exporting an environment variable named JAEGER_PASSWORD
Password string `yaml:"password"`
+
+ // HTTPHeaders instructs the reporter to add these headers to the http request when reporting spans.
+ // This field takes effect only when using HTTPTransport by setting the CollectorEndpoint.
+ HTTPHeaders map[string]string `yaml:"http_headers"`
}
// BaggageRestrictionsConfig configures the baggage restrictions manager which can be used to whitelist
@@ -397,11 +401,12 @@ func (rc *ReporterConfig) NewReporter(
func (rc *ReporterConfig) newTransport() (jaeger.Transport, error) {
switch {
- case rc.CollectorEndpoint != "" && rc.User != "" && rc.Password != "":
- return transport.NewHTTPTransport(rc.CollectorEndpoint, transport.HTTPBatchSize(1),
- transport.HTTPBasicAuth(rc.User, rc.Password)), nil
case rc.CollectorEndpoint != "":
- return transport.NewHTTPTransport(rc.CollectorEndpoint, transport.HTTPBatchSize(1)), nil
+ httpOptions := []transport.HTTPOption{transport.HTTPBatchSize(1), transport.HTTPHeaders(rc.HTTPHeaders)}
+ if rc.User != "" && rc.Password != "" {
+ httpOptions = append(httpOptions, transport.HTTPBasicAuth(rc.User, rc.Password))
+ }
+ return transport.NewHTTPTransport(rc.CollectorEndpoint, httpOptions...), nil
default:
return jaeger.NewUDPTransport(rc.LocalAgentHostPort, 0)
}
diff --git a/vendor/github.com/uber/jaeger-client-go/constants.go b/vendor/github.com/uber/jaeger-client-go/constants.go
index 5d27b628d..1702c7de4 100644
--- a/vendor/github.com/uber/jaeger-client-go/constants.go
+++ b/vendor/github.com/uber/jaeger-client-go/constants.go
@@ -22,7 +22,7 @@ import (
const (
// JaegerClientVersion is the version of the client library reported as Span tag.
- JaegerClientVersion = "Go-2.20.1"
+ JaegerClientVersion = "Go-2.22.1"
// JaegerClientVersionTagKey is the name of the tag used to report client version.
JaegerClientVersionTagKey = "jaeger.version"
diff --git a/vendor/github.com/uber/jaeger-client-go/internal/reporterstats/stats.go b/vendor/github.com/uber/jaeger-client-go/internal/reporterstats/stats.go
new file mode 100644
index 000000000..fe0bef268
--- /dev/null
+++ b/vendor/github.com/uber/jaeger-client-go/internal/reporterstats/stats.go
@@ -0,0 +1,25 @@
+// Copyright (c) 2020 The Jaeger Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package reporterstats
+
+// ReporterStats exposes some metrics from the RemoteReporter.
+type ReporterStats interface {
+ SpansDroppedFromQueue() int64
+}
+
+// Receiver can be implemented by a Transport to be given ReporterStats.
+type Receiver interface {
+ SetReporterStats(ReporterStats)
+}
diff --git a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go
index f0f1afe2f..3ac2f8f94 100644
--- a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go
+++ b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go
@@ -24,6 +24,7 @@ import (
)
// BuildJaegerThrift builds jaeger span based on internal span.
+// TODO: (breaking change) move to internal package.
func BuildJaegerThrift(span *Span) *j.Span {
span.Lock()
defer span.Unlock()
@@ -46,6 +47,7 @@ func BuildJaegerThrift(span *Span) *j.Span {
}
// BuildJaegerProcessThrift creates a thrift Process type.
+// TODO: (breaking change) move to internal package.
func BuildJaegerProcessThrift(span *Span) *j.Process {
span.Lock()
defer span.Unlock()
diff --git a/vendor/github.com/uber/jaeger-client-go/reporter.go b/vendor/github.com/uber/jaeger-client-go/reporter.go
index 0b78cec20..830b5a4bb 100644
--- a/vendor/github.com/uber/jaeger-client-go/reporter.go
+++ b/vendor/github.com/uber/jaeger-client-go/reporter.go
@@ -22,6 +22,7 @@ import (
"github.com/opentracing/opentracing-go"
+ "github.com/uber/jaeger-client-go/internal/reporterstats"
"github.com/uber/jaeger-client-go/log"
)
@@ -176,16 +177,31 @@ type reporterQueueItem struct {
close *sync.WaitGroup
}
+// reporterStats implements reporterstats.ReporterStats.
+type reporterStats struct {
+ droppedCount int64 // provided to Transports to report data loss to the backend
+}
+
+// SpansDroppedFromQueue implements reporterstats.ReporterStats.
+func (r *reporterStats) SpansDroppedFromQueue() int64 {
+ return atomic.LoadInt64(&r.droppedCount)
+}
+
+func (r *reporterStats) incDroppedCount() {
+ atomic.AddInt64(&r.droppedCount, 1)
+}
+
type remoteReporter struct {
// These fields must be first in the struct because `sync/atomic` expects 64-bit alignment.
// Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq
- queueLength int64
+ queueLength int64 // used to update metrics.Gauge
closed int64 // 0 - not closed, 1 - closed
reporterOptions
- sender Transport
- queue chan reporterQueueItem
+ sender Transport
+ queue chan reporterQueueItem
+ reporterStats *reporterStats
}
// NewRemoteReporter creates a new reporter that sends spans out of process by means of Sender.
@@ -213,6 +229,10 @@ func NewRemoteReporter(sender Transport, opts ...ReporterOption) Reporter {
reporterOptions: options,
sender: sender,
queue: make(chan reporterQueueItem, options.queueSize),
+ reporterStats: new(reporterStats),
+ }
+ if receiver, ok := sender.(reporterstats.Receiver); ok {
+ receiver.SetReporterStats(reporter.reporterStats)
}
go reporter.processQueue()
return reporter
@@ -231,6 +251,7 @@ func (r *remoteReporter) Report(span *Span) {
atomic.AddInt64(&r.queueLength, 1)
default:
r.metrics.ReporterDropped.Inc(1)
+ r.reporterStats.incDroppedCount()
}
}
@@ -241,7 +262,7 @@ func (r *remoteReporter) Close() {
return
}
r.sendCloseEvent()
- r.sender.Close()
+ _ = r.sender.Close()
}
func (r *remoteReporter) sendCloseEvent() {
@@ -263,7 +284,7 @@ func (r *remoteReporter) processQueue() {
flush := func() {
if flushed, err := r.sender.Flush(); err != nil {
r.metrics.ReporterFailure.Inc(int64(flushed))
- r.logger.Error(fmt.Sprintf("error when flushing the buffer: %s", err.Error()))
+ r.logger.Error(fmt.Sprintf("failed to flush Jaeger spans to server: %s", err.Error()))
} else if flushed > 0 {
r.metrics.ReporterSuccess.Inc(int64(flushed))
}
@@ -281,7 +302,7 @@ func (r *remoteReporter) processQueue() {
span := item.span
if flushed, err := r.sender.Append(span); err != nil {
r.metrics.ReporterFailure.Inc(int64(flushed))
- r.logger.Error(fmt.Sprintf("error reporting span %q: %s", span.OperationName(), err.Error()))
+ r.logger.Error(fmt.Sprintf("error reporting Jaeger span %q: %s", span.OperationName(), err.Error()))
} else if flushed > 0 {
r.metrics.ReporterSuccess.Inc(int64(flushed))
// to reduce the number of gauge stats, we only emit queue length on flush
diff --git a/vendor/github.com/uber/jaeger-client-go/span.go b/vendor/github.com/uber/jaeger-client-go/span.go
index bbf6fb068..42c9112c0 100644
--- a/vendor/github.com/uber/jaeger-client-go/span.go
+++ b/vendor/github.com/uber/jaeger-client-go/span.go
@@ -59,6 +59,9 @@ type Span struct {
// The span's "micro-log"
logs []opentracing.LogRecord
+ // The number of logs dropped because of MaxLogsPerSpan.
+ numDroppedLogs int
+
// references for this span
references []Reference
@@ -152,7 +155,12 @@ func (s *Span) Logs() []opentracing.LogRecord {
s.Lock()
defer s.Unlock()
- return append([]opentracing.LogRecord(nil), s.logs...)
+ logs := append([]opentracing.LogRecord(nil), s.logs...)
+ if s.numDroppedLogs != 0 {
+ fixLogs(logs, s.numDroppedLogs)
+ }
+
+ return logs
}
// References returns references for this span
@@ -234,8 +242,65 @@ func (s *Span) Log(ld opentracing.LogData) {
// this function should only be called while holding a Write lock
func (s *Span) appendLogNoLocking(lr opentracing.LogRecord) {
- // TODO add logic to limit number of logs per span (issue #46)
- s.logs = append(s.logs, lr)
+ maxLogs := s.tracer.options.maxLogsPerSpan
+ if maxLogs == 0 || len(s.logs) < maxLogs {
+ s.logs = append(s.logs, lr)
+ return
+ }
+
+ // We have too many logs. We don't touch the first numOld logs; we treat the
+ // rest as a circular buffer and overwrite the oldest log among those.
+ numOld := (maxLogs - 1) / 2
+ numNew := maxLogs - numOld
+ s.logs[numOld+s.numDroppedLogs%numNew] = lr
+ s.numDroppedLogs++
+}
+
+// rotateLogBuffer rotates the records in the buffer: records 0 to pos-1 move at
+// the end (i.e. pos circular left shifts).
+func rotateLogBuffer(buf []opentracing.LogRecord, pos int) {
+ // This algorithm is described in:
+ // http://www.cplusplus.com/reference/algorithm/rotate
+ for first, middle, next := 0, pos, pos; first != middle; {
+ buf[first], buf[next] = buf[next], buf[first]
+ first++
+ next++
+ if next == len(buf) {
+ next = middle
+ } else if first == middle {
+ middle = next
+ }
+ }
+}
+
+func fixLogs(logs []opentracing.LogRecord, numDroppedLogs int) {
+ // We dropped some log events, which means that we used part of Logs as a
+ // circular buffer (see appendLog). De-circularize it.
+ numOld := (len(logs) - 1) / 2
+ numNew := len(logs) - numOld
+ rotateLogBuffer(logs[numOld:], numDroppedLogs%numNew)
+
+ // Replace the log in the middle (the oldest "new" log) with information
+ // about the dropped logs. This means that we are effectively dropping one
+ // more "new" log.
+ numDropped := numDroppedLogs + 1
+ logs[numOld] = opentracing.LogRecord{
+ // Keep the timestamp of the last dropped event.
+ Timestamp: logs[numOld].Timestamp,
+ Fields: []log.Field{
+ log.String("event", "dropped Span logs"),
+ log.Int("dropped_log_count", numDropped),
+ log.String("component", "jaeger-client"),
+ },
+ }
+}
+
+func (s *Span) fixLogsIfDropped() {
+ if s.numDroppedLogs == 0 {
+ return
+ }
+ fixLogs(s.logs, s.numDroppedLogs)
+ s.numDroppedLogs = 0
}
// SetBaggageItem implements SetBaggageItem() of opentracing.SpanContext
@@ -274,8 +339,9 @@ func (s *Span) FinishWithOptions(options opentracing.FinishOptions) {
s.applySamplingDecision(decision, true)
}
if s.context.IsSampled() {
+ s.Lock()
+ s.fixLogsIfDropped()
if len(options.LogRecords) > 0 || len(options.BulkLogData) > 0 {
- s.Lock()
// Note: bulk logs are not subject to maxLogsPerSpan limit
if options.LogRecords != nil {
s.logs = append(s.logs, options.LogRecords...)
@@ -283,8 +349,8 @@ func (s *Span) FinishWithOptions(options opentracing.FinishOptions) {
for _, ld := range options.BulkLogData {
s.logs = append(s.logs, ld.ToLogRecord())
}
- s.Unlock()
}
+ s.Unlock()
}
// call reportSpan even for non-sampled traces, to return span to the pool
// and update metrics counter
@@ -344,6 +410,7 @@ func (s *Span) reset() {
// Note: To reuse memory we can save the pointers on the heap
s.tags = s.tags[:0]
s.logs = s.logs[:0]
+ s.numDroppedLogs = 0
s.references = s.references[:0]
}
diff --git a/vendor/github.com/uber/jaeger-client-go/span_context.go b/vendor/github.com/uber/jaeger-client-go/span_context.go
index b7230abfe..1b44f3f8c 100644
--- a/vendor/github.com/uber/jaeger-client-go/span_context.go
+++ b/vendor/github.com/uber/jaeger-client-go/span_context.go
@@ -213,9 +213,9 @@ func (c SpanContext) SetFirehose() {
func (c SpanContext) String() string {
if c.traceID.High == 0 {
- return fmt.Sprintf("%x:%x:%x:%x", c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.samplingState.stateFlags.Load())
+ return fmt.Sprintf("%016x:%016x:%016x:%x", c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.samplingState.stateFlags.Load())
}
- return fmt.Sprintf("%x%016x:%x:%x:%x", c.traceID.High, c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.samplingState.stateFlags.Load())
+ return fmt.Sprintf("%016x%016x:%016x:%016x:%x", c.traceID.High, c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.samplingState.stateFlags.Load())
}
// ContextFromString reconstructs the Context encoded in a string
diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go
index d23ed2fc2..e69c6d603 100644
--- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go
+++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/jaeger/ttypes.go
@@ -1577,11 +1577,192 @@ func (p *Process) String() string {
}
// Attributes:
+// - FullQueueDroppedSpans
+// - TooLargeDroppedSpans
+// - FailedToEmitSpans
+type ClientStats struct {
+ FullQueueDroppedSpans int64 `thrift:"fullQueueDroppedSpans,1,required" json:"fullQueueDroppedSpans"`
+ TooLargeDroppedSpans int64 `thrift:"tooLargeDroppedSpans,2,required" json:"tooLargeDroppedSpans"`
+ FailedToEmitSpans int64 `thrift:"failedToEmitSpans,3,required" json:"failedToEmitSpans"`
+}
+
+func NewClientStats() *ClientStats {
+ return &ClientStats{}
+}
+
+func (p *ClientStats) GetFullQueueDroppedSpans() int64 {
+ return p.FullQueueDroppedSpans
+}
+
+func (p *ClientStats) GetTooLargeDroppedSpans() int64 {
+ return p.TooLargeDroppedSpans
+}
+
+func (p *ClientStats) GetFailedToEmitSpans() int64 {
+ return p.FailedToEmitSpans
+}
+func (p *ClientStats) Read(iprot thrift.TProtocol) error {
+ if _, err := iprot.ReadStructBegin(); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
+ }
+
+ var issetFullQueueDroppedSpans bool = false
+ var issetTooLargeDroppedSpans bool = false
+ var issetFailedToEmitSpans bool = false
+
+ for {
+ _, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()
+ if err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T field %d read error: ", p, fieldId), err)
+ }
+ if fieldTypeId == thrift.STOP {
+ break
+ }
+ switch fieldId {
+ case 1:
+ if err := p.readField1(iprot); err != nil {
+ return err
+ }
+ issetFullQueueDroppedSpans = true
+ case 2:
+ if err := p.readField2(iprot); err != nil {
+ return err
+ }
+ issetTooLargeDroppedSpans = true
+ case 3:
+ if err := p.readField3(iprot); err != nil {
+ return err
+ }
+ issetFailedToEmitSpans = true
+ default:
+ if err := iprot.Skip(fieldTypeId); err != nil {
+ return err
+ }
+ }
+ if err := iprot.ReadFieldEnd(); err != nil {
+ return err
+ }
+ }
+ if err := iprot.ReadStructEnd(); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err)
+ }
+ if !issetFullQueueDroppedSpans {
+ return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field FullQueueDroppedSpans is not set"))
+ }
+ if !issetTooLargeDroppedSpans {
+ return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field TooLargeDroppedSpans is not set"))
+ }
+ if !issetFailedToEmitSpans {
+ return thrift.NewTProtocolExceptionWithType(thrift.INVALID_DATA, fmt.Errorf("Required field FailedToEmitSpans is not set"))
+ }
+ return nil
+}
+
+func (p *ClientStats) readField1(iprot thrift.TProtocol) error {
+ if v, err := iprot.ReadI64(); err != nil {
+ return thrift.PrependError("error reading field 1: ", err)
+ } else {
+ p.FullQueueDroppedSpans = v
+ }
+ return nil
+}
+
+func (p *ClientStats) readField2(iprot thrift.TProtocol) error {
+ if v, err := iprot.ReadI64(); err != nil {
+ return thrift.PrependError("error reading field 2: ", err)
+ } else {
+ p.TooLargeDroppedSpans = v
+ }
+ return nil
+}
+
+func (p *ClientStats) readField3(iprot thrift.TProtocol) error {
+ if v, err := iprot.ReadI64(); err != nil {
+ return thrift.PrependError("error reading field 3: ", err)
+ } else {
+ p.FailedToEmitSpans = v
+ }
+ return nil
+}
+
+func (p *ClientStats) Write(oprot thrift.TProtocol) error {
+ if err := oprot.WriteStructBegin("ClientStats"); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
+ }
+ if err := p.writeField1(oprot); err != nil {
+ return err
+ }
+ if err := p.writeField2(oprot); err != nil {
+ return err
+ }
+ if err := p.writeField3(oprot); err != nil {
+ return err
+ }
+ if err := oprot.WriteFieldStop(); err != nil {
+ return thrift.PrependError("write field stop error: ", err)
+ }
+ if err := oprot.WriteStructEnd(); err != nil {
+ return thrift.PrependError("write struct stop error: ", err)
+ }
+ return nil
+}
+
+func (p *ClientStats) writeField1(oprot thrift.TProtocol) (err error) {
+ if err := oprot.WriteFieldBegin("fullQueueDroppedSpans", thrift.I64, 1); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field begin error 1:fullQueueDroppedSpans: ", p), err)
+ }
+ if err := oprot.WriteI64(int64(p.FullQueueDroppedSpans)); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T.fullQueueDroppedSpans (1) field write error: ", p), err)
+ }
+ if err := oprot.WriteFieldEnd(); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field end error 1:fullQueueDroppedSpans: ", p), err)
+ }
+ return err
+}
+
+func (p *ClientStats) writeField2(oprot thrift.TProtocol) (err error) {
+ if err := oprot.WriteFieldBegin("tooLargeDroppedSpans", thrift.I64, 2); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:tooLargeDroppedSpans: ", p), err)
+ }
+ if err := oprot.WriteI64(int64(p.TooLargeDroppedSpans)); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T.tooLargeDroppedSpans (2) field write error: ", p), err)
+ }
+ if err := oprot.WriteFieldEnd(); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field end error 2:tooLargeDroppedSpans: ", p), err)
+ }
+ return err
+}
+
+func (p *ClientStats) writeField3(oprot thrift.TProtocol) (err error) {
+ if err := oprot.WriteFieldBegin("failedToEmitSpans", thrift.I64, 3); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:failedToEmitSpans: ", p), err)
+ }
+ if err := oprot.WriteI64(int64(p.FailedToEmitSpans)); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T.failedToEmitSpans (3) field write error: ", p), err)
+ }
+ if err := oprot.WriteFieldEnd(); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field end error 3:failedToEmitSpans: ", p), err)
+ }
+ return err
+}
+
+func (p *ClientStats) String() string {
+ if p == nil {
+ return "<nil>"
+ }
+ return fmt.Sprintf("ClientStats(%+v)", *p)
+}
+
+// Attributes:
// - Process
// - Spans
+// - SeqNo
+// - Stats
type Batch struct {
- Process *Process `thrift:"process,1,required" json:"process"`
- Spans []*Span `thrift:"spans,2,required" json:"spans"`
+ Process *Process `thrift:"process,1,required" json:"process"`
+ Spans []*Span `thrift:"spans,2,required" json:"spans"`
+ SeqNo *int64 `thrift:"seqNo,3" json:"seqNo,omitempty"`
+ Stats *ClientStats `thrift:"stats,4" json:"stats,omitempty"`
}
func NewBatch() *Batch {
@@ -1600,10 +1781,36 @@ func (p *Batch) GetProcess() *Process {
func (p *Batch) GetSpans() []*Span {
return p.Spans
}
+
+var Batch_SeqNo_DEFAULT int64
+
+func (p *Batch) GetSeqNo() int64 {
+ if !p.IsSetSeqNo() {
+ return Batch_SeqNo_DEFAULT
+ }
+ return *p.SeqNo
+}
+
+var Batch_Stats_DEFAULT *ClientStats
+
+func (p *Batch) GetStats() *ClientStats {
+ if !p.IsSetStats() {
+ return Batch_Stats_DEFAULT
+ }
+ return p.Stats
+}
func (p *Batch) IsSetProcess() bool {
return p.Process != nil
}
+func (p *Batch) IsSetSeqNo() bool {
+ return p.SeqNo != nil
+}
+
+func (p *Batch) IsSetStats() bool {
+ return p.Stats != nil
+}
+
func (p *Batch) Read(iprot thrift.TProtocol) error {
if _, err := iprot.ReadStructBegin(); err != nil {
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
@@ -1631,6 +1838,14 @@ func (p *Batch) Read(iprot thrift.TProtocol) error {
return err
}
issetSpans = true
+ case 3:
+ if err := p.readField3(iprot); err != nil {
+ return err
+ }
+ case 4:
+ if err := p.readField4(iprot); err != nil {
+ return err
+ }
default:
if err := iprot.Skip(fieldTypeId); err != nil {
return err
@@ -1680,6 +1895,23 @@ func (p *Batch) readField2(iprot thrift.TProtocol) error {
return nil
}
+func (p *Batch) readField3(iprot thrift.TProtocol) error {
+ if v, err := iprot.ReadI64(); err != nil {
+ return thrift.PrependError("error reading field 3: ", err)
+ } else {
+ p.SeqNo = &v
+ }
+ return nil
+}
+
+func (p *Batch) readField4(iprot thrift.TProtocol) error {
+ p.Stats = &ClientStats{}
+ if err := p.Stats.Read(iprot); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T error reading struct: ", p.Stats), err)
+ }
+ return nil
+}
+
func (p *Batch) Write(oprot thrift.TProtocol) error {
if err := oprot.WriteStructBegin("Batch"); err != nil {
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
@@ -1690,6 +1922,12 @@ func (p *Batch) Write(oprot thrift.TProtocol) error {
if err := p.writeField2(oprot); err != nil {
return err
}
+ if err := p.writeField3(oprot); err != nil {
+ return err
+ }
+ if err := p.writeField4(oprot); err != nil {
+ return err
+ }
if err := oprot.WriteFieldStop(); err != nil {
return thrift.PrependError("write field stop error: ", err)
}
@@ -1733,6 +1971,36 @@ func (p *Batch) writeField2(oprot thrift.TProtocol) (err error) {
return err
}
+func (p *Batch) writeField3(oprot thrift.TProtocol) (err error) {
+ if p.IsSetSeqNo() {
+ if err := oprot.WriteFieldBegin("seqNo", thrift.I64, 3); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field begin error 3:seqNo: ", p), err)
+ }
+ if err := oprot.WriteI64(int64(*p.SeqNo)); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T.seqNo (3) field write error: ", p), err)
+ }
+ if err := oprot.WriteFieldEnd(); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field end error 3:seqNo: ", p), err)
+ }
+ }
+ return err
+}
+
+func (p *Batch) writeField4(oprot thrift.TProtocol) (err error) {
+ if p.IsSetStats() {
+ if err := oprot.WriteFieldBegin("stats", thrift.STRUCT, 4); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field begin error 4:stats: ", p), err)
+ }
+ if err := p.Stats.Write(oprot); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T error writing struct: ", p.Stats), err)
+ }
+ if err := oprot.WriteFieldEnd(); err != nil {
+ return thrift.PrependError(fmt.Sprintf("%T write field end error 4:stats: ", p), err)
+ }
+ }
+ return err
+}
+
func (p *Batch) String() string {
if p == nil {
return "<nil>"
diff --git a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go
index 2d49e1d5f..15583e56b 100644
--- a/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go
+++ b/vendor/github.com/uber/jaeger-client-go/thrift-gen/zipkincore/ttypes.go
@@ -729,7 +729,7 @@ func (p *BinaryAnnotation) String() string {
// precise value possible. For example, gettimeofday or syncing nanoTime
// against a tick of currentTimeMillis.
//
-// For compatibilty with instrumentation that precede this field, collectors
+// For compatibility with instrumentation that precede this field, collectors
// or span stores can derive this via Annotation.timestamp.
// For example, SERVER_RECV.timestamp or CLIENT_SEND.timestamp.
//
@@ -741,7 +741,7 @@ func (p *BinaryAnnotation) String() string {
// precise measurement decoupled from problems of clocks, such as skew or NTP
// updates causing time to move backwards.
//
-// For compatibilty with instrumentation that precede this field, collectors
+// For compatibility with instrumentation that precede this field, collectors
// or span stores can derive this by subtracting Annotation.timestamp.
// For example, SERVER_SEND.timestamp - SERVER_RECV.timestamp.
//
diff --git a/vendor/github.com/uber/jaeger-client-go/tracer.go b/vendor/github.com/uber/jaeger-client-go/tracer.go
index f03372dc7..da43ec6db 100644
--- a/vendor/github.com/uber/jaeger-client-go/tracer.go
+++ b/vendor/github.com/uber/jaeger-client-go/tracer.go
@@ -52,6 +52,7 @@ type Tracer struct {
highTraceIDGenerator func() uint64 // custom high trace ID generator
maxTagValueLength int
noDebugFlagOnForcedSampling bool
+ maxLogsPerSpan int
// more options to come
}
// allocator of Span objects
diff --git a/vendor/github.com/uber/jaeger-client-go/tracer_options.go b/vendor/github.com/uber/jaeger-client-go/tracer_options.go
index 469685bb4..f016484b9 100644
--- a/vendor/github.com/uber/jaeger-client-go/tracer_options.go
+++ b/vendor/github.com/uber/jaeger-client-go/tracer_options.go
@@ -144,6 +144,18 @@ func (tracerOptions) MaxTagValueLength(maxTagValueLength int) TracerOption {
}
}
+// MaxLogsPerSpan limits the number of Logs in a span (if set to a nonzero
+// value). If a span has more logs than this value, logs are dropped as
+// necessary (and replaced with a log describing how many were dropped).
+//
+// About half of the MaxLogsPerSpan logs kept are the oldest logs, and about
+// half are the newest logs.
+func (tracerOptions) MaxLogsPerSpan(maxLogsPerSpan int) TracerOption {
+ return func(tracer *Tracer) {
+ tracer.options.maxLogsPerSpan = maxLogsPerSpan
+ }
+}
+
func (tracerOptions) ZipkinSharedRPCSpan(zipkinSharedRPCSpan bool) TracerOption {
return func(tracer *Tracer) {
tracer.options.zipkinSharedRPCSpan = zipkinSharedRPCSpan
diff --git a/vendor/github.com/uber/jaeger-client-go/transport/http.go b/vendor/github.com/uber/jaeger-client-go/transport/http.go
index bc1b3e6b0..bb7eb00c9 100644
--- a/vendor/github.com/uber/jaeger-client-go/transport/http.go
+++ b/vendor/github.com/uber/jaeger-client-go/transport/http.go
@@ -39,6 +39,7 @@ type HTTPTransport struct {
spans []*j.Span
process *j.Process
httpCredentials *HTTPBasicAuthCredentials
+ headers map[string]string
}
// HTTPBasicAuthCredentials stores credentials for HTTP basic auth.
@@ -76,6 +77,13 @@ func HTTPRoundTripper(transport http.RoundTripper) HTTPOption {
}
}
+// HTTPHeaders defines the HTTP headers that will be attached to the jaeger client's HTTP request
+func HTTPHeaders(headers map[string]string) HTTPOption {
+ return func(c *HTTPTransport) {
+ c.headers = headers
+ }
+}
+
// NewHTTPTransport returns a new HTTP-backend transport. url should be an http
// url of the collector to handle POST request, typically something like:
// http://hostname:14268/api/traces?format=jaeger.thrift
@@ -136,6 +144,9 @@ func (c *HTTPTransport) send(spans []*j.Span) error {
return err
}
req.Header.Set("Content-Type", "application/x-thrift")
+ for k, v := range c.headers {
+ req.Header.Set(k, v)
+ }
if c.httpCredentials != nil {
req.SetBasicAuth(c.httpCredentials.username, c.httpCredentials.password)
diff --git a/vendor/github.com/uber/jaeger-client-go/transport_udp.go b/vendor/github.com/uber/jaeger-client-go/transport_udp.go
index 7b9ccf937..7370d8007 100644
--- a/vendor/github.com/uber/jaeger-client-go/transport_udp.go
+++ b/vendor/github.com/uber/jaeger-client-go/transport_udp.go
@@ -18,8 +18,8 @@ import (
"errors"
"fmt"
+ "github.com/uber/jaeger-client-go/internal/reporterstats"
"github.com/uber/jaeger-client-go/thrift"
-
j "github.com/uber/jaeger-client-go/thrift-gen/jaeger"
"github.com/uber/jaeger-client-go/utils"
)
@@ -27,12 +27,14 @@ import (
// Empirically obtained constant for how many bytes in the message are used for envelope.
// The total datagram size is:
// sizeof(Span) * numSpans + processByteSize + emitBatchOverhead <= maxPacketSize
-// There is a unit test `TestEmitBatchOverhead` that validates this number.
+//
// Note that due to the use of Compact Thrift protocol, overhead grows with the number of spans
// in the batch, because the length of the list is encoded as varint32, as well as SeqId.
-const emitBatchOverhead = 30
+//
+// There is a unit test `TestEmitBatchOverhead` that validates this number, it fails at <68.
+const emitBatchOverhead = 70
-var errSpanTooLarge = errors.New("Span is too large")
+var errSpanTooLarge = errors.New("span is too large")
type udpSender struct {
client *utils.AgentClientUDP
@@ -44,9 +46,19 @@ type udpSender struct {
thriftProtocol thrift.TProtocol
process *j.Process
processByteSize int
+
+ // reporterStats provides access to stats that are only known to Reporter
+ reporterStats reporterstats.ReporterStats
+
+ // The following counters are always non-negative, but we need to send them in signed i64 Thrift fields,
+ // so we keep them as signed. At 10k QPS, overflow happens in about 300 million years.
+ batchSeqNo int64
+ tooLargeDroppedSpans int64
+ failedToEmitSpans int64
}
-// NewUDPTransport creates a reporter that submits spans to jaeger-agent
+// NewUDPTransport creates a reporter that submits spans to jaeger-agent.
+// TODO: (breaking change) move to transport/ package.
func NewUDPTransport(hostPort string, maxPacketSize int) (Transport, error) {
if len(hostPort) == 0 {
hostPort = fmt.Sprintf("%s:%d", DefaultUDPSpanServerHost, DefaultUDPSpanServerPort)
@@ -66,17 +78,22 @@ func NewUDPTransport(hostPort string, maxPacketSize int) (Transport, error) {
return nil, err
}
- sender := &udpSender{
+ return &udpSender{
client: client,
maxSpanBytes: maxPacketSize - emitBatchOverhead,
thriftBuffer: thriftBuffer,
- thriftProtocol: thriftProtocol}
- return sender, nil
+ thriftProtocol: thriftProtocol,
+ }, nil
+}
+
+// SetReporterStats implements reporterstats.Receiver.
+func (s *udpSender) SetReporterStats(rs reporterstats.ReporterStats) {
+ s.reporterStats = rs
}
func (s *udpSender) calcSizeOfSerializedThrift(thriftStruct thrift.TStruct) int {
s.thriftBuffer.Reset()
- thriftStruct.Write(s.thriftProtocol)
+ _ = thriftStruct.Write(s.thriftProtocol)
return s.thriftBuffer.Len()
}
@@ -89,6 +106,7 @@ func (s *udpSender) Append(span *Span) (int, error) {
jSpan := BuildJaegerThrift(span)
spanSize := s.calcSizeOfSerializedThrift(jSpan)
if spanSize > s.maxSpanBytes {
+ s.tooLargeDroppedSpans++
return 1, errSpanTooLarge
}
@@ -112,9 +130,18 @@ func (s *udpSender) Flush() (int, error) {
if n == 0 {
return 0, nil
}
- err := s.client.EmitBatch(&j.Batch{Process: s.process, Spans: s.spanBuffer})
+ s.batchSeqNo++
+ batchSeqNo := int64(s.batchSeqNo)
+ err := s.client.EmitBatch(&j.Batch{
+ Process: s.process,
+ Spans: s.spanBuffer,
+ SeqNo: &batchSeqNo,
+ Stats: s.makeStats(),
+ })
s.resetBuffers()
-
+ if err != nil {
+ s.failedToEmitSpans += int64(n)
+ }
return n, err
}
@@ -129,3 +156,15 @@ func (s *udpSender) resetBuffers() {
s.spanBuffer = s.spanBuffer[:0]
s.byteBufferSize = s.processByteSize
}
+
+func (s *udpSender) makeStats() *j.ClientStats {
+ var dropped int64
+ if s.reporterStats != nil {
+ dropped = s.reporterStats.SpansDroppedFromQueue()
+ }
+ return &j.ClientStats{
+ FullQueueDroppedSpans: dropped,
+ TooLargeDroppedSpans: s.tooLargeDroppedSpans,
+ FailedToEmitSpans: s.failedToEmitSpans,
+ }
+}
diff --git a/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go b/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go
index 6f042073d..fadd73e49 100644
--- a/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go
+++ b/vendor/github.com/uber/jaeger-client-go/utils/udp_client.go
@@ -85,7 +85,7 @@ func (a *AgentClientUDP) EmitBatch(batch *jaeger.Batch) error {
return err
}
if a.thriftBuffer.Len() > a.maxPacketSize {
- return fmt.Errorf("Data does not fit within one UDP packet; size %d, max %d, spans %d",
+ return fmt.Errorf("data does not fit within one UDP packet; size %d, max %d, spans %d",
a.thriftBuffer.Len(), a.maxPacketSize, len(batch.Spans))
}
_, err := a.connUDP.Write(a.thriftBuffer.Bytes())
diff --git a/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go
index eb31c4369..73aeb000f 100644
--- a/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go
+++ b/vendor/github.com/uber/jaeger-client-go/zipkin_thrift_span.go
@@ -40,6 +40,7 @@ var specialTagHandlers = map[string]func(*zipkinSpan, interface{}){
}
// BuildZipkinThrift builds thrift span based on internal span.
+// TODO: (breaking change) move to transport/zipkin and make private.
func BuildZipkinThrift(s *Span) *z.Span {
span := &zipkinSpan{Span: s}
span.handleSpecialTags()
diff --git a/vendor/github.com/vishvananda/netlink/.gitignore b/vendor/github.com/vishvananda/netlink/.gitignore
new file mode 100644
index 000000000..9f11b755a
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/.gitignore
@@ -0,0 +1 @@
+.idea/
diff --git a/vendor/github.com/vishvananda/netlink/.travis.yml b/vendor/github.com/vishvananda/netlink/.travis.yml
index f5c0b3eb5..7d14af4d6 100644
--- a/vendor/github.com/vishvananda/netlink/.travis.yml
+++ b/vendor/github.com/vishvananda/netlink/.travis.yml
@@ -1,4 +1,8 @@
language: go
+go:
+ - "1.10.x"
+ - "1.11.x"
+ - "1.12.x"
before_script:
# make sure we keep path in tact when we sudo
- sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers
@@ -9,5 +13,7 @@ before_script:
- sudo modprobe nf_conntrack_netlink
- sudo modprobe nf_conntrack_ipv4
- sudo modprobe nf_conntrack_ipv6
+ - sudo modprobe sch_hfsc
install:
- go get github.com/vishvananda/netns
+go_import_path: github.com/vishvananda/netlink
diff --git a/vendor/github.com/vishvananda/netlink/addr_linux.go b/vendor/github.com/vishvananda/netlink/addr_linux.go
index d59c3281e..28746d5af 100644
--- a/vendor/github.com/vishvananda/netlink/addr_linux.go
+++ b/vendor/github.com/vishvananda/netlink/addr_linux.go
@@ -15,39 +15,62 @@ import (
const IFA_FLAGS = 0x8
// AddrAdd will add an IP address to a link device.
+//
// Equivalent to: `ip addr add $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
func AddrAdd(link Link, addr *Addr) error {
return pkgHandle.AddrAdd(link, addr)
}
// AddrAdd will add an IP address to a link device.
+//
// Equivalent to: `ip addr add $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
func (h *Handle) AddrAdd(link Link, addr *Addr) error {
req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
}
// AddrReplace will replace (or, if not present, add) an IP address on a link device.
+//
// Equivalent to: `ip addr replace $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
func AddrReplace(link Link, addr *Addr) error {
return pkgHandle.AddrReplace(link, addr)
}
// AddrReplace will replace (or, if not present, add) an IP address on a link device.
+//
// Equivalent to: `ip addr replace $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
func (h *Handle) AddrReplace(link Link, addr *Addr) error {
req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
}
// AddrDel will delete an IP address from a link device.
+//
// Equivalent to: `ip addr del $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
func AddrDel(link Link, addr *Addr) error {
return pkgHandle.AddrDel(link, addr)
}
// AddrDel will delete an IP address from a link device.
// Equivalent to: `ip addr del $addr dev $link`
+//
+// If `addr` is an IPv4 address and the broadcast address is not given, it
+// will be automatically computed based on the IP mask if /30 or larger.
func (h *Handle) AddrDel(link Link, addr *Addr) error {
req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK)
return h.addrHandle(link, addr, req)
@@ -65,7 +88,11 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
msg := nl.NewIfAddrmsg(family)
msg.Index = uint32(base.Index)
msg.Scope = uint8(addr.Scope)
- prefixlen, masklen := addr.Mask.Size()
+ mask := addr.Mask
+ if addr.Peer != nil {
+ mask = addr.Peer.Mask
+ }
+ prefixlen, masklen := mask.Size()
msg.Prefixlen = uint8(prefixlen)
req.AddData(msg)
@@ -104,14 +131,20 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error
}
if family == FAMILY_V4 {
- if addr.Broadcast == nil {
+ // Automatically set the broadcast address if it is unset and the
+ // subnet is large enough to sensibly have one (/30 or larger).
+ // See: RFC 3021
+ if addr.Broadcast == nil && prefixlen < 31 {
calcBroadcast := make(net.IP, masklen/8)
for i := range localAddrData {
- calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i]
+ calcBroadcast[i] = localAddrData[i] | ^mask[i]
}
addr.Broadcast = calcBroadcast
}
- req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
+
+ if addr.Broadcast != nil {
+ req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast))
+ }
if addr.Label != "" {
labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label))
@@ -206,13 +239,17 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
IP: attr.Value,
Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
}
- addr.Peer = dst
case unix.IFA_LOCAL:
+ // iproute2 manual:
+ // If a peer address is specified, the local address
+ // cannot have a prefix length. The network prefix is
+ // associated with the peer rather than with the local
+ // address.
+ n := 8 * len(attr.Value)
local = &net.IPNet{
IP: attr.Value,
- Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
+ Mask: net.CIDRMask(n, n),
}
- addr.IPNet = local
case unix.IFA_BROADCAST:
addr.Broadcast = attr.Value
case unix.IFA_LABEL:
@@ -226,12 +263,24 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) {
}
}
- // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
+ // libnl addr.c comment:
+ // IPv6 sends the local address as IFA_ADDRESS with no
+ // IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
+ // with IFA_ADDRESS being the peer address if they differ
+ //
+ // But obviously, as there are IPv6 PtP addresses, too,
+ // IFA_LOCAL should also be handled for IPv6.
if local != nil {
- addr.IPNet = local
+ if family == FAMILY_V4 && local.IP.Equal(dst.IP) {
+ addr.IPNet = dst
+ } else {
+ addr.IPNet = local
+ addr.Peer = dst
+ }
} else {
addr.IPNet = dst
}
+
addr.Scope = int(msg.Scope)
return
@@ -250,21 +299,22 @@ type AddrUpdate struct {
// AddrSubscribe takes a chan down which notifications will be sent
// when addresses change. Close the 'done' chan to stop subscription.
func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
- return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
+ return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0)
}
// AddrSubscribeAt works like AddrSubscribe plus it allows the caller
// to choose the network namespace in which to subscribe (ns).
func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error {
- return addrSubscribeAt(ns, netns.None(), ch, done, nil, false)
+ return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0)
}
// AddrSubscribeOptions contains a set of options to use with
// AddrSubscribeWithOptions.
type AddrSubscribeOptions struct {
- Namespace *netns.NsHandle
- ErrorCallback func(error)
- ListExisting bool
+ Namespace *netns.NsHandle
+ ErrorCallback func(error)
+ ListExisting bool
+ ReceiveBufferSize int
}
// AddrSubscribeWithOptions work like AddrSubscribe but enable to
@@ -275,10 +325,10 @@ func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, option
none := netns.None()
options.Namespace = &none
}
- return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
+ return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize)
}
-func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
+func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int) error {
s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR)
if err != nil {
return err
@@ -289,6 +339,12 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
s.Close()
}()
}
+ if rcvbuf != 0 {
+ err = pkgHandle.SetSocketReceiveBufferSize(rcvbuf, false)
+ if err != nil {
+ return err
+ }
+ }
if listExisting {
req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR,
unix.NLM_F_DUMP)
@@ -301,13 +357,19 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
go func() {
defer close(ch)
for {
- msgs, err := s.Receive()
+ msgs, from, err := s.Receive()
if err != nil {
if cberr != nil {
cberr(err)
}
return
}
+ if from.Pid != nl.PidKernel {
+ if cberr != nil {
+ cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
+ }
+ continue
+ }
for _, m := range msgs {
if m.Header.Type == unix.NLMSG_DONE {
continue
@@ -319,16 +381,17 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
continue
}
if cberr != nil {
- cberr(syscall.Errno(-error))
+ cberr(fmt.Errorf("error message: %v",
+ syscall.Errno(-error)))
}
- return
+ continue
}
msgType := m.Header.Type
if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR {
if cberr != nil {
cberr(fmt.Errorf("bad message type: %d", msgType))
}
- return
+ continue
}
addr, _, ifindex, err := parseAddr(m.Data)
@@ -336,7 +399,7 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c
if cberr != nil {
cberr(fmt.Errorf("could not parse address: %v", err))
}
- return
+ continue
}
ch <- AddrUpdate{LinkAddress: *addr.IPNet,
diff --git a/vendor/github.com/vishvananda/netlink/bridge_linux.go b/vendor/github.com/vishvananda/netlink/bridge_linux.go
index 350ab0db4..6e1224c47 100644
--- a/vendor/github.com/vishvananda/netlink/bridge_linux.go
+++ b/vendor/github.com/vishvananda/netlink/bridge_linux.go
@@ -96,7 +96,7 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged
flags |= nl.BRIDGE_FLAGS_MASTER
}
if flags > 0 {
- nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
+ br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
}
vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
if pvid {
@@ -105,11 +105,8 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged
if untagged {
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
}
- nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
+ br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
req.AddData(br)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
- if err != nil {
- return err
- }
- return nil
+ return err
}
diff --git a/vendor/github.com/vishvananda/netlink/class.go b/vendor/github.com/vishvananda/netlink/class.go
index 8ee13af48..dcc22d9e9 100644
--- a/vendor/github.com/vishvananda/netlink/class.go
+++ b/vendor/github.com/vishvananda/netlink/class.go
@@ -4,25 +4,76 @@ import (
"fmt"
)
+// Class interfaces for all classes
type Class interface {
Attrs() *ClassAttrs
Type() string
}
+// Generic networking statistics for netlink users.
+// This file contains "gnet_" prefixed structs and relevant functions.
+// See Documentation/networking/getn_stats.txt in Linux source code for more details.
+
+// GnetStatsBasic Ref: struct gnet_stats_basic { ... }
+type GnetStatsBasic struct {
+ Bytes uint64 // number of seen bytes
+ Packets uint32 // number of seen packets
+}
+
+// GnetStatsRateEst Ref: struct gnet_stats_rate_est { ... }
+type GnetStatsRateEst struct {
+ Bps uint32 // current byte rate
+ Pps uint32 // current packet rate
+}
+
+// GnetStatsRateEst64 Ref: struct gnet_stats_rate_est64 { ... }
+type GnetStatsRateEst64 struct {
+ Bps uint64 // current byte rate
+ Pps uint64 // current packet rate
+}
+
+// GnetStatsQueue Ref: struct gnet_stats_queue { ... }
+type GnetStatsQueue struct {
+ Qlen uint32 // queue length
+ Backlog uint32 // backlog size of queue
+ Drops uint32 // number of dropped packets
+ Requeues uint32 // number of requues
+ Overlimits uint32 // number of enqueues over the limit
+}
+
+// ClassStatistics representation based on generic networking statistics for netlink.
+// See Documentation/networking/gen_stats.txt in Linux source code for more details.
+type ClassStatistics struct {
+ Basic *GnetStatsBasic
+ Queue *GnetStatsQueue
+ RateEst *GnetStatsRateEst
+}
+
+// NewClassStatistics Construct a ClassStatistics struct which fields are all initialized by 0.
+func NewClassStatistics() *ClassStatistics {
+ return &ClassStatistics{
+ Basic: &GnetStatsBasic{},
+ Queue: &GnetStatsQueue{},
+ RateEst: &GnetStatsRateEst{},
+ }
+}
+
// ClassAttrs represents a netlink class. A filter is associated with a link,
// has a handle and a parent. The root filter of a device should have a
// parent == HANDLE_ROOT.
type ClassAttrs struct {
- LinkIndex int
- Handle uint32
- Parent uint32
- Leaf uint32
+ LinkIndex int
+ Handle uint32
+ Parent uint32
+ Leaf uint32
+ Statistics *ClassStatistics
}
func (q ClassAttrs) String() string {
return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf)
}
+// HtbClassAttrs stores the attributes of HTB class
type HtbClassAttrs struct {
// TODO handle all attributes
Rate uint64
@@ -54,10 +105,12 @@ func (q HtbClass) String() string {
return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer)
}
+// Attrs returns the class attributes
func (q *HtbClass) Attrs() *ClassAttrs {
return &q.ClassAttrs
}
+// Type return the class type
func (q *HtbClass) Type() string {
return "htb"
}
@@ -69,10 +122,90 @@ type GenericClass struct {
ClassType string
}
+// Attrs return the class attributes
func (class *GenericClass) Attrs() *ClassAttrs {
return &class.ClassAttrs
}
+// Type return the class type
func (class *GenericClass) Type() string {
return class.ClassType
}
+
+// ServiceCurve is the way the HFSC curve are represented
+type ServiceCurve struct {
+ m1 uint32
+ d uint32
+ m2 uint32
+}
+
+// Attrs return the parameters of the service curve
+func (c *ServiceCurve) Attrs() (uint32, uint32, uint32) {
+ return c.m1, c.d, c.m2
+}
+
+// HfscClass is a representation of the HFSC class
+type HfscClass struct {
+ ClassAttrs
+ Rsc ServiceCurve
+ Fsc ServiceCurve
+ Usc ServiceCurve
+}
+
+// SetUsc sets the Usc curve
+func (hfsc *HfscClass) SetUsc(m1 uint32, d uint32, m2 uint32) {
+ hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetFsc sets the Fsc curve
+func (hfsc *HfscClass) SetFsc(m1 uint32, d uint32, m2 uint32) {
+ hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetRsc sets the Rsc curve
+func (hfsc *HfscClass) SetRsc(m1 uint32, d uint32, m2 uint32) {
+ hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetSC implements the SC from the tc CLI
+func (hfsc *HfscClass) SetSC(m1 uint32, d uint32, m2 uint32) {
+ hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+ hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetUL implements the UL from the tc CLI
+func (hfsc *HfscClass) SetUL(m1 uint32, d uint32, m2 uint32) {
+ hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// SetLS implements the LS from the tc CLI
+func (hfsc *HfscClass) SetLS(m1 uint32, d uint32, m2 uint32) {
+ hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8}
+}
+
+// NewHfscClass returns a new HFSC struct with the set parameters
+func NewHfscClass(attrs ClassAttrs) *HfscClass {
+ return &HfscClass{
+ ClassAttrs: attrs,
+ Rsc: ServiceCurve{},
+ Fsc: ServiceCurve{},
+ Usc: ServiceCurve{},
+ }
+}
+
+func (hfsc *HfscClass) String() string {
+ return fmt.Sprintf(
+ "{%s -- {RSC: {m1=%d d=%d m2=%d}} {FSC: {m1=%d d=%d m2=%d}} {USC: {m1=%d d=%d m2=%d}}}",
+ hfsc.Attrs(), hfsc.Rsc.m1*8, hfsc.Rsc.d, hfsc.Rsc.m2*8, hfsc.Fsc.m1*8, hfsc.Fsc.d, hfsc.Fsc.m2*8, hfsc.Usc.m1*8, hfsc.Usc.d, hfsc.Usc.m2*8,
+ )
+}
+
+// Attrs return the Hfsc parameters
+func (hfsc *HfscClass) Attrs() *ClassAttrs {
+ return &hfsc.ClassAttrs
+}
+
+// Type return the type of the class
+func (hfsc *HfscClass) Type() string {
+ return "hfsc"
+}
diff --git a/vendor/github.com/vishvananda/netlink/class_linux.go b/vendor/github.com/vishvananda/netlink/class_linux.go
index a4997740e..31091e501 100644
--- a/vendor/github.com/vishvananda/netlink/class_linux.go
+++ b/vendor/github.com/vishvananda/netlink/class_linux.go
@@ -1,14 +1,34 @@
package netlink
import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
"errors"
+ "fmt"
"syscall"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
-// NOTE: function is in here because it uses other linux functions
+// Internal tc_stats representation in Go struct.
+// This is for internal uses only to deserialize the payload of rtattr.
+// After the deserialization, this should be converted into the canonical stats
+// struct, ClassStatistics, in case of statistics of a class.
+// Ref: struct tc_stats { ... }
+type tcStats struct {
+ Bytes uint64 // Number of enqueued bytes
+ Packets uint32 // Number of enqueued packets
+ Drops uint32 // Packets dropped because of lack of resources
+ Overlimits uint32 // Number of throttle events when this flow goes out of allocated bandwidth
+ Bps uint32 // Current flow byte rate
+ Pps uint32 // Current flow packet rate
+ Qlen uint32
+ Backlog uint32
+}
+
+// NewHtbClass NOTE: function is in here because it uses other linux functions
func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
mtu := 1600
rate := cattrs.Rate / 8
@@ -126,7 +146,9 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(class.Type())))
options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
- if htb, ok := class.(*HtbClass); ok {
+ switch class.Type() {
+ case "htb":
+ htb := class.(*HtbClass)
opt := nl.TcHtbCopt{}
opt.Buffer = htb.Buffer
opt.Cbuffer = htb.Cbuffer
@@ -151,9 +173,18 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
return errors.New("HTB: failed to calculate ceil rate table")
}
opt.Ceil = tcceil
- nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize())
- nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab))
- nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab))
+ options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize())
+ options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab))
+ options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab))
+ case "hfsc":
+ hfsc := class.(*HfscClass)
+ opt := nl.HfscCopt{}
+ opt.Rsc.Set(hfsc.Rsc.Attrs())
+ opt.Fsc.Set(hfsc.Fsc.Attrs())
+ opt.Usc.Set(hfsc.Usc.Attrs())
+ options.AddRtAttr(nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc))
+ options.AddRtAttr(nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc))
+ options.AddRtAttr(nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc))
}
req.AddData(options)
return nil
@@ -197,9 +228,10 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
}
base := ClassAttrs{
- LinkIndex: int(msg.Ifindex),
- Handle: msg.Handle,
- Parent: msg.Parent,
+ LinkIndex: int(msg.Ifindex),
+ Handle: msg.Handle,
+ Parent: msg.Parent,
+ Statistics: nil,
}
var class Class
@@ -211,6 +243,8 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
switch classType {
case "htb":
class = &HtbClass{}
+ case "hfsc":
+ class = &HfscClass{}
default:
class = &GenericClass{ClassType: classType}
}
@@ -225,6 +259,26 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
if err != nil {
return nil, err
}
+ case "hfsc":
+ data, err := nl.ParseRouteAttr(attr.Value)
+ if err != nil {
+ return nil, err
+ }
+ _, err = parseHfscClassData(class, data)
+ if err != nil {
+ return nil, err
+ }
+ }
+ // For backward compatibility.
+ case nl.TCA_STATS:
+ base.Statistics, err = parseTcStats(attr.Value)
+ if err != nil {
+ return nil, err
+ }
+ case nl.TCA_STATS2:
+ base.Statistics, err = parseTcStats2(attr.Value)
+ if err != nil {
+ return nil, err
}
}
}
@@ -253,3 +307,78 @@ func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, erro
}
return detailed, nil
}
+
+func parseHfscClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) {
+ hfsc := class.(*HfscClass)
+ detailed := false
+ for _, datum := range data {
+ m1, d, m2 := nl.DeserializeHfscCurve(datum.Value).Attrs()
+ switch datum.Attr.Type {
+ case nl.TCA_HFSC_RSC:
+ hfsc.Rsc = ServiceCurve{m1: m1, d: d, m2: m2}
+ case nl.TCA_HFSC_FSC:
+ hfsc.Fsc = ServiceCurve{m1: m1, d: d, m2: m2}
+ case nl.TCA_HFSC_USC:
+ hfsc.Usc = ServiceCurve{m1: m1, d: d, m2: m2}
+ }
+ }
+ return detailed, nil
+}
+
+func parseTcStats(data []byte) (*ClassStatistics, error) {
+ buf := &bytes.Buffer{}
+ buf.Write(data)
+ native := nl.NativeEndian()
+ tcStats := &tcStats{}
+ if err := binary.Read(buf, native, tcStats); err != nil {
+ return nil, err
+ }
+
+ stats := NewClassStatistics()
+ stats.Basic.Bytes = tcStats.Bytes
+ stats.Basic.Packets = tcStats.Packets
+ stats.Queue.Qlen = tcStats.Qlen
+ stats.Queue.Backlog = tcStats.Backlog
+ stats.Queue.Drops = tcStats.Drops
+ stats.Queue.Overlimits = tcStats.Overlimits
+ stats.RateEst.Bps = tcStats.Bps
+ stats.RateEst.Pps = tcStats.Pps
+
+ return stats, nil
+}
+
+func parseGnetStats(data []byte, gnetStats interface{}) error {
+ buf := &bytes.Buffer{}
+ buf.Write(data)
+ native := nl.NativeEndian()
+ return binary.Read(buf, native, gnetStats)
+}
+
+func parseTcStats2(data []byte) (*ClassStatistics, error) {
+ rtAttrs, err := nl.ParseRouteAttr(data)
+ if err != nil {
+ return nil, err
+ }
+ stats := NewClassStatistics()
+ for _, datum := range rtAttrs {
+ switch datum.Attr.Type {
+ case nl.TCA_STATS_BASIC:
+ if err := parseGnetStats(datum.Value, stats.Basic); err != nil {
+ return nil, fmt.Errorf("Failed to parse ClassStatistics.Basic with: %v\n%s",
+ err, hex.Dump(datum.Value))
+ }
+ case nl.TCA_STATS_QUEUE:
+ if err := parseGnetStats(datum.Value, stats.Queue); err != nil {
+ return nil, fmt.Errorf("Failed to parse ClassStatistics.Queue with: %v\n%s",
+ err, hex.Dump(datum.Value))
+ }
+ case nl.TCA_STATS_RATE_EST:
+ if err := parseGnetStats(datum.Value, stats.RateEst); err != nil {
+ return nil, fmt.Errorf("Failed to parse ClassStatistics.RateEst with: %v\n%s",
+ err, hex.Dump(datum.Value))
+ }
+ }
+ }
+
+ return stats, nil
+}
diff --git a/vendor/github.com/vishvananda/netlink/conntrack_linux.go b/vendor/github.com/vishvananda/netlink/conntrack_linux.go
index a0fc74a37..4bff0dcba 100644
--- a/vendor/github.com/vishvananda/netlink/conntrack_linux.go
+++ b/vendor/github.com/vishvananda/netlink/conntrack_linux.go
@@ -22,11 +22,7 @@ const (
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK_EXP 2
ConntrackExpectTable = 2
)
-const (
- // For Parsing Mark
- TCP_PROTO = 6
- UDP_PROTO = 17
-)
+
const (
// backward compatibility with golang 1.6 which does not have io.SeekCurrent
seekCurrent = 1
@@ -135,11 +131,13 @@ func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily)
// http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h
// For the time being, the structure below allows to parse and extract the base information of a flow
type ipTuple struct {
- SrcIP net.IP
+ Bytes uint64
DstIP net.IP
+ DstPort uint16
+ Packets uint64
Protocol uint8
+ SrcIP net.IP
SrcPort uint16
- DstPort uint16
}
type ConntrackFlow struct {
@@ -151,11 +149,12 @@ type ConntrackFlow struct {
func (s *ConntrackFlow) String() string {
// conntrack cmd output:
- // udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 mark=0
- return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d\tsrc=%s dst=%s sport=%d dport=%d mark=%d",
+ // udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0
+ return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=%d",
nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol,
- s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort,
- s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Mark)
+ s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes,
+ s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes,
+ s.Mark)
}
// This method parse the ip tuple structure
@@ -220,9 +219,35 @@ func parseBERaw16(r *bytes.Reader, v *uint16) {
binary.Read(r, binary.BigEndian, v)
}
+func parseBERaw32(r *bytes.Reader, v *uint32) {
+ binary.Read(r, binary.BigEndian, v)
+}
+
+func parseBERaw64(r *bytes.Reader, v *uint64) {
+ binary.Read(r, binary.BigEndian, v)
+}
+
+func parseByteAndPacketCounters(r *bytes.Reader) (bytes, packets uint64) {
+ for i := 0; i < 2; i++ {
+ switch _, t, _ := parseNfAttrTL(r); t {
+ case nl.CTA_COUNTERS_BYTES:
+ parseBERaw64(r, &bytes)
+ case nl.CTA_COUNTERS_PACKETS:
+ parseBERaw64(r, &packets)
+ default:
+ return
+ }
+ }
+ return
+}
+
+func parseConnectionMark(r *bytes.Reader) (mark uint32) {
+ parseBERaw32(r, &mark)
+ return
+}
+
func parseRawData(data []byte) *ConntrackFlow {
s := &ConntrackFlow{}
- var proto uint8
// First there is the Nfgenmsg header
// consume only the family field
reader := bytes.NewReader(data)
@@ -238,36 +263,31 @@ func parseRawData(data []byte) *ConntrackFlow {
// <len, NLA_F_NESTED|CTA_TUPLE_IP> 4 bytes
// flow information of the reverse flow
for reader.Len() > 0 {
- nested, t, l := parseNfAttrTL(reader)
- if nested && t == nl.CTA_TUPLE_ORIG {
- if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
- proto = parseIpTuple(reader, &s.Forward)
+ if nested, t, l := parseNfAttrTL(reader); nested {
+ switch t {
+ case nl.CTA_TUPLE_ORIG:
+ if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
+ parseIpTuple(reader, &s.Forward)
+ }
+ case nl.CTA_TUPLE_REPLY:
+ if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
+ parseIpTuple(reader, &s.Reverse)
+ } else {
+ // Header not recognized skip it
+ reader.Seek(int64(l), seekCurrent)
+ }
+ case nl.CTA_COUNTERS_ORIG:
+ s.Forward.Bytes, s.Forward.Packets = parseByteAndPacketCounters(reader)
+ case nl.CTA_COUNTERS_REPLY:
+ s.Reverse.Bytes, s.Reverse.Packets = parseByteAndPacketCounters(reader)
}
- } else if nested && t == nl.CTA_TUPLE_REPLY {
- if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP {
- parseIpTuple(reader, &s.Reverse)
-
- // Got all the useful information stop parsing
- break
- } else {
- // Header not recognized skip it
- reader.Seek(int64(l), seekCurrent)
+ } else {
+ switch t {
+ case nl.CTA_MARK:
+ s.Mark = parseConnectionMark(reader)
}
}
}
- if proto == TCP_PROTO {
- reader.Seek(64, seekCurrent)
- _, t, _, v := parseNfAttrTLV(reader)
- if t == nl.CTA_MARK {
- s.Mark = uint32(v[3])
- }
- } else if proto == UDP_PROTO {
- reader.Seek(16, seekCurrent)
- _, t, _, v := parseNfAttrTLV(reader)
- if t == nl.CTA_MARK {
- s.Mark = uint32(v[3])
- }
- }
return s
}
@@ -285,7 +305,7 @@ func parseRawData(data []byte) *ConntrackFlow {
// Common parameters and options:
// -s, --src, --orig-src ip Source address from original direction
// -d, --dst, --orig-dst ip Destination address from original direction
-// -r, --reply-src ip Source addres from reply direction
+// -r, --reply-src ip Source address from reply direction
// -q, --reply-dst ip Destination address from reply direction
// -p, --protonum proto Layer 4 Protocol, eg. 'tcp'
// -f, --family proto Layer 3 Protocol, eg. 'ipv6'
@@ -302,11 +322,14 @@ func parseRawData(data []byte) *ConntrackFlow {
type ConntrackFilterType uint8
const (
- ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction
- ConntrackOrigDstIP // -orig-dst ip Destination address from original direction
- ConntrackNatSrcIP // -src-nat ip Source NAT ip
- ConntrackNatDstIP // -dst-nat ip Destination NAT ip
- ConntrackNatAnyIP // -any-nat ip Source or destination NAT ip
+ ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction
+ ConntrackOrigDstIP // -orig-dst ip Destination address from original direction
+ ConntrackReplySrcIP // --reply-src ip Reply Source IP
+ ConntrackReplyDstIP // --reply-dst ip Reply Destination IP
+ ConntrackReplyAnyIP // Match source or destination reply IP
+ ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP
+ ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP
+ ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instaed ConntrackReplyAnyIP
)
type CustomConntrackFilter interface {
@@ -351,17 +374,17 @@ func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool {
}
// -src-nat ip Source NAT ip
- if elem, found := f.ipFilter[ConntrackNatSrcIP]; match && found {
+ if elem, found := f.ipFilter[ConntrackReplySrcIP]; match && found {
match = match && elem.Equal(flow.Reverse.SrcIP)
}
// -dst-nat ip Destination NAT ip
- if elem, found := f.ipFilter[ConntrackNatDstIP]; match && found {
+ if elem, found := f.ipFilter[ConntrackReplyDstIP]; match && found {
match = match && elem.Equal(flow.Reverse.DstIP)
}
- // -any-nat ip Source or destination NAT ip
- if elem, found := f.ipFilter[ConntrackNatAnyIP]; match && found {
+ // Match source or destination reply IP
+ if elem, found := f.ipFilter[ConntrackReplyAnyIP]; match && found {
match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP))
}
diff --git a/vendor/github.com/vishvananda/netlink/devlink_linux.go b/vendor/github.com/vishvananda/netlink/devlink_linux.go
new file mode 100644
index 000000000..29b3f8ec1
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/devlink_linux.go
@@ -0,0 +1,272 @@
+package netlink
+
+import (
+ "syscall"
+
+ "fmt"
+ "github.com/vishvananda/netlink/nl"
+ "golang.org/x/sys/unix"
+)
+
+// DevlinkDevEswitchAttr represents device's eswitch attributes
+type DevlinkDevEswitchAttr struct {
+ Mode string
+ InlineMode string
+ EncapMode string
+}
+
+// DevlinkDevAttrs represents device attributes
+type DevlinkDevAttrs struct {
+ Eswitch DevlinkDevEswitchAttr
+}
+
+// DevlinkDevice represents device and its attributes
+type DevlinkDevice struct {
+ BusName string
+ DeviceName string
+ Attrs DevlinkDevAttrs
+}
+
+func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) {
+ devices := make([]*DevlinkDevice, 0, len(msgs))
+ for _, m := range msgs {
+ attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
+ if err != nil {
+ return nil, err
+ }
+ dev := &DevlinkDevice{}
+ if err = dev.parseAttributes(attrs); err != nil {
+ return nil, err
+ }
+ devices = append(devices, dev)
+ }
+ return devices, nil
+}
+
+func eswitchStringToMode(modeName string) (uint16, error) {
+ if modeName == "legacy" {
+ return nl.DEVLINK_ESWITCH_MODE_LEGACY, nil
+ } else if modeName == "switchdev" {
+ return nl.DEVLINK_ESWITCH_MODE_SWITCHDEV, nil
+ } else {
+ return 0xffff, fmt.Errorf("invalid switchdev mode")
+ }
+}
+
+func parseEswitchMode(mode uint16) string {
+ var eswitchMode = map[uint16]string{
+ nl.DEVLINK_ESWITCH_MODE_LEGACY: "legacy",
+ nl.DEVLINK_ESWITCH_MODE_SWITCHDEV: "switchdev",
+ }
+ if eswitchMode[mode] == "" {
+ return "unknown"
+ } else {
+ return eswitchMode[mode]
+ }
+}
+
+func parseEswitchInlineMode(inlinemode uint8) string {
+ var eswitchInlineMode = map[uint8]string{
+ nl.DEVLINK_ESWITCH_INLINE_MODE_NONE: "none",
+ nl.DEVLINK_ESWITCH_INLINE_MODE_LINK: "link",
+ nl.DEVLINK_ESWITCH_INLINE_MODE_NETWORK: "network",
+ nl.DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: "transport",
+ }
+ if eswitchInlineMode[inlinemode] == "" {
+ return "unknown"
+ } else {
+ return eswitchInlineMode[inlinemode]
+ }
+}
+
+func parseEswitchEncapMode(encapmode uint8) string {
+ var eswitchEncapMode = map[uint8]string{
+ nl.DEVLINK_ESWITCH_ENCAP_MODE_NONE: "disable",
+ nl.DEVLINK_ESWITCH_ENCAP_MODE_BASIC: "enable",
+ }
+ if eswitchEncapMode[encapmode] == "" {
+ return "unknown"
+ } else {
+ return eswitchEncapMode[encapmode]
+ }
+}
+
+func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error {
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case nl.DEVLINK_ATTR_BUS_NAME:
+ d.BusName = string(a.Value)
+ case nl.DEVLINK_ATTR_DEV_NAME:
+ d.DeviceName = string(a.Value)
+ case nl.DEVLINK_ATTR_ESWITCH_MODE:
+ d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value))
+ case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE:
+ d.Attrs.Eswitch.InlineMode = parseEswitchInlineMode(uint8(a.Value[0]))
+ case nl.DEVLINK_ATTR_ESWITCH_ENCAP_MODE:
+ d.Attrs.Eswitch.EncapMode = parseEswitchEncapMode(uint8(a.Value[0]))
+ }
+ }
+ return nil
+}
+
+func (dev *DevlinkDevice) parseEswitchAttrs(msgs [][]byte) {
+ m := msgs[0]
+ attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
+ if err != nil {
+ return
+ }
+ dev.parseAttributes(attrs)
+}
+
+func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) {
+ msg := &nl.Genlmsg{
+ Command: nl.DEVLINK_CMD_ESWITCH_GET,
+ Version: nl.GENL_DEVLINK_VERSION,
+ }
+ req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK)
+ req.AddData(msg)
+
+ b := make([]byte, len(dev.BusName))
+ copy(b, dev.BusName)
+ data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
+ req.AddData(data)
+
+ b = make([]byte, len(dev.DeviceName))
+ copy(b, dev.DeviceName)
+ data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
+ req.AddData(data)
+
+ msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
+ if err != nil {
+ return
+ }
+ dev.parseEswitchAttrs(msgs)
+}
+
+// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
+// otherwise returns an error code.
+func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
+ f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
+ if err != nil {
+ return nil, err
+ }
+ msg := &nl.Genlmsg{
+ Command: nl.DEVLINK_CMD_GET,
+ Version: nl.GENL_DEVLINK_VERSION,
+ }
+ req := h.newNetlinkRequest(int(f.ID),
+ unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP)
+ req.AddData(msg)
+ msgs, err := req.Execute(unix.NETLINK_GENERIC, 0)
+ if err != nil {
+ return nil, err
+ }
+ devices, err := parseDevLinkDeviceList(msgs)
+ if err != nil {
+ return nil, err
+ }
+ for _, d := range devices {
+ h.getEswitchAttrs(f, d)
+ }
+ return devices, nil
+}
+
+// DevLinkGetDeviceList provides a pointer to devlink devices and nil error,
+// otherwise returns an error code.
+func DevLinkGetDeviceList() ([]*DevlinkDevice, error) {
+ return pkgHandle.DevLinkGetDeviceList()
+}
+
+func parseDevlinkDevice(msgs [][]byte) (*DevlinkDevice, error) {
+ m := msgs[0]
+ attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:])
+ if err != nil {
+ return nil, err
+ }
+ dev := &DevlinkDevice{}
+ if err = dev.parseAttributes(attrs); err != nil {
+ return nil, err
+ }
+ return dev, nil
+}
+
+func (h *Handle) createCmdReq(cmd uint8, bus string, device string) (*GenlFamily, *nl.NetlinkRequest, error) {
+ f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ msg := &nl.Genlmsg{
+ Command: cmd,
+ Version: nl.GENL_DEVLINK_VERSION,
+ }
+ req := h.newNetlinkRequest(int(f.ID),
+ unix.NLM_F_REQUEST|unix.NLM_F_ACK)
+ req.AddData(msg)
+
+ b := make([]byte, len(bus)+1)
+ copy(b, bus)
+ data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b)
+ req.AddData(data)
+
+ b = make([]byte, len(device)+1)
+ copy(b, device)
+ data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b)
+ req.AddData(data)
+
+ return f, req, nil
+}
+
+// DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
+// otherwise returns an error code.
+func (h *Handle) DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
+ f, req, err := h.createCmdReq(nl.DEVLINK_CMD_GET, Bus, Device)
+ if err != nil {
+ return nil, err
+ }
+
+ respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0)
+ if err != nil {
+ return nil, err
+ }
+ dev, err := parseDevlinkDevice(respmsg)
+ if err == nil {
+ h.getEswitchAttrs(f, dev)
+ }
+ return dev, err
+}
+
+// DevlinkGetDeviceByName provides a pointer to devlink device and nil error,
+// otherwise returns an error code.
+func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) {
+ return pkgHandle.DevLinkGetDeviceByName(Bus, Device)
+}
+
+// DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
+// returns an error code.
+// Equivalent to: `devlink dev eswitch set $dev mode switchdev`
+// Equivalent to: `devlink dev eswitch set $dev mode legacy`
+func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
+ mode, err := eswitchStringToMode(NewMode)
+ if err != nil {
+ return err
+ }
+
+ _, req, err := h.createCmdReq(nl.DEVLINK_CMD_ESWITCH_SET, Dev.BusName, Dev.DeviceName)
+ if err != nil {
+ return err
+ }
+
+ req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_ESWITCH_MODE, nl.Uint16Attr(mode)))
+
+ _, err = req.Execute(unix.NETLINK_GENERIC, 0)
+ return err
+}
+
+// DevLinkSetEswitchMode sets eswitch mode if able to set successfully or
+// returns an error code.
+// Equivalent to: `devlink dev eswitch set $dev mode switchdev`
+// Equivalent to: `devlink dev eswitch set $dev mode legacy`
+func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error {
+ return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode)
+}
diff --git a/vendor/github.com/vishvananda/netlink/filter.go b/vendor/github.com/vishvananda/netlink/filter.go
index c2cf8e4dc..88792eab0 100644
--- a/vendor/github.com/vishvananda/netlink/filter.go
+++ b/vendor/github.com/vishvananda/netlink/filter.go
@@ -2,6 +2,7 @@ package netlink
import (
"fmt"
+ "net"
)
type Filter interface {
@@ -135,6 +136,27 @@ func (action *BpfAction) Attrs() *ActionAttrs {
return &action.ActionAttrs
}
+type ConnmarkAction struct {
+ ActionAttrs
+ Zone uint16
+}
+
+func (action *ConnmarkAction) Type() string {
+ return "connmark"
+}
+
+func (action *ConnmarkAction) Attrs() *ActionAttrs {
+ return &action.ActionAttrs
+}
+
+func NewConnmarkAction() *ConnmarkAction {
+ return &ConnmarkAction{
+ ActionAttrs: ActionAttrs{
+ Action: TC_ACT_PIPE,
+ },
+ }
+}
+
type MirredAct uint8
func (a MirredAct) String() string {
@@ -182,47 +204,59 @@ func NewMirredAction(redirIndex int) *MirredAction {
}
}
-// Sel of the U32 filters that contains multiple TcU32Key. This is the copy
-// and the frontend representation of nl.TcU32Sel. It is serialized into canonical
-// nl.TcU32Sel with the appropriate endianness.
-type TcU32Sel struct {
- Flags uint8
- Offshift uint8
- Nkeys uint8
- Pad uint8
- Offmask uint16
- Off uint16
- Offoff int16
- Hoff int16
- Hmask uint32
- Keys []TcU32Key
-}
-
-// TcU32Key contained of Sel in the U32 filters. This is the copy and the frontend
-// representation of nl.TcU32Key. It is serialized into chanonical nl.TcU32Sel
-// with the appropriate endianness.
-type TcU32Key struct {
- Mask uint32
- Val uint32
- Off int32
- OffMask int32
-}
-
-// U32 filters on many packet related properties
-type U32 struct {
- FilterAttrs
- ClassId uint32
- RedirIndex int
- Sel *TcU32Sel
- Actions []Action
+type TunnelKeyAct int8
+
+const (
+ TCA_TUNNEL_KEY_SET TunnelKeyAct = 1 // set tunnel key
+ TCA_TUNNEL_KEY_UNSET TunnelKeyAct = 2 // unset tunnel key
+)
+
+type TunnelKeyAction struct {
+ ActionAttrs
+ Action TunnelKeyAct
+ SrcAddr net.IP
+ DstAddr net.IP
+ KeyID uint32
}
-func (filter *U32) Attrs() *FilterAttrs {
- return &filter.FilterAttrs
+func (action *TunnelKeyAction) Type() string {
+ return "tunnel_key"
}
-func (filter *U32) Type() string {
- return "u32"
+func (action *TunnelKeyAction) Attrs() *ActionAttrs {
+ return &action.ActionAttrs
+}
+
+func NewTunnelKeyAction() *TunnelKeyAction {
+ return &TunnelKeyAction{
+ ActionAttrs: ActionAttrs{
+ Action: TC_ACT_PIPE,
+ },
+ }
+}
+
+type SkbEditAction struct {
+ ActionAttrs
+ QueueMapping *uint16
+ PType *uint16
+ Priority *uint32
+ Mark *uint32
+}
+
+func (action *SkbEditAction) Type() string {
+ return "skbedit"
+}
+
+func (action *SkbEditAction) Attrs() *ActionAttrs {
+ return &action.ActionAttrs
+}
+
+func NewSkbEditAction() *SkbEditAction {
+ return &SkbEditAction{
+ ActionAttrs: ActionAttrs{
+ Action: TC_ACT_PIPE,
+ },
+ }
}
// MatchAll filters match all packets
@@ -262,6 +296,8 @@ type BpfFilter struct {
Fd int
Name string
DirectAction bool
+ Id int
+ Tag string
}
func (filter *BpfFilter) Type() string {
diff --git a/vendor/github.com/vishvananda/netlink/filter_linux.go b/vendor/github.com/vishvananda/netlink/filter_linux.go
index f0eac6b78..c56f314cd 100644
--- a/vendor/github.com/vishvananda/netlink/filter_linux.go
+++ b/vendor/github.com/vishvananda/netlink/filter_linux.go
@@ -3,10 +3,11 @@ package netlink
import (
"bytes"
"encoding/binary"
+ "encoding/hex"
"errors"
"fmt"
+ "net"
"syscall"
- "unsafe"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
@@ -20,6 +21,35 @@ const (
TC_U32_EAT = nl.TC_U32_EAT
)
+// Sel of the U32 filters that contains multiple TcU32Key. This is the type
+// alias and the frontend representation of nl.TcU32Sel. It is serialized into
+// canonical nl.TcU32Sel with the appropriate endianness.
+type TcU32Sel = nl.TcU32Sel
+
+// TcU32Key contained of Sel in the U32 filters. This is the type alias and the
+// frontend representation of nl.TcU32Key. It is serialized into chanonical
+// nl.TcU32Sel with the appropriate endianness.
+type TcU32Key = nl.TcU32Key
+
+// U32 filters on many packet related properties
+type U32 struct {
+ FilterAttrs
+ ClassId uint32
+ Divisor uint32 // Divisor MUST be power of 2.
+ Hash uint32
+ RedirIndex int
+ Sel *TcU32Sel
+ Actions []Action
+}
+
+func (filter *U32) Attrs() *FilterAttrs {
+ return &filter.FilterAttrs
+}
+
+func (filter *U32) Type() string {
+ return "u32"
+}
+
// Fw filter filters on firewall marks
// NOTE: this is in filter_linux because it refers to nl.TcPolice which
// is defined in nl/tc_linux.go
@@ -123,8 +153,24 @@ func FilterAdd(filter Filter) error {
// FilterAdd will add a filter to the system.
// Equivalent to: `tc filter add $filter`
func (h *Handle) FilterAdd(filter Filter) error {
+ return h.filterModify(filter, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
+}
+
+// FilterReplace will replace a filter.
+// Equivalent to: `tc filter replace $filter`
+func FilterReplace(filter Filter) error {
+ return pkgHandle.FilterReplace(filter)
+}
+
+// FilterReplace will replace a filter.
+// Equivalent to: `tc filter replace $filter`
+func (h *Handle) FilterReplace(filter Filter) error {
+ return h.filterModify(filter, unix.NLM_F_CREATE)
+}
+
+func (h *Handle) filterModify(filter Filter, flags int) error {
native = nl.NativeEndian()
- req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
+ req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, flags|unix.NLM_F_ACK)
base := filter.Attrs()
msg := &nl.TcMsg{
Family: nl.FAMILY_ALL,
@@ -140,8 +186,7 @@ func (h *Handle) FilterAdd(filter Filter) error {
switch filter := filter.(type) {
case *U32:
- // Convert TcU32Sel into nl.TcU32Sel as it is without copy.
- sel := (*nl.TcU32Sel)(unsafe.Pointer(filter.Sel))
+ sel := filter.Sel
if sel == nil {
// match all
sel = &nl.TcU32Sel{
@@ -168,11 +213,20 @@ func (h *Handle) FilterAdd(filter Filter) error {
}
}
sel.Nkeys = uint8(len(sel.Keys))
- nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
+ options.AddRtAttr(nl.TCA_U32_SEL, sel.Serialize())
if filter.ClassId != 0 {
- nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId))
+ options.AddRtAttr(nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId))
+ }
+ if filter.Divisor != 0 {
+ if (filter.Divisor-1)&filter.Divisor != 0 {
+ return fmt.Errorf("illegal divisor %d. Must be a power of 2", filter.Divisor)
+ }
+ options.AddRtAttr(nl.TCA_U32_DIVISOR, nl.Uint32Attr(filter.Divisor))
}
- actionsAttr := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
+ if filter.Hash != 0 {
+ options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash))
+ }
+ actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil)
// backwards compatibility
if filter.RedirIndex != 0 {
filter.Actions = append([]Action{NewMirredAction(filter.RedirIndex)}, filter.Actions...)
@@ -184,51 +238,51 @@ func (h *Handle) FilterAdd(filter Filter) error {
if filter.Mask != 0 {
b := make([]byte, 4)
native.PutUint32(b, filter.Mask)
- nl.NewRtAttrChild(options, nl.TCA_FW_MASK, b)
+ options.AddRtAttr(nl.TCA_FW_MASK, b)
}
if filter.InDev != "" {
- nl.NewRtAttrChild(options, nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev))
+ options.AddRtAttr(nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev))
}
if (filter.Police != nl.TcPolice{}) {
- police := nl.NewRtAttrChild(options, nl.TCA_FW_POLICE, nil)
- nl.NewRtAttrChild(police, nl.TCA_POLICE_TBF, filter.Police.Serialize())
+ police := options.AddRtAttr(nl.TCA_FW_POLICE, nil)
+ police.AddRtAttr(nl.TCA_POLICE_TBF, filter.Police.Serialize())
if (filter.Police.Rate != nl.TcRateSpec{}) {
payload := SerializeRtab(filter.Rtab)
- nl.NewRtAttrChild(police, nl.TCA_POLICE_RATE, payload)
+ police.AddRtAttr(nl.TCA_POLICE_RATE, payload)
}
if (filter.Police.PeakRate != nl.TcRateSpec{}) {
payload := SerializeRtab(filter.Ptab)
- nl.NewRtAttrChild(police, nl.TCA_POLICE_PEAKRATE, payload)
+ police.AddRtAttr(nl.TCA_POLICE_PEAKRATE, payload)
}
}
if filter.ClassId != 0 {
b := make([]byte, 4)
native.PutUint32(b, filter.ClassId)
- nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b)
+ options.AddRtAttr(nl.TCA_FW_CLASSID, b)
}
case *BpfFilter:
var bpfFlags uint32
if filter.ClassId != 0 {
- nl.NewRtAttrChild(options, nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId))
+ options.AddRtAttr(nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId))
}
if filter.Fd >= 0 {
- nl.NewRtAttrChild(options, nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd))))
+ options.AddRtAttr(nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd))))
}
if filter.Name != "" {
- nl.NewRtAttrChild(options, nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name))
+ options.AddRtAttr(nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name))
}
if filter.DirectAction {
bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT
}
- nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
+ options.AddRtAttr(nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
case *MatchAll:
- actionsAttr := nl.NewRtAttrChild(options, nl.TCA_MATCHALL_ACT, nil)
+ actionsAttr := options.AddRtAttr(nl.TCA_MATCHALL_ACT, nil)
if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
return err
}
if filter.ClassId != 0 {
- nl.NewRtAttrChild(options, nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
+ options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
}
}
@@ -366,34 +420,91 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error {
default:
return fmt.Errorf("unknown action type %s", action.Type())
case *MirredAction:
- table := nl.NewRtAttrChild(attr, tabIndex, nil)
+ table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
- nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
- aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
+ table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
+ aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
mirred := nl.TcMirred{
Eaction: int32(action.MirredAction),
Ifindex: uint32(action.Ifindex),
}
toTcGen(action.Attrs(), &mirred.TcGen)
- nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mirred.Serialize())
+ aopts.AddRtAttr(nl.TCA_MIRRED_PARMS, mirred.Serialize())
+ case *TunnelKeyAction:
+ table := attr.AddRtAttr(tabIndex, nil)
+ tabIndex++
+ table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("tunnel_key"))
+ aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
+ tun := nl.TcTunnelKey{
+ Action: int32(action.Action),
+ }
+ toTcGen(action.Attrs(), &tun.TcGen)
+ aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_PARMS, tun.Serialize())
+ if action.Action == TCA_TUNNEL_KEY_SET {
+ aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_KEY_ID, htonl(action.KeyID))
+ if v4 := action.SrcAddr.To4(); v4 != nil {
+ aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC, v4[:])
+ } else if v6 := action.SrcAddr.To16(); v6 != nil {
+ aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC, v6[:])
+ } else {
+ return fmt.Errorf("invalid src addr %s for tunnel_key action", action.SrcAddr)
+ }
+ if v4 := action.DstAddr.To4(); v4 != nil {
+ aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_DST, v4[:])
+ } else if v6 := action.DstAddr.To16(); v6 != nil {
+ aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_DST, v6[:])
+ } else {
+ return fmt.Errorf("invalid dst addr %s for tunnel_key action", action.DstAddr)
+ }
+ }
+ case *SkbEditAction:
+ table := attr.AddRtAttr(tabIndex, nil)
+ tabIndex++
+ table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("skbedit"))
+ aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
+ skbedit := nl.TcSkbEdit{}
+ toTcGen(action.Attrs(), &skbedit.TcGen)
+ aopts.AddRtAttr(nl.TCA_SKBEDIT_PARMS, skbedit.Serialize())
+ if action.QueueMapping != nil {
+ aopts.AddRtAttr(nl.TCA_SKBEDIT_QUEUE_MAPPING, nl.Uint16Attr(*action.QueueMapping))
+ }
+ if action.Priority != nil {
+ aopts.AddRtAttr(nl.TCA_SKBEDIT_PRIORITY, nl.Uint32Attr(*action.Priority))
+ }
+ if action.PType != nil {
+ aopts.AddRtAttr(nl.TCA_SKBEDIT_PTYPE, nl.Uint16Attr(*action.PType))
+ }
+ if action.Mark != nil {
+ aopts.AddRtAttr(nl.TCA_SKBEDIT_MARK, nl.Uint32Attr(*action.Mark))
+ }
+ case *ConnmarkAction:
+ table := attr.AddRtAttr(tabIndex, nil)
+ tabIndex++
+ table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("connmark"))
+ aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
+ connmark := nl.TcConnmark{
+ Zone: action.Zone,
+ }
+ toTcGen(action.Attrs(), &connmark.TcGen)
+ aopts.AddRtAttr(nl.TCA_CONNMARK_PARMS, connmark.Serialize())
case *BpfAction:
- table := nl.NewRtAttrChild(attr, tabIndex, nil)
+ table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
- nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
- aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
+ table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
+ aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
gen := nl.TcGen{}
toTcGen(action.Attrs(), &gen)
- nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_PARMS, gen.Serialize())
- nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
- nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
+ aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize())
+ aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
+ aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
case *GenericAction:
- table := nl.NewRtAttrChild(attr, tabIndex, nil)
+ table := attr.AddRtAttr(tabIndex, nil)
tabIndex++
- nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("gact"))
- aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
+ table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("gact"))
+ aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
gen := nl.TcGen{}
toTcGen(action.Attrs(), &gen)
- nl.NewRtAttrChild(aopts, nl.TCA_GACT_PARMS, gen.Serialize())
+ aopts.AddRtAttr(nl.TCA_GACT_PARMS, gen.Serialize())
}
}
return nil
@@ -419,8 +530,14 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
action = &MirredAction{}
case "bpf":
action = &BpfAction{}
+ case "connmark":
+ action = &ConnmarkAction{}
case "gact":
action = &GenericAction{}
+ case "tunnel_key":
+ action = &TunnelKeyAction{}
+ case "skbedit":
+ action = &SkbEditAction{}
default:
break nextattr
}
@@ -435,11 +552,46 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
switch adatum.Attr.Type {
case nl.TCA_MIRRED_PARMS:
mirred := *nl.DeserializeTcMirred(adatum.Value)
- toAttrs(&mirred.TcGen, action.Attrs())
action.(*MirredAction).ActionAttrs = ActionAttrs{}
+ toAttrs(&mirred.TcGen, action.Attrs())
action.(*MirredAction).Ifindex = int(mirred.Ifindex)
action.(*MirredAction).MirredAction = MirredAct(mirred.Eaction)
}
+ case "tunnel_key":
+ switch adatum.Attr.Type {
+ case nl.TCA_TUNNEL_KEY_PARMS:
+ tun := *nl.DeserializeTunnelKey(adatum.Value)
+ action.(*TunnelKeyAction).ActionAttrs = ActionAttrs{}
+ toAttrs(&tun.TcGen, action.Attrs())
+ action.(*TunnelKeyAction).Action = TunnelKeyAct(tun.Action)
+ case nl.TCA_TUNNEL_KEY_ENC_KEY_ID:
+ action.(*TunnelKeyAction).KeyID = networkOrder.Uint32(adatum.Value[0:4])
+ case nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC:
+ case nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC:
+ action.(*TunnelKeyAction).SrcAddr = net.IP(adatum.Value[:])
+ case nl.TCA_TUNNEL_KEY_ENC_IPV6_DST:
+ case nl.TCA_TUNNEL_KEY_ENC_IPV4_DST:
+ action.(*TunnelKeyAction).DstAddr = net.IP(adatum.Value[:])
+ }
+ case "skbedit":
+ switch adatum.Attr.Type {
+ case nl.TCA_SKBEDIT_PARMS:
+ skbedit := *nl.DeserializeSkbEdit(adatum.Value)
+ action.(*SkbEditAction).ActionAttrs = ActionAttrs{}
+ toAttrs(&skbedit.TcGen, action.Attrs())
+ case nl.TCA_SKBEDIT_MARK:
+ mark := native.Uint32(adatum.Value[0:4])
+ action.(*SkbEditAction).Mark = &mark
+ case nl.TCA_SKBEDIT_PRIORITY:
+ priority := native.Uint32(adatum.Value[0:4])
+ action.(*SkbEditAction).Priority = &priority
+ case nl.TCA_SKBEDIT_PTYPE:
+ ptype := native.Uint16(adatum.Value[0:2])
+ action.(*SkbEditAction).PType = &ptype
+ case nl.TCA_SKBEDIT_QUEUE_MAPPING:
+ mapping := native.Uint16(adatum.Value[0:2])
+ action.(*SkbEditAction).QueueMapping = &mapping
+ }
case "bpf":
switch adatum.Attr.Type {
case nl.TCA_ACT_BPF_PARMS:
@@ -450,6 +602,14 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
case nl.TCA_ACT_BPF_NAME:
action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1])
}
+ case "connmark":
+ switch adatum.Attr.Type {
+ case nl.TCA_CONNMARK_PARMS:
+ connmark := *nl.DeserializeTcConnmark(adatum.Value)
+ action.(*ConnmarkAction).ActionAttrs = ActionAttrs{}
+ toAttrs(&connmark.TcGen, action.Attrs())
+ action.(*ConnmarkAction).Zone = connmark.Zone
+ }
case "gact":
switch adatum.Attr.Type {
case nl.TCA_GACT_PARMS:
@@ -474,7 +634,7 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
case nl.TCA_U32_SEL:
detailed = true
sel := nl.DeserializeTcU32Sel(datum.Value)
- u32.Sel = (*TcU32Sel)(unsafe.Pointer(sel))
+ u32.Sel = sel
if native != networkOrder {
// Handle the endianness of attributes
u32.Sel.Offmask = native.Uint16(htons(sel.Offmask))
@@ -500,6 +660,10 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
}
case nl.TCA_U32_CLASSID:
u32.ClassId = native.Uint32(datum.Value)
+ case nl.TCA_U32_DIVISOR:
+ u32.Divisor = native.Uint32(datum.Value)
+ case nl.TCA_U32_HASH:
+ u32.Hash = native.Uint32(datum.Value)
}
}
return detailed, nil
@@ -551,6 +715,10 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 {
bpf.DirectAction = true
}
+ case nl.TCA_BPF_ID:
+ bpf.Id = int(native.Uint32(datum.Value[0:4]))
+ case nl.TCA_BPF_TAG:
+ bpf.Tag = hex.EncodeToString(datum.Value[:len(datum.Value)-1])
}
}
return detailed, nil
diff --git a/vendor/github.com/vishvananda/netlink/fou_linux.go b/vendor/github.com/vishvananda/netlink/fou_linux.go
index 62d59bd2d..ed55b2b79 100644
--- a/vendor/github.com/vishvananda/netlink/fou_linux.go
+++ b/vendor/github.com/vishvananda/netlink/fou_linux.go
@@ -90,11 +90,7 @@ func (h *Handle) FouAdd(f Fou) error {
req.AddRawData(raw)
_, err = req.Execute(unix.NETLINK_GENERIC, 0)
- if err != nil {
- return err
- }
-
- return nil
+ return err
}
func FouDel(f Fou) error {
diff --git a/vendor/github.com/vishvananda/netlink/genetlink_linux.go b/vendor/github.com/vishvananda/netlink/genetlink_linux.go
index ce7969907..772e5834a 100644
--- a/vendor/github.com/vishvananda/netlink/genetlink_linux.go
+++ b/vendor/github.com/vishvananda/netlink/genetlink_linux.go
@@ -157,6 +157,9 @@ func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) {
return nil, err
}
families, err := parseFamilies(msgs)
+ if err != nil {
+ return nil, err
+ }
if len(families) != 1 {
return nil, fmt.Errorf("invalid response for GENL_CTRL_CMD_GETFAMILY")
}
diff --git a/vendor/github.com/vishvananda/netlink/go.mod b/vendor/github.com/vishvananda/netlink/go.mod
new file mode 100644
index 000000000..09ee60e77
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/go.mod
@@ -0,0 +1,8 @@
+module github.com/vishvananda/netlink
+
+go 1.12
+
+require (
+ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
+ golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444
+)
diff --git a/vendor/github.com/vishvananda/netlink/go.sum b/vendor/github.com/vishvananda/netlink/go.sum
new file mode 100644
index 000000000..402d14ec5
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/go.sum
@@ -0,0 +1,4 @@
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444 h1:/d2cWp6PSamH4jDPFLyO150psQdqvtoNX8Zjg3AQ31g=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/vishvananda/netlink/handle_linux.go b/vendor/github.com/vishvananda/netlink/handle_linux.go
index 9f6d7fe0f..26887b759 100644
--- a/vendor/github.com/vishvananda/netlink/handle_linux.go
+++ b/vendor/github.com/vishvananda/netlink/handle_linux.go
@@ -91,7 +91,7 @@ func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) {
return results, nil
}
-// NewHandle returns a netlink handle on the network namespace
+// NewHandleAt returns a netlink handle on the network namespace
// specified by ns. If ns=netns.None(), current network namespace
// will be assumed
func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error) {
diff --git a/vendor/github.com/vishvananda/netlink/handle_unspecified.go b/vendor/github.com/vishvananda/netlink/handle_unspecified.go
index 915b765de..ef914dcb8 100644
--- a/vendor/github.com/vishvananda/netlink/handle_unspecified.go
+++ b/vendor/github.com/vishvananda/netlink/handle_unspecified.go
@@ -73,10 +73,18 @@ func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
return ErrNotImplemented
}
+func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
+ return ErrNotImplemented
+}
+
func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
return ErrNotImplemented
}
+func (h *Handle) LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
+ return ErrNotImplemented
+}
+
func (h *Handle) LinkSetMaster(link Link, master *Bridge) error {
return ErrNotImplemented
}
@@ -149,6 +157,10 @@ func (h *Handle) LinkSetTxQLen(link Link, qlen int) error {
return ErrNotImplemented
}
+func (h *Handle) LinkSetGroup(link Link, group int) error {
+ return ErrNotImplemented
+}
+
func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
return ErrNotImplemented
}
diff --git a/vendor/github.com/vishvananda/netlink/ioctl_linux.go b/vendor/github.com/vishvananda/netlink/ioctl_linux.go
index a8503126d..4d33db5da 100644
--- a/vendor/github.com/vishvananda/netlink/ioctl_linux.go
+++ b/vendor/github.com/vishvananda/netlink/ioctl_linux.go
@@ -56,18 +56,10 @@ type ethtoolSset struct {
data [1]uint32
}
-// ethtoolGstrings is string set for data tagging
-type ethtoolGstrings struct {
- cmd uint32
- stringSet uint32
- length uint32
- data [32]byte
-}
-
type ethtoolStats struct {
cmd uint32
nStats uint32
- data [1]uint64
+ // Followed by nStats * []uint64.
}
// newIocltSlaveReq returns filled IfreqSlave with proper interface names
diff --git a/vendor/github.com/vishvananda/netlink/link.go b/vendor/github.com/vishvananda/netlink/link.go
index fe74ffab9..886d88d1b 100644
--- a/vendor/github.com/vishvananda/netlink/link.go
+++ b/vendor/github.com/vishvananda/netlink/link.go
@@ -4,6 +4,7 @@ import (
"fmt"
"net"
"os"
+ "strconv"
)
// Link represents a link device from netlink. Shared link attributes
@@ -41,6 +42,29 @@ type LinkAttrs struct {
NetNsID int
NumTxQueues int
NumRxQueues int
+ GSOMaxSize uint32
+ GSOMaxSegs uint32
+ Vfs []VfInfo // virtual functions available on link
+ Group uint32
+ Slave LinkSlave
+}
+
+// LinkSlave represents a slave device.
+type LinkSlave interface {
+ SlaveType() string
+}
+
+// VfInfo represents configuration of virtual function
+type VfInfo struct {
+ ID int
+ Mac net.HardwareAddr
+ Vlan int
+ Qos int
+ TxRate int // IFLA_VF_TX_RATE Max TxRate
+ Spoofchk bool
+ LinkState uint32
+ MaxTxRate uint32 // IFLA_VF_RATE Max TxRate
+ MinTxRate uint32 // IFLA_VF_RATE Min TxRate
}
// LinkOperState represents the values of the IFLA_OPERSTATE link
@@ -223,6 +247,7 @@ type Bridge struct {
LinkAttrs
MulticastSnooping *bool
HelloTime *uint32
+ VlanFiltering *bool
}
func (bridge *Bridge) Attrs() *LinkAttrs {
@@ -236,7 +261,8 @@ func (bridge *Bridge) Type() string {
// Vlan links have ParentIndex set in their Attrs()
type Vlan struct {
LinkAttrs
- VlanId int
+ VlanId int
+ VlanProtocol VlanProtocol
}
func (vlan *Vlan) Attrs() *LinkAttrs {
@@ -290,10 +316,13 @@ type TuntapFlag uint16
// Tuntap links created via /dev/tun/tap, but can be destroyed via netlink
type Tuntap struct {
LinkAttrs
- Mode TuntapMode
- Flags TuntapFlag
- Queues int
- Fds []*os.File
+ Mode TuntapMode
+ Flags TuntapFlag
+ NonPersist bool
+ Queues int
+ Fds []*os.File
+ Owner uint32
+ Group uint32
}
func (tuntap *Tuntap) Attrs() *LinkAttrs {
@@ -307,7 +336,8 @@ func (tuntap *Tuntap) Type() string {
// Veth devices must specify PeerName on create
type Veth struct {
LinkAttrs
- PeerName string // veth on create only
+ PeerName string // veth on create only
+ PeerHardwareAddr net.HardwareAddr
}
func (veth *Veth) Attrs() *LinkAttrs {
@@ -376,9 +406,18 @@ const (
IPVLAN_MODE_MAX
)
+type IPVlanFlag uint16
+
+const (
+ IPVLAN_FLAG_BRIDGE IPVlanFlag = iota
+ IPVLAN_FLAG_PRIVATE
+ IPVLAN_FLAG_VEPA
+)
+
type IPVlan struct {
LinkAttrs
Mode IPVlanMode
+ Flag IPVlanFlag
}
func (ipvlan *IPVlan) Attrs() *LinkAttrs {
@@ -389,6 +428,43 @@ func (ipvlan *IPVlan) Type() string {
return "ipvlan"
}
+// VlanProtocol type
+type VlanProtocol int
+
+func (p VlanProtocol) String() string {
+ s, ok := VlanProtocolToString[p]
+ if !ok {
+ return fmt.Sprintf("VlanProtocol(%d)", p)
+ }
+ return s
+}
+
+// StringToVlanProtocol returns vlan protocol, or unknown is the s is invalid.
+func StringToVlanProtocol(s string) VlanProtocol {
+ mode, ok := StringToVlanProtocolMap[s]
+ if !ok {
+ return VLAN_PROTOCOL_UNKNOWN
+ }
+ return mode
+}
+
+// VlanProtocol possible values
+const (
+ VLAN_PROTOCOL_UNKNOWN VlanProtocol = 0
+ VLAN_PROTOCOL_8021Q VlanProtocol = 0x8100
+ VLAN_PROTOCOL_8021AD VlanProtocol = 0x88A8
+)
+
+var VlanProtocolToString = map[VlanProtocol]string{
+ VLAN_PROTOCOL_8021Q: "802.1q",
+ VLAN_PROTOCOL_8021AD: "802.1ad",
+}
+
+var StringToVlanProtocolMap = map[string]VlanProtocol{
+ "802.1q": VLAN_PROTOCOL_8021Q,
+ "802.1ad": VLAN_PROTOCOL_8021AD,
+}
+
// BondMode type
type BondMode int
@@ -400,7 +476,7 @@ func (b BondMode) String() string {
return s
}
-// StringToBondMode returns bond mode, or uknonw is the s is invalid.
+// StringToBondMode returns bond mode, or unknown is the s is invalid.
func StringToBondMode(s string) BondMode {
mode, ok := StringToBondModeMap[s]
if !ok {
@@ -491,7 +567,7 @@ func (b BondXmitHashPolicy) String() string {
return s
}
-// StringToBondXmitHashPolicy returns bond lacp arte, or uknonw is the s is invalid.
+// StringToBondXmitHashPolicy returns bond lacp arte, or unknown is the s is invalid.
func StringToBondXmitHashPolicy(s string) BondXmitHashPolicy {
lacp, ok := StringToBondXmitHashPolicyMap[s]
if !ok {
@@ -536,7 +612,7 @@ func (b BondLacpRate) String() string {
return s
}
-// StringToBondLacpRate returns bond lacp arte, or uknonw is the s is invalid.
+// StringToBondLacpRate returns bond lacp arte, or unknown is the s is invalid.
func StringToBondLacpRate(s string) BondLacpRate {
lacp, ok := StringToBondLacpRateMap[s]
if !ok {
@@ -680,6 +756,67 @@ func (bond *Bond) Type() string {
return "bond"
}
+// BondSlaveState represents the values of the IFLA_BOND_SLAVE_STATE bond slave
+// attribute, which contains the state of the bond slave.
+type BondSlaveState uint8
+
+const (
+ BondStateActive = iota // Link is active.
+ BondStateBackup // Link is backup.
+)
+
+func (s BondSlaveState) String() string {
+ switch s {
+ case BondStateActive:
+ return "ACTIVE"
+ case BondStateBackup:
+ return "BACKUP"
+ default:
+ return strconv.Itoa(int(s))
+ }
+}
+
+// BondSlaveState represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave
+// attribute, which contains the status of MII link monitoring
+type BondSlaveMiiStatus uint8
+
+const (
+ BondLinkUp = iota // link is up and running.
+ BondLinkFail // link has just gone down.
+ BondLinkDown // link has been down for too long time.
+ BondLinkBack // link is going back.
+)
+
+func (s BondSlaveMiiStatus) String() string {
+ switch s {
+ case BondLinkUp:
+ return "UP"
+ case BondLinkFail:
+ return "GOING_DOWN"
+ case BondLinkDown:
+ return "DOWN"
+ case BondLinkBack:
+ return "GOING_BACK"
+ default:
+ return strconv.Itoa(int(s))
+ }
+}
+
+type BondSlave struct {
+ State BondSlaveState
+ MiiStatus BondSlaveMiiStatus
+ LinkFailureCount uint32
+ PermHardwareAddr net.HardwareAddr
+ QueueId uint16
+ AggregatorId uint16
+ AdActorOperPortState uint8
+ AdPartnerOperPortState uint16
+}
+
+func (b *BondSlave) SlaveType() string {
+ return "bond"
+}
+
// Gretap devices must specify LocalIP and RemoteIP on create
type Gretap struct {
LinkAttrs
@@ -734,6 +871,27 @@ func (iptun *Iptun) Type() string {
return "ipip"
}
+type Ip6tnl struct {
+ LinkAttrs
+ Link uint32
+ Local net.IP
+ Remote net.IP
+ Ttl uint8
+ Tos uint8
+ EncapLimit uint8
+ Flags uint32
+ Proto uint8
+ FlowInfo uint32
+}
+
+func (ip6tnl *Ip6tnl) Attrs() *LinkAttrs {
+ return &ip6tnl.LinkAttrs
+}
+
+func (ip6tnl *Ip6tnl) Type() string {
+ return "ip6tnl"
+}
+
type Sittun struct {
LinkAttrs
Link uint32
@@ -769,7 +927,10 @@ func (vti *Vti) Attrs() *LinkAttrs {
return &vti.LinkAttrs
}
-func (iptun *Vti) Type() string {
+func (vti *Vti) Type() string {
+ if vti.Local.To4() == nil {
+ return "vti6"
+ }
return "vti"
}
@@ -831,11 +992,68 @@ func (gtp *GTP) Type() string {
return "gtp"
}
+// Virtual XFRM Interfaces
+// Named "xfrmi" to prevent confusion with XFRM objects
+type Xfrmi struct {
+ LinkAttrs
+ Ifid uint32
+}
+
+func (xfrm *Xfrmi) Attrs() *LinkAttrs {
+ return &xfrm.LinkAttrs
+}
+
+func (xfrm *Xfrmi) Type() string {
+ return "xfrm"
+}
+
+// IPoIB interface
+
+type IPoIBMode uint16
+
+func (m *IPoIBMode) String() string {
+ str, ok := iPoIBModeToString[*m]
+ if !ok {
+ return fmt.Sprintf("mode(%d)", *m)
+ }
+ return str
+}
+
+const (
+ IPOIB_MODE_DATAGRAM = iota
+ IPOIB_MODE_CONNECTED
+)
+
+var iPoIBModeToString = map[IPoIBMode]string{
+ IPOIB_MODE_DATAGRAM: "datagram",
+ IPOIB_MODE_CONNECTED: "connected",
+}
+
+var StringToIPoIBMode = map[string]IPoIBMode{
+ "datagram": IPOIB_MODE_DATAGRAM,
+ "connected": IPOIB_MODE_CONNECTED,
+}
+
+type IPoIB struct {
+ LinkAttrs
+ Pkey uint16
+ Mode IPoIBMode
+ Umcast uint16
+}
+
+func (ipoib *IPoIB) Attrs() *LinkAttrs {
+ return &ipoib.LinkAttrs
+}
+
+func (ipoib *IPoIB) Type() string {
+ return "ipoib"
+}
+
// iproute2 supported devices;
// vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
-// gre | gretap | ip6gre | ip6gretap | vti | nlmon |
-// bond_slave | ipvlan
+// gre | gretap | ip6gre | ip6gretap | vti | vti6 | nlmon |
+// bond_slave | ipvlan | xfrm
// LinkNotFoundError wraps the various not found errors when
// getting/reading links. This is intended for better error
diff --git a/vendor/github.com/vishvananda/netlink/link_linux.go b/vendor/github.com/vishvananda/netlink/link_linux.go
index 540191ed8..ec915a0b9 100644
--- a/vendor/github.com/vishvananda/netlink/link_linux.go
+++ b/vendor/github.com/vishvananda/netlink/link_linux.go
@@ -4,8 +4,11 @@ import (
"bytes"
"encoding/binary"
"fmt"
+ "io/ioutil"
"net"
"os"
+ "strconv"
+ "strings"
"syscall"
"unsafe"
@@ -16,7 +19,7 @@ import (
const (
SizeofLinkStats32 = 0x5c
- SizeofLinkStats64 = 0xd8
+ SizeofLinkStats64 = 0xb8
)
const (
@@ -31,6 +34,12 @@ const (
TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI
)
+const (
+ VF_LINK_STATE_AUTO uint32 = 0
+ VF_LINK_STATE_ENABLE uint32 = 1
+ VF_LINK_STATE_DISABLE uint32 = 2
+)
+
var lookupByDump = false
var macvlanModes = [...]uint32{
@@ -113,6 +122,52 @@ func (h *Handle) SetPromiscOn(link Link) error {
return err
}
+// LinkSetAllmulticastOn enables the reception of all hardware multicast packets for the link device.
+// Equivalent to: `ip link set $link allmulticast on`
+func LinkSetAllmulticastOn(link Link) error {
+ return pkgHandle.LinkSetAllmulticastOn(link)
+}
+
+// LinkSetAllmulticastOn enables the reception of all hardware multicast packets for the link device.
+// Equivalent to: `ip link set $link allmulticast on`
+func (h *Handle) LinkSetAllmulticastOn(link Link) error {
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Change = unix.IFF_ALLMULTI
+ msg.Flags = unix.IFF_ALLMULTI
+
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
+// LinkSetAllmulticastOff disables the reception of all hardware multicast packets for the link device.
+// Equivalent to: `ip link set $link allmulticast off`
+func LinkSetAllmulticastOff(link Link) error {
+ return pkgHandle.LinkSetAllmulticastOff(link)
+}
+
+// LinkSetAllmulticastOff disables the reception of all hardware multicast packets for the link device.
+// Equivalent to: `ip link set $link allmulticast off`
+func (h *Handle) LinkSetAllmulticastOff(link Link) error {
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Change = unix.IFF_ALLMULTI
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
func MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error {
return pkgHandle.MacvlanMACAddrAdd(link, addr)
}
@@ -155,24 +210,24 @@ func (h *Handle) macvlanMACAddrChange(link Link, addrs []net.HardwareAddr, mode
req.AddData(msg)
linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
- nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
- inner := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
+ inner := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
// IFLA_MACVLAN_MACADDR_MODE = mode
b := make([]byte, 4)
native.PutUint32(b, mode)
- nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR_MODE, b)
+ inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR_MODE, b)
// populate message with MAC addrs, if necessary
switch mode {
case nl.MACVLAN_MACADDR_ADD, nl.MACVLAN_MACADDR_DEL:
if len(addrs) == 1 {
- nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR, []byte(addrs[0]))
+ inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR, []byte(addrs[0]))
}
case nl.MACVLAN_MACADDR_SET:
- mad := nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR_DATA, nil)
+ mad := inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR_DATA, nil)
for _, addr := range addrs {
- nl.NewRtAttrChild(mad, nl.IFLA_MACVLAN_MACADDR, []byte(addr))
+ mad.AddRtAttr(nl.IFLA_MACVLAN_MACADDR, []byte(addr))
}
}
@@ -203,7 +258,6 @@ func (h *Handle) SetPromiscOff(link Link) error {
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Change = unix.IFF_PROMISC
- msg.Flags = 0 & ^unix.IFF_PROMISC
msg.Index = int32(base.Index)
req.AddData(msg)
@@ -253,7 +307,6 @@ func (h *Handle) LinkSetDown(link Link) error {
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Change = unix.IFF_UP
- msg.Flags = 0 & ^unix.IFF_UP
msg.Index = int32(base.Index)
req.AddData(msg)
@@ -378,12 +431,12 @@ func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAdd
req.AddData(msg)
data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
- info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
+ info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfMac{
Vf: uint32(vf),
}
copy(vfmsg.Mac[:], []byte(hwaddr))
- nl.NewRtAttrChild(info, nl.IFLA_VF_MAC, vfmsg.Serialize())
+ info.AddRtAttr(nl.IFLA_VF_MAC, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
@@ -408,10 +461,41 @@ func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
req.AddData(msg)
data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
+ info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
+ vfmsg := nl.VfVlan{
+ Vf: uint32(vf),
+ Vlan: uint32(vlan),
+ }
+ info.AddRtAttr(nl.IFLA_VF_VLAN, vfmsg.Serialize())
+ req.AddData(data)
+
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
+// LinkSetVfVlanQos sets the vlan and qos priority of a vf for the link.
+// Equivalent to: `ip link set $link vf $vf vlan $vlan qos $qos`
+func LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
+ return pkgHandle.LinkSetVfVlanQos(link, vf, vlan, qos)
+}
+
+// LinkSetVfVlanQos sets the vlan and qos priority of a vf for the link.
+// Equivalent to: `ip link set $link vf $vf vlan $vlan qos $qos`
+func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfVlan{
Vf: uint32(vf),
Vlan: uint32(vlan),
+ Qos: uint32(qos),
}
nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize())
req.AddData(data)
@@ -438,12 +522,73 @@ func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error {
req.AddData(msg)
data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
- info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
+ info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
vfmsg := nl.VfTxRate{
Vf: uint32(vf),
Rate: uint32(rate),
}
- nl.NewRtAttrChild(info, nl.IFLA_VF_TX_RATE, vfmsg.Serialize())
+ info.AddRtAttr(nl.IFLA_VF_TX_RATE, vfmsg.Serialize())
+ req.AddData(data)
+
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
+// LinkSetVfRate sets the min and max tx rate of a vf for the link.
+// Equivalent to: `ip link set $link vf $vf min_tx_rate $min_rate max_tx_rate $max_rate`
+func LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
+ return pkgHandle.LinkSetVfRate(link, vf, minRate, maxRate)
+}
+
+// LinkSetVfRate sets the min and max tx rate of a vf for the link.
+// Equivalent to: `ip link set $link vf $vf min_tx_rate $min_rate max_tx_rate $max_rate`
+func (h *Handle) LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
+ info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
+ vfmsg := nl.VfRate{
+ Vf: uint32(vf),
+ MinTxRate: uint32(minRate),
+ MaxTxRate: uint32(maxRate),
+ }
+ info.AddRtAttr(nl.IFLA_VF_RATE, vfmsg.Serialize())
+ req.AddData(data)
+
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
+// LinkSetVfState enables/disables virtual link state on a vf.
+// Equivalent to: `ip link set $link vf $vf state $state`
+func LinkSetVfState(link Link, vf int, state uint32) error {
+ return pkgHandle.LinkSetVfState(link, vf, state)
+}
+
+// LinkSetVfState enables/disables virtual link state on a vf.
+// Equivalent to: `ip link set $link vf $vf state $state`
+func (h *Handle) LinkSetVfState(link Link, vf int, state uint32) error {
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
+ info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
+ vfmsg := nl.VfLinkState{
+ Vf: uint32(vf),
+ LinkState: state,
+ }
+ info.AddRtAttr(nl.IFLA_VF_LINK_STATE, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
@@ -456,7 +601,7 @@ func LinkSetVfSpoofchk(link Link, vf int, check bool) error {
return pkgHandle.LinkSetVfSpoofchk(link, vf, check)
}
-// LinkSetVfSpookfchk enables/disables spoof check on a vf for the link.
+// LinkSetVfSpoofchk enables/disables spoof check on a vf for the link.
// Equivalent to: `ip link set $link vf $vf spoofchk $check`
func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error {
var setting uint32
@@ -469,7 +614,7 @@ func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error {
req.AddData(msg)
data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
- info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
+ info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
if check {
setting = 1
}
@@ -477,7 +622,7 @@ func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error {
Vf: uint32(vf),
Setting: setting,
}
- nl.NewRtAttrChild(info, nl.IFLA_VF_SPOOFCHK, vfmsg.Serialize())
+ info.AddRtAttr(nl.IFLA_VF_SPOOFCHK, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
@@ -503,7 +648,7 @@ func (h *Handle) LinkSetVfTrust(link Link, vf int, state bool) error {
req.AddData(msg)
data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
- info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
+ info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
if state {
setting = 1
}
@@ -511,22 +656,66 @@ func (h *Handle) LinkSetVfTrust(link Link, vf int, state bool) error {
Vf: uint32(vf),
Setting: setting,
}
- nl.NewRtAttrChild(info, nl.IFLA_VF_TRUST, vfmsg.Serialize())
+ info.AddRtAttr(nl.IFLA_VF_TRUST, vfmsg.Serialize())
req.AddData(data)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
+// LinkSetVfNodeGUID sets the node GUID of a vf for the link.
+// Equivalent to: `ip link set dev $link vf $vf node_guid $nodeguid`
+func LinkSetVfNodeGUID(link Link, vf int, nodeguid net.HardwareAddr) error {
+ return pkgHandle.LinkSetVfGUID(link, vf, nodeguid, nl.IFLA_VF_IB_NODE_GUID)
+}
+
+// LinkSetVfPortGUID sets the port GUID of a vf for the link.
+// Equivalent to: `ip link set dev $link vf $vf port_guid $portguid`
+func LinkSetVfPortGUID(link Link, vf int, portguid net.HardwareAddr) error {
+ return pkgHandle.LinkSetVfGUID(link, vf, portguid, nl.IFLA_VF_IB_PORT_GUID)
+}
+
+// LinkSetVfGUID sets the node or port GUID of a vf for the link.
+func (h *Handle) LinkSetVfGUID(link Link, vf int, vfGuid net.HardwareAddr, guidType int) error {
+ var err error
+ var guid uint64
+
+ buf := bytes.NewBuffer(vfGuid)
+ err = binary.Read(buf, binary.BigEndian, &guid)
+ if err != nil {
+ return err
+ }
+
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil)
+ info := data.AddRtAttr(nl.IFLA_VF_INFO, nil)
+ vfmsg := nl.VfGUID{
+ Vf: uint32(vf),
+ GUID: guid,
+ }
+ info.AddRtAttr(guidType, vfmsg.Serialize())
+ req.AddData(data)
+
+ _, err = req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
// LinkSetMaster sets the master of the link device.
// Equivalent to: `ip link set $link master $master`
-func LinkSetMaster(link Link, master *Bridge) error {
+func LinkSetMaster(link Link, master Link) error {
return pkgHandle.LinkSetMaster(link, master)
}
// LinkSetMaster sets the master of the link device.
// Equivalent to: `ip link set $link master $master`
-func (h *Handle) LinkSetMaster(link Link, master *Bridge) error {
+func (h *Handle) LinkSetMaster(link Link, master Link) error {
index := 0
if master != nil {
masterBase := master.Attrs()
@@ -672,69 +861,69 @@ type vxlanPortRange struct {
}
func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
if vxlan.FlowBased {
vxlan.VxlanId = 0
}
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId)))
+ data.AddRtAttr(nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId)))
if vxlan.VtepDevIndex != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex)))
+ data.AddRtAttr(nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex)))
}
if vxlan.SrcAddr != nil {
ip := vxlan.SrcAddr.To4()
if ip != nil {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL, []byte(ip))
+ data.AddRtAttr(nl.IFLA_VXLAN_LOCAL, []byte(ip))
} else {
ip = vxlan.SrcAddr.To16()
if ip != nil {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL6, []byte(ip))
+ data.AddRtAttr(nl.IFLA_VXLAN_LOCAL6, []byte(ip))
}
}
}
if vxlan.Group != nil {
group := vxlan.Group.To4()
if group != nil {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP, []byte(group))
+ data.AddRtAttr(nl.IFLA_VXLAN_GROUP, []byte(group))
} else {
group = vxlan.Group.To16()
if group != nil {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP6, []byte(group))
+ data.AddRtAttr(nl.IFLA_VXLAN_GROUP6, []byte(group))
}
}
}
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL)))
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS)))
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning))
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy))
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC))
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, boolAttr(vxlan.UDP6ZeroCSumTx))
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, boolAttr(vxlan.UDP6ZeroCSumRx))
+ data.AddRtAttr(nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL)))
+ data.AddRtAttr(nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS)))
+ data.AddRtAttr(nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning))
+ data.AddRtAttr(nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy))
+ data.AddRtAttr(nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC))
+ data.AddRtAttr(nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
+ data.AddRtAttr(nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
+ data.AddRtAttr(nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, boolAttr(vxlan.UDP6ZeroCSumTx))
+ data.AddRtAttr(nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, boolAttr(vxlan.UDP6ZeroCSumRx))
if vxlan.UDPCSum {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum))
+ data.AddRtAttr(nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum))
}
if vxlan.GBP {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GBP, []byte{})
+ data.AddRtAttr(nl.IFLA_VXLAN_GBP, []byte{})
}
if vxlan.FlowBased {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_FLOWBASED, boolAttr(vxlan.FlowBased))
+ data.AddRtAttr(nl.IFLA_VXLAN_FLOWBASED, boolAttr(vxlan.FlowBased))
}
if vxlan.NoAge {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
+ data.AddRtAttr(nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
} else if vxlan.Age > 0 {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age)))
+ data.AddRtAttr(nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age)))
}
if vxlan.Limit > 0 {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit)))
+ data.AddRtAttr(nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit)))
}
if vxlan.Port > 0 {
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, htons(uint16(vxlan.Port)))
+ data.AddRtAttr(nl.IFLA_VXLAN_PORT, htons(uint16(vxlan.Port)))
}
if vxlan.PortLow > 0 || vxlan.PortHigh > 0 {
pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)}
@@ -742,100 +931,100 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, &pr)
- nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes())
+ data.AddRtAttr(nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes())
}
}
func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
if bond.Mode >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_MODE, nl.Uint8Attr(uint8(bond.Mode)))
+ data.AddRtAttr(nl.IFLA_BOND_MODE, nl.Uint8Attr(uint8(bond.Mode)))
}
if bond.ActiveSlave >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_ACTIVE_SLAVE, nl.Uint32Attr(uint32(bond.ActiveSlave)))
+ data.AddRtAttr(nl.IFLA_BOND_ACTIVE_SLAVE, nl.Uint32Attr(uint32(bond.ActiveSlave)))
}
if bond.Miimon >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_MIIMON, nl.Uint32Attr(uint32(bond.Miimon)))
+ data.AddRtAttr(nl.IFLA_BOND_MIIMON, nl.Uint32Attr(uint32(bond.Miimon)))
}
if bond.UpDelay >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_UPDELAY, nl.Uint32Attr(uint32(bond.UpDelay)))
+ data.AddRtAttr(nl.IFLA_BOND_UPDELAY, nl.Uint32Attr(uint32(bond.UpDelay)))
}
if bond.DownDelay >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_DOWNDELAY, nl.Uint32Attr(uint32(bond.DownDelay)))
+ data.AddRtAttr(nl.IFLA_BOND_DOWNDELAY, nl.Uint32Attr(uint32(bond.DownDelay)))
}
if bond.UseCarrier >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_USE_CARRIER, nl.Uint8Attr(uint8(bond.UseCarrier)))
+ data.AddRtAttr(nl.IFLA_BOND_USE_CARRIER, nl.Uint8Attr(uint8(bond.UseCarrier)))
}
if bond.ArpInterval >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_ARP_INTERVAL, nl.Uint32Attr(uint32(bond.ArpInterval)))
+ data.AddRtAttr(nl.IFLA_BOND_ARP_INTERVAL, nl.Uint32Attr(uint32(bond.ArpInterval)))
}
if bond.ArpIpTargets != nil {
- msg := nl.NewRtAttrChild(data, nl.IFLA_BOND_ARP_IP_TARGET, nil)
+ msg := data.AddRtAttr(nl.IFLA_BOND_ARP_IP_TARGET, nil)
for i := range bond.ArpIpTargets {
ip := bond.ArpIpTargets[i].To4()
if ip != nil {
- nl.NewRtAttrChild(msg, i, []byte(ip))
+ msg.AddRtAttr(i, []byte(ip))
continue
}
ip = bond.ArpIpTargets[i].To16()
if ip != nil {
- nl.NewRtAttrChild(msg, i, []byte(ip))
+ msg.AddRtAttr(i, []byte(ip))
}
}
}
if bond.ArpValidate >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_ARP_VALIDATE, nl.Uint32Attr(uint32(bond.ArpValidate)))
+ data.AddRtAttr(nl.IFLA_BOND_ARP_VALIDATE, nl.Uint32Attr(uint32(bond.ArpValidate)))
}
if bond.ArpAllTargets >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_ARP_ALL_TARGETS, nl.Uint32Attr(uint32(bond.ArpAllTargets)))
+ data.AddRtAttr(nl.IFLA_BOND_ARP_ALL_TARGETS, nl.Uint32Attr(uint32(bond.ArpAllTargets)))
}
if bond.Primary >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_PRIMARY, nl.Uint32Attr(uint32(bond.Primary)))
+ data.AddRtAttr(nl.IFLA_BOND_PRIMARY, nl.Uint32Attr(uint32(bond.Primary)))
}
if bond.PrimaryReselect >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_PRIMARY_RESELECT, nl.Uint8Attr(uint8(bond.PrimaryReselect)))
+ data.AddRtAttr(nl.IFLA_BOND_PRIMARY_RESELECT, nl.Uint8Attr(uint8(bond.PrimaryReselect)))
}
if bond.FailOverMac >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_FAIL_OVER_MAC, nl.Uint8Attr(uint8(bond.FailOverMac)))
+ data.AddRtAttr(nl.IFLA_BOND_FAIL_OVER_MAC, nl.Uint8Attr(uint8(bond.FailOverMac)))
}
if bond.XmitHashPolicy >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_XMIT_HASH_POLICY, nl.Uint8Attr(uint8(bond.XmitHashPolicy)))
+ data.AddRtAttr(nl.IFLA_BOND_XMIT_HASH_POLICY, nl.Uint8Attr(uint8(bond.XmitHashPolicy)))
}
if bond.ResendIgmp >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_RESEND_IGMP, nl.Uint32Attr(uint32(bond.ResendIgmp)))
+ data.AddRtAttr(nl.IFLA_BOND_RESEND_IGMP, nl.Uint32Attr(uint32(bond.ResendIgmp)))
}
if bond.NumPeerNotif >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_NUM_PEER_NOTIF, nl.Uint8Attr(uint8(bond.NumPeerNotif)))
+ data.AddRtAttr(nl.IFLA_BOND_NUM_PEER_NOTIF, nl.Uint8Attr(uint8(bond.NumPeerNotif)))
}
if bond.AllSlavesActive >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_ALL_SLAVES_ACTIVE, nl.Uint8Attr(uint8(bond.AllSlavesActive)))
+ data.AddRtAttr(nl.IFLA_BOND_ALL_SLAVES_ACTIVE, nl.Uint8Attr(uint8(bond.AllSlavesActive)))
}
if bond.MinLinks >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_MIN_LINKS, nl.Uint32Attr(uint32(bond.MinLinks)))
+ data.AddRtAttr(nl.IFLA_BOND_MIN_LINKS, nl.Uint32Attr(uint32(bond.MinLinks)))
}
if bond.LpInterval >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval)))
+ data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval)))
}
if bond.PackersPerSlave >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave)))
+ data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave)))
}
if bond.LacpRate >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate)))
+ data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate)))
}
if bond.AdSelect >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_SELECT, nl.Uint8Attr(uint8(bond.AdSelect)))
+ data.AddRtAttr(nl.IFLA_BOND_AD_SELECT, nl.Uint8Attr(uint8(bond.AdSelect)))
}
if bond.AdActorSysPrio >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_ACTOR_SYS_PRIO, nl.Uint16Attr(uint16(bond.AdActorSysPrio)))
+ data.AddRtAttr(nl.IFLA_BOND_AD_ACTOR_SYS_PRIO, nl.Uint16Attr(uint16(bond.AdActorSysPrio)))
}
if bond.AdUserPortKey >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_USER_PORT_KEY, nl.Uint16Attr(uint16(bond.AdUserPortKey)))
+ data.AddRtAttr(nl.IFLA_BOND_AD_USER_PORT_KEY, nl.Uint16Attr(uint16(bond.AdUserPortKey)))
}
if bond.AdActorSystem != nil {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_ACTOR_SYSTEM, []byte(bond.AdActorSystem))
+ data.AddRtAttr(nl.IFLA_BOND_AD_ACTOR_SYSTEM, []byte(bond.AdActorSystem))
}
if bond.TlbDynamicLb >= 0 {
- nl.NewRtAttrChild(data, nl.IFLA_BOND_TLB_DYNAMIC_LB, nl.Uint8Attr(uint8(bond.TlbDynamicLb)))
+ data.AddRtAttr(nl.IFLA_BOND_TLB_DYNAMIC_LB, nl.Uint8Attr(uint8(bond.TlbDynamicLb)))
}
}
@@ -853,7 +1042,7 @@ func LinkAdd(link Link) error {
}
// LinkAdd adds a new link device. The type and features of the device
-// are taken fromt the parameters in the link object.
+// are taken from the parameters in the link object.
// Equivalent to: `ip link add $link`
func (h *Handle) LinkAdd(link Link) error {
return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
@@ -863,16 +1052,18 @@ func (h *Handle) linkModify(link Link, flags int) error {
// TODO: support extra data for macvlan
base := link.Attrs()
- if base.Name == "" {
- return fmt.Errorf("LinkAttrs.Name cannot be empty!")
+ // if tuntap, then the name can be empty, OS will provide a name
+ tuntap, isTuntap := link.(*Tuntap)
+
+ if base.Name == "" && !isTuntap {
+ return fmt.Errorf("LinkAttrs.Name cannot be empty")
}
- if tuntap, ok := link.(*Tuntap); ok {
+ if isTuntap {
// TODO: support user
// TODO: support group
- // TODO: support non- persistent
if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP {
- return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode)
+ return fmt.Errorf("Tuntap.Mode %v unknown", tuntap.Mode)
}
queues := tuntap.Queues
@@ -913,12 +1104,25 @@ func (h *Handle) linkModify(link Link, flags int) error {
cleanupFds(fds)
return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno)
}
+ // 1) we only care for the name of the first tap in the multi queue set
+ // 2) if the original name was empty, the localReq has now the actual name
+ //
+ // In addition:
+ // This ensures that the link name is always identical to what the kernel returns.
+ // Not only in case of an empty name, but also when using name templates.
+ // e.g. when the provided name is "tap%d", the kernel replaces %d with the next available number.
+ if i == 0 {
+ link.Attrs().Name = strings.Trim(string(localReq.Name[:]), "\x00")
+ }
}
- _, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1)
- if errno != 0 {
- cleanupFds(fds)
- return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
+ // only persist interface if NonPersist is NOT set
+ if !tuntap.NonPersist {
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1)
+ if errno != 0 {
+ cleanupFds(fds)
+ return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
+ }
}
h.ensureIndex(base)
@@ -928,7 +1132,11 @@ func (h *Handle) linkModify(link Link, flags int) error {
// TODO: verify MasterIndex is actually a bridge?
err := h.LinkSetMasterByIndex(link, base.MasterIndex)
if err != nil {
- _, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0)
+ // un-persist (e.g. allow the interface to be removed) the tuntap
+ // should not hurt if not set prior, condition might be not needed
+ if !tuntap.NonPersist {
+ _, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0)
+ }
cleanupFds(fds)
return err
}
@@ -978,8 +1186,8 @@ func (h *Handle) linkModify(link Link, flags int) error {
native.PutUint32(b, uint32(base.ParentIndex))
data := nl.NewRtAttr(unix.IFLA_LINK, b)
req.AddData(data)
- } else if link.Type() == "ipvlan" {
- return fmt.Errorf("Can't create ipvlan link without ParentIndex")
+ } else if link.Type() == "ipvlan" || link.Type() == "ipoib" {
+ return fmt.Errorf("Can't create %s link without ParentIndex", link.Type())
}
nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
@@ -1010,14 +1218,29 @@ func (h *Handle) linkModify(link Link, flags int) error {
req.AddData(rxqueues)
}
+ if base.GSOMaxSegs > 0 {
+ gsoAttr := nl.NewRtAttr(unix.IFLA_GSO_MAX_SEGS, nl.Uint32Attr(base.GSOMaxSegs))
+ req.AddData(gsoAttr)
+ }
+
+ if base.GSOMaxSize > 0 {
+ gsoAttr := nl.NewRtAttr(unix.IFLA_GSO_MAX_SIZE, nl.Uint32Attr(base.GSOMaxSize))
+ req.AddData(gsoAttr)
+ }
+
+ if base.Group > 0 {
+ groupAttr := nl.NewRtAttr(unix.IFLA_GROUP, nl.Uint32Attr(base.Group))
+ req.AddData(groupAttr)
+ }
+
if base.Namespace != nil {
var attr *nl.RtAttr
- switch base.Namespace.(type) {
+ switch ns := base.Namespace.(type) {
case NsPid:
- val := nl.Uint32Attr(uint32(base.Namespace.(NsPid)))
+ val := nl.Uint32Attr(uint32(ns))
attr = nl.NewRtAttr(unix.IFLA_NET_NS_PID, val)
case NsFd:
- val := nl.Uint32Attr(uint32(base.Namespace.(NsFd)))
+ val := nl.Uint32Attr(uint32(ns))
attr = nl.NewRtAttr(unix.IFLA_NET_NS_FD, val)
}
@@ -1029,47 +1252,56 @@ func (h *Handle) linkModify(link Link, flags int) error {
}
linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
- nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
+ linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
switch link := link.(type) {
case *Vlan:
b := make([]byte, 2)
native.PutUint16(b, uint16(link.VlanId))
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
- nl.NewRtAttrChild(data, nl.IFLA_VLAN_ID, b)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ data.AddRtAttr(nl.IFLA_VLAN_ID, b)
+
+ if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN {
+ data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol)))
+ }
case *Veth:
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
- peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil)
nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC)
- nl.NewRtAttrChild(peer, unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName))
+ peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName))
if base.TxQLen >= 0 {
- nl.NewRtAttrChild(peer, unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
+ peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
}
if base.MTU > 0 {
- nl.NewRtAttrChild(peer, unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
+ peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
+ }
+ if link.PeerHardwareAddr != nil {
+ peer.AddRtAttr(unix.IFLA_ADDRESS, []byte(link.PeerHardwareAddr))
}
-
case *Vxlan:
addVxlanAttrs(link, linkInfo)
case *Bond:
addBondAttrs(link, linkInfo)
case *IPVlan:
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
- nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode)))
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode)))
+ data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag)))
case *Macvlan:
if link.Mode != MACVLAN_MODE_DEFAULT {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
- nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
}
case *Macvtap:
if link.Mode != MACVLAN_MODE_DEFAULT {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
- nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode]))
}
case *Gretap:
addGretapAttrs(link, linkInfo)
case *Iptun:
addIptunAttrs(link, linkInfo)
+ case *Ip6tnl:
+ addIp6tnlAttrs(link, linkInfo)
case *Sittun:
addSittunAttrs(link, linkInfo)
case *Gretun:
@@ -1082,6 +1314,10 @@ func (h *Handle) linkModify(link Link, flags int) error {
addBridgeAttrs(link, linkInfo)
case *GTP:
addGTPAttrs(link, linkInfo)
+ case *Xfrmi:
+ addXfrmiAttrs(link, linkInfo)
+ case *IPoIB:
+ addIPoIBAttrs(link, linkInfo)
}
req.AddData(linkInfo)
@@ -1170,6 +1406,9 @@ func (h *Handle) LinkByName(name string) (Link, error) {
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
req.AddData(msg)
+ attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
+ req.AddData(attr)
+
nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(name))
req.AddData(nameData)
@@ -1202,6 +1441,9 @@ func (h *Handle) LinkByAlias(alias string) (Link, error) {
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
req.AddData(msg)
+ attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
+ req.AddData(attr)
+
nameData := nl.NewRtAttr(unix.IFLA_IFALIAS, nl.ZeroTerminated(alias))
req.AddData(nameData)
@@ -1228,6 +1470,8 @@ func (h *Handle) LinkByIndex(index int) (Link, error) {
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
msg.Index = int32(index)
req.AddData(msg)
+ attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
+ req.AddData(attr)
return execGetLink(req)
}
@@ -1270,10 +1514,12 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
base.Promisc = 1
}
var (
- link Link
- stats32 []byte
- stats64 []byte
- linkType string
+ link Link
+ stats32 *LinkStatistics32
+ stats64 *LinkStatistics64
+ linkType string
+ linkSlave LinkSlave
+ slaveType string
)
for _, attr := range attrs {
switch attr.Attr.Type {
@@ -1313,18 +1559,26 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Gretap{}
case "ipip":
link = &Iptun{}
+ case "ip6tnl":
+ link = &Ip6tnl{}
case "sit":
link = &Sittun{}
case "gre":
link = &Gretun{}
case "ip6gre":
link = &Gretun{}
- case "vti":
+ case "vti", "vti6":
link = &Vti{}
case "vrf":
link = &Vrf{}
case "gtp":
link = &GTP{}
+ case "xfrm":
+ link = &Xfrmi{}
+ case "tun":
+ link = &Tuntap{}
+ case "ipoib":
+ link = &IPoIB{}
default:
link = &GenericLink{LinkType: linkType}
}
@@ -1352,13 +1606,15 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
parseGretapData(link, data)
case "ipip":
parseIptunData(link, data)
+ case "ip6tnl":
+ parseIp6tnlData(link, data)
case "sit":
parseSittunData(link, data)
case "gre":
parseGretunData(link, data)
case "ip6gre":
parseGretunData(link, data)
- case "vti":
+ case "vti", "vti6":
parseVtiData(link, data)
case "vrf":
parseVrfData(link, data)
@@ -1366,6 +1622,27 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
parseBridgeData(link, data)
case "gtp":
parseGTPData(link, data)
+ case "xfrm":
+ parseXfrmiData(link, data)
+ case "tun":
+ parseTuntapData(link, data)
+ case "ipoib":
+ parseIPoIBData(link, data)
+ }
+ case nl.IFLA_INFO_SLAVE_KIND:
+ slaveType = string(info.Value[:len(info.Value)-1])
+ switch slaveType {
+ case "bond":
+ linkSlave = &BondSlave{}
+ }
+ case nl.IFLA_INFO_SLAVE_DATA:
+ switch slaveType {
+ case "bond":
+ data, err := nl.ParseRouteAttr(info.Value)
+ if err != nil {
+ return nil, err
+ }
+ parseBondSlaveData(linkSlave, data)
}
}
}
@@ -1392,9 +1669,15 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
case unix.IFLA_IFALIAS:
base.Alias = string(attr.Value[:len(attr.Value)-1])
case unix.IFLA_STATS:
- stats32 = attr.Value[:]
+ stats32 = new(LinkStatistics32)
+ if err := binary.Read(bytes.NewBuffer(attr.Value[:]), nl.NativeEndian(), stats32); err != nil {
+ return nil, err
+ }
case unix.IFLA_STATS64:
- stats64 = attr.Value[:]
+ stats64 = new(LinkStatistics64)
+ if err := binary.Read(bytes.NewBuffer(attr.Value[:]), nl.NativeEndian(), stats64); err != nil {
+ return nil, err
+ }
case unix.IFLA_XDP:
xdp, err := parseLinkXdp(attr.Value[:])
if err != nil {
@@ -1408,19 +1691,40 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
if err != nil {
return nil, err
}
- base.Protinfo = parseProtinfo(attrs)
+ protinfo := parseProtinfo(attrs)
+ base.Protinfo = &protinfo
}
case unix.IFLA_OPERSTATE:
base.OperState = LinkOperState(uint8(attr.Value[0]))
case unix.IFLA_LINK_NETNSID:
base.NetNsID = int(native.Uint32(attr.Value[0:4]))
+ case unix.IFLA_GSO_MAX_SIZE:
+ base.GSOMaxSize = native.Uint32(attr.Value[0:4])
+ case unix.IFLA_GSO_MAX_SEGS:
+ base.GSOMaxSegs = native.Uint32(attr.Value[0:4])
+ case unix.IFLA_VFINFO_LIST:
+ data, err := nl.ParseRouteAttr(attr.Value)
+ if err != nil {
+ return nil, err
+ }
+ vfs, err := parseVfInfoList(data)
+ if err != nil {
+ return nil, err
+ }
+ base.Vfs = vfs
+ case unix.IFLA_NUM_TX_QUEUES:
+ base.NumTxQueues = int(native.Uint32(attr.Value[0:4]))
+ case unix.IFLA_NUM_RX_QUEUES:
+ base.NumRxQueues = int(native.Uint32(attr.Value[0:4]))
+ case unix.IFLA_GROUP:
+ base.Group = native.Uint32(attr.Value[0:4])
}
}
if stats64 != nil {
- base.Statistics = parseLinkStats64(stats64)
+ base.Statistics = (*LinkStatistics)(stats64)
} else if stats32 != nil {
- base.Statistics = parseLinkStats32(stats32)
+ base.Statistics = (*LinkStatistics)(stats32.to64())
}
// Links that don't have IFLA_INFO_KIND are hardware devices
@@ -1428,10 +1732,59 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
link = &Device{}
}
*link.Attrs() = base
+ link.Attrs().Slave = linkSlave
+
+ // If the tuntap attributes are not updated by netlink due to
+ // an older driver, use sysfs
+ if link != nil && linkType == "tun" {
+ tuntap := link.(*Tuntap)
+
+ if tuntap.Mode == 0 {
+ ifname := tuntap.Attrs().Name
+ if flags, err := readSysPropAsInt64(ifname, "tun_flags"); err == nil {
+
+ if flags&unix.IFF_TUN != 0 {
+ tuntap.Mode = unix.IFF_TUN
+ } else if flags&unix.IFF_TAP != 0 {
+ tuntap.Mode = unix.IFF_TAP
+ }
+
+ tuntap.NonPersist = false
+ if flags&unix.IFF_PERSIST == 0 {
+ tuntap.NonPersist = true
+ }
+ }
+
+ // The sysfs interface for owner/group returns -1 for root user, instead of returning 0.
+ // So explicitly check for negative value, before assigning the owner uid/gid.
+ if owner, err := readSysPropAsInt64(ifname, "owner"); err == nil && owner > 0 {
+ tuntap.Owner = uint32(owner)
+ }
+
+ if group, err := readSysPropAsInt64(ifname, "group"); err == nil && group > 0 {
+ tuntap.Group = uint32(group)
+ }
+ }
+ }
return link, nil
}
+func readSysPropAsInt64(ifname, prop string) (int64, error) {
+ fname := fmt.Sprintf("/sys/class/net/%s/%s", ifname, prop)
+ contents, err := ioutil.ReadFile(fname)
+ if err != nil {
+ return 0, err
+ }
+
+ num, err := strconv.ParseInt(strings.TrimSpace(string(contents)), 0, 64)
+ if err == nil {
+ return num, nil
+ }
+
+ return 0, err
+}
+
// LinkList gets a list of link devices.
// Equivalent to: `ip link show`
func LinkList() ([]Link, error) {
@@ -1447,6 +1800,8 @@ func (h *Handle) LinkList() ([]Link, error) {
msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
req.AddData(msg)
+ attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF))
+ req.AddData(attr)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
if err != nil {
@@ -1526,13 +1881,19 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c
go func() {
defer close(ch)
for {
- msgs, err := s.Receive()
+ msgs, from, err := s.Receive()
if err != nil {
if cberr != nil {
cberr(err)
}
return
}
+ if from.Pid != nl.PidKernel {
+ if cberr != nil {
+ cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
+ }
+ continue
+ }
for _, m := range msgs {
if m.Header.Type == unix.NLMSG_DONE {
continue
@@ -1639,7 +2000,7 @@ func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
req.AddData(msg)
br := nl.NewRtAttr(unix.IFLA_PROTINFO|unix.NLA_F_NESTED, nil)
- nl.NewRtAttrChild(br, attr, boolToByte(mode))
+ br.AddRtAttr(attr, boolToByte(mode))
req.AddData(br)
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
if err != nil {
@@ -1675,12 +2036,43 @@ func (h *Handle) LinkSetTxQLen(link Link, qlen int) error {
return err
}
+// LinkSetGroup sets the link group id which can be used to perform mass actions
+// with iproute2 as well use it as a reference in nft filters.
+// Equivalent to: `ip link set $link group $id`
+func LinkSetGroup(link Link, group int) error {
+ return pkgHandle.LinkSetGroup(link, group)
+}
+
+// LinkSetGroup sets the link group id which can be used to perform mass actions
+// with iproute2 as well use it as a reference in nft filters.
+// Equivalent to: `ip link set $link group $id`
+func (h *Handle) LinkSetGroup(link Link, group int) error {
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ b := make([]byte, 4)
+ native.PutUint32(b, uint32(group))
+
+ data := nl.NewRtAttr(unix.IFLA_GROUP, b)
+ req.AddData(data)
+
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
vlan := link.(*Vlan)
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_VLAN_ID:
vlan.VlanId = int(native.Uint16(datum.Value[0:2]))
+ case nl.IFLA_VLAN_PROTOCOL:
+ vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2])))
}
}
}
@@ -1762,7 +2154,7 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_BOND_ARP_INTERVAL:
bond.ArpInterval = int(native.Uint32(data[i].Value[0:4]))
case nl.IFLA_BOND_ARP_IP_TARGET:
- // TODO: implement
+ bond.ArpIpTargets = parseBondArpIpTargets(data[i].Value)
case nl.IFLA_BOND_ARP_VALIDATE:
bond.ArpValidate = BondArpValidate(native.Uint32(data[i].Value[0:4]))
case nl.IFLA_BOND_ARP_ALL_TARGETS:
@@ -1805,12 +2197,75 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) {
}
}
+func parseBondArpIpTargets(value []byte) []net.IP {
+ data, err := nl.ParseRouteAttr(value)
+ if err != nil {
+ return nil
+ }
+
+ targets := []net.IP{}
+ for i := range data {
+ target := net.IP(data[i].Value)
+ if ip := target.To4(); ip != nil {
+ targets = append(targets, ip)
+ continue
+ }
+ if ip := target.To16(); ip != nil {
+ targets = append(targets, ip)
+ }
+ }
+
+ return targets
+}
+
+func addBondSlaveAttrs(bondSlave *BondSlave, linkInfo *nl.RtAttr) {
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil)
+
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_STATE, nl.Uint8Attr(uint8(bondSlave.State)))
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_MII_STATUS, nl.Uint8Attr(uint8(bondSlave.MiiStatus)))
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, nl.Uint32Attr(bondSlave.LinkFailureCount))
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(bondSlave.QueueId))
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, nl.Uint16Attr(bondSlave.AggregatorId))
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, nl.Uint8Attr(bondSlave.AdActorOperPortState))
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, nl.Uint16Attr(bondSlave.AdPartnerOperPortState))
+
+ if mac := bondSlave.PermHardwareAddr; mac != nil {
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_PERM_HWADDR, []byte(mac))
+ }
+}
+
+func parseBondSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) {
+ bondSlave := slave.(*BondSlave)
+ for i := range data {
+ switch data[i].Attr.Type {
+ case nl.IFLA_BOND_SLAVE_STATE:
+ bondSlave.State = BondSlaveState(data[i].Value[0])
+ case nl.IFLA_BOND_SLAVE_MII_STATUS:
+ bondSlave.MiiStatus = BondSlaveMiiStatus(data[i].Value[0])
+ case nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT:
+ bondSlave.LinkFailureCount = native.Uint32(data[i].Value[0:4])
+ case nl.IFLA_BOND_SLAVE_PERM_HWADDR:
+ bondSlave.PermHardwareAddr = net.HardwareAddr(data[i].Value[0:6])
+ case nl.IFLA_BOND_SLAVE_QUEUE_ID:
+ bondSlave.QueueId = native.Uint16(data[i].Value[0:2])
+ case nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID:
+ bondSlave.AggregatorId = native.Uint16(data[i].Value[0:2])
+ case nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE:
+ bondSlave.AdActorOperPortState = uint8(data[i].Value[0])
+ case nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE:
+ bondSlave.AdPartnerOperPortState = native.Uint16(data[i].Value[0:2])
+ }
+ }
+}
+
func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
ipv := link.(*IPVlan)
for _, datum := range data {
- if datum.Attr.Type == nl.IFLA_IPVLAN_MODE {
+ switch datum.Attr.Type {
+ case nl.IFLA_IPVLAN_MODE:
ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4]))
- return
+ case nl.IFLA_IPVLAN_FLAG:
+ ipv.Flag = IPVlanFlag(native.Uint32(datum.Value[0:4]))
}
}
}
@@ -1873,11 +2328,11 @@ func linkFlags(rawFlags uint32) net.Flags {
}
func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
if gretap.FlowBased {
// In flow based mode, no other attributes need to be configured
- nl.NewRtAttrChild(data, nl.IFLA_GRE_COLLECT_METADATA, boolAttr(gretap.FlowBased))
+ data.AddRtAttr(nl.IFLA_GRE_COLLECT_METADATA, boolAttr(gretap.FlowBased))
return
}
@@ -1885,40 +2340,40 @@ func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) {
if ip.To4() != nil {
ip = ip.To4()
}
- nl.NewRtAttrChild(data, nl.IFLA_GRE_LOCAL, []byte(ip))
+ data.AddRtAttr(nl.IFLA_GRE_LOCAL, []byte(ip))
}
if ip := gretap.Remote; ip != nil {
if ip.To4() != nil {
ip = ip.To4()
}
- nl.NewRtAttrChild(data, nl.IFLA_GRE_REMOTE, []byte(ip))
+ data.AddRtAttr(nl.IFLA_GRE_REMOTE, []byte(ip))
}
if gretap.IKey != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_GRE_IKEY, htonl(gretap.IKey))
+ data.AddRtAttr(nl.IFLA_GRE_IKEY, htonl(gretap.IKey))
gretap.IFlags |= uint16(nl.GRE_KEY)
}
if gretap.OKey != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_GRE_OKEY, htonl(gretap.OKey))
+ data.AddRtAttr(nl.IFLA_GRE_OKEY, htonl(gretap.OKey))
gretap.OFlags |= uint16(nl.GRE_KEY)
}
- nl.NewRtAttrChild(data, nl.IFLA_GRE_IFLAGS, htons(gretap.IFlags))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_OFLAGS, htons(gretap.OFlags))
+ data.AddRtAttr(nl.IFLA_GRE_IFLAGS, htons(gretap.IFlags))
+ data.AddRtAttr(nl.IFLA_GRE_OFLAGS, htons(gretap.OFlags))
if gretap.Link != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_GRE_LINK, nl.Uint32Attr(gretap.Link))
+ data.AddRtAttr(nl.IFLA_GRE_LINK, nl.Uint32Attr(gretap.Link))
}
- nl.NewRtAttrChild(data, nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gretap.PMtuDisc))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_TTL, nl.Uint8Attr(gretap.Ttl))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_TOS, nl.Uint8Attr(gretap.Tos))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gretap.EncapType))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gretap.EncapFlags))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_SPORT, htons(gretap.EncapSport))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_DPORT, htons(gretap.EncapDport))
+ data.AddRtAttr(nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gretap.PMtuDisc))
+ data.AddRtAttr(nl.IFLA_GRE_TTL, nl.Uint8Attr(gretap.Ttl))
+ data.AddRtAttr(nl.IFLA_GRE_TOS, nl.Uint8Attr(gretap.Tos))
+ data.AddRtAttr(nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gretap.EncapType))
+ data.AddRtAttr(nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gretap.EncapFlags))
+ data.AddRtAttr(nl.IFLA_GRE_ENCAP_SPORT, htons(gretap.EncapSport))
+ data.AddRtAttr(nl.IFLA_GRE_ENCAP_DPORT, htons(gretap.EncapDport))
}
func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
@@ -1930,9 +2385,9 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_GRE_IKEY:
gre.OKey = ntohl(datum.Value[0:4])
case nl.IFLA_GRE_LOCAL:
- gre.Local = net.IP(datum.Value[0:16])
+ gre.Local = net.IP(datum.Value)
case nl.IFLA_GRE_REMOTE:
- gre.Remote = net.IP(datum.Value[0:16])
+ gre.Remote = net.IP(datum.Value)
case nl.IFLA_GRE_ENCAP_SPORT:
gre.EncapSport = ntohs(datum.Value[0:2])
case nl.IFLA_GRE_ENCAP_DPORT:
@@ -1941,7 +2396,6 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
gre.IFlags = ntohs(datum.Value[0:2])
case nl.IFLA_GRE_OFLAGS:
gre.OFlags = ntohs(datum.Value[0:2])
-
case nl.IFLA_GRE_TTL:
gre.Ttl = uint8(datum.Value[0])
case nl.IFLA_GRE_TOS:
@@ -1953,73 +2407,70 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_GRE_ENCAP_FLAGS:
gre.EncapFlags = native.Uint16(datum.Value[0:2])
case nl.IFLA_GRE_COLLECT_METADATA:
- if len(datum.Value) > 0 {
- gre.FlowBased = int8(datum.Value[0]) != 0
- }
+ gre.FlowBased = true
}
}
}
func addGretunAttrs(gre *Gretun, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
if ip := gre.Local; ip != nil {
if ip.To4() != nil {
ip = ip.To4()
}
- nl.NewRtAttrChild(data, nl.IFLA_GRE_LOCAL, []byte(ip))
+ data.AddRtAttr(nl.IFLA_GRE_LOCAL, []byte(ip))
}
if ip := gre.Remote; ip != nil {
if ip.To4() != nil {
ip = ip.To4()
}
- nl.NewRtAttrChild(data, nl.IFLA_GRE_REMOTE, []byte(ip))
+ data.AddRtAttr(nl.IFLA_GRE_REMOTE, []byte(ip))
}
if gre.IKey != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_GRE_IKEY, htonl(gre.IKey))
+ data.AddRtAttr(nl.IFLA_GRE_IKEY, htonl(gre.IKey))
gre.IFlags |= uint16(nl.GRE_KEY)
}
if gre.OKey != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_GRE_OKEY, htonl(gre.OKey))
+ data.AddRtAttr(nl.IFLA_GRE_OKEY, htonl(gre.OKey))
gre.OFlags |= uint16(nl.GRE_KEY)
}
- nl.NewRtAttrChild(data, nl.IFLA_GRE_IFLAGS, htons(gre.IFlags))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_OFLAGS, htons(gre.OFlags))
+ data.AddRtAttr(nl.IFLA_GRE_IFLAGS, htons(gre.IFlags))
+ data.AddRtAttr(nl.IFLA_GRE_OFLAGS, htons(gre.OFlags))
if gre.Link != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_GRE_LINK, nl.Uint32Attr(gre.Link))
+ data.AddRtAttr(nl.IFLA_GRE_LINK, nl.Uint32Attr(gre.Link))
}
- nl.NewRtAttrChild(data, nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gre.PMtuDisc))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_TTL, nl.Uint8Attr(gre.Ttl))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_TOS, nl.Uint8Attr(gre.Tos))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gre.EncapType))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gre.EncapFlags))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_SPORT, htons(gre.EncapSport))
- nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_DPORT, htons(gre.EncapDport))
+ data.AddRtAttr(nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gre.PMtuDisc))
+ data.AddRtAttr(nl.IFLA_GRE_TTL, nl.Uint8Attr(gre.Ttl))
+ data.AddRtAttr(nl.IFLA_GRE_TOS, nl.Uint8Attr(gre.Tos))
+ data.AddRtAttr(nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gre.EncapType))
+ data.AddRtAttr(nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gre.EncapFlags))
+ data.AddRtAttr(nl.IFLA_GRE_ENCAP_SPORT, htons(gre.EncapSport))
+ data.AddRtAttr(nl.IFLA_GRE_ENCAP_DPORT, htons(gre.EncapDport))
}
func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) {
gre := link.(*Gretun)
for _, datum := range data {
switch datum.Attr.Type {
- case nl.IFLA_GRE_OKEY:
- gre.IKey = ntohl(datum.Value[0:4])
case nl.IFLA_GRE_IKEY:
+ gre.IKey = ntohl(datum.Value[0:4])
+ case nl.IFLA_GRE_OKEY:
gre.OKey = ntohl(datum.Value[0:4])
case nl.IFLA_GRE_LOCAL:
- gre.Local = net.IP(datum.Value[0:16])
+ gre.Local = net.IP(datum.Value)
case nl.IFLA_GRE_REMOTE:
- gre.Remote = net.IP(datum.Value[0:16])
+ gre.Remote = net.IP(datum.Value)
case nl.IFLA_GRE_IFLAGS:
gre.IFlags = ntohs(datum.Value[0:2])
case nl.IFLA_GRE_OFLAGS:
gre.OFlags = ntohs(datum.Value[0:2])
-
case nl.IFLA_GRE_TTL:
gre.Ttl = uint8(datum.Value[0])
case nl.IFLA_GRE_TOS:
@@ -2038,23 +2489,15 @@ func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) {
}
}
-func parseLinkStats32(data []byte) *LinkStatistics {
- return (*LinkStatistics)((*LinkStatistics32)(unsafe.Pointer(&data[0:SizeofLinkStats32][0])).to64())
-}
-
-func parseLinkStats64(data []byte) *LinkStatistics {
- return (*LinkStatistics)((*LinkStatistics64)(unsafe.Pointer(&data[0:SizeofLinkStats64][0])))
-}
-
func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) {
attrs := nl.NewRtAttr(unix.IFLA_XDP|unix.NLA_F_NESTED, nil)
b := make([]byte, 4)
native.PutUint32(b, uint32(xdp.Fd))
- nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FD, b)
+ attrs.AddRtAttr(nl.IFLA_XDP_FD, b)
if xdp.Flags != 0 {
b := make([]byte, 4)
native.PutUint32(b, xdp.Flags)
- nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FLAGS, b)
+ attrs.AddRtAttr(nl.IFLA_XDP_FLAGS, b)
}
req.AddData(attrs)
}
@@ -2083,32 +2526,32 @@ func parseLinkXdp(data []byte) (*LinkXdp, error) {
func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) {
if iptun.FlowBased {
// In flow based mode, no other attributes need to be configured
- nl.NewRtAttrChild(linkInfo, nl.IFLA_IPTUN_COLLECT_METADATA, boolAttr(iptun.FlowBased))
+ linkInfo.AddRtAttr(nl.IFLA_IPTUN_COLLECT_METADATA, boolAttr(iptun.FlowBased))
return
}
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
ip := iptun.Local.To4()
if ip != nil {
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LOCAL, []byte(ip))
+ data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip))
}
ip = iptun.Remote.To4()
if ip != nil {
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_REMOTE, []byte(ip))
+ data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip))
}
if iptun.Link != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LINK, nl.Uint32Attr(iptun.Link))
+ data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(iptun.Link))
}
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(iptun.EncapType))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport))
+ data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc))
+ data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl))
+ data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(iptun.EncapType))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport))
}
func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
@@ -2139,34 +2582,83 @@ func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) {
}
}
+func addIp6tnlAttrs(ip6tnl *Ip6tnl, linkInfo *nl.RtAttr) {
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+
+ if ip6tnl.Link != 0 {
+ data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(ip6tnl.Link))
+ }
+
+ ip := ip6tnl.Local.To16()
+ if ip != nil {
+ data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip))
+ }
+
+ ip = ip6tnl.Remote.To16()
+ if ip != nil {
+ data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip))
+ }
+
+ data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(ip6tnl.Ttl))
+ data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(ip6tnl.Tos))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_LIMIT, nl.Uint8Attr(ip6tnl.EncapLimit))
+ data.AddRtAttr(nl.IFLA_IPTUN_FLAGS, nl.Uint32Attr(ip6tnl.Flags))
+ data.AddRtAttr(nl.IFLA_IPTUN_PROTO, nl.Uint8Attr(ip6tnl.Proto))
+ data.AddRtAttr(nl.IFLA_IPTUN_FLOWINFO, nl.Uint32Attr(ip6tnl.FlowInfo))
+}
+
+func parseIp6tnlData(link Link, data []syscall.NetlinkRouteAttr) {
+ ip6tnl := link.(*Ip6tnl)
+ for _, datum := range data {
+ switch datum.Attr.Type {
+ case nl.IFLA_IPTUN_LOCAL:
+ ip6tnl.Local = net.IP(datum.Value[:16])
+ case nl.IFLA_IPTUN_REMOTE:
+ ip6tnl.Remote = net.IP(datum.Value[:16])
+ case nl.IFLA_IPTUN_TTL:
+ ip6tnl.Ttl = uint8(datum.Value[0])
+ case nl.IFLA_IPTUN_TOS:
+ ip6tnl.Tos = uint8(datum.Value[0])
+ case nl.IFLA_IPTUN_ENCAP_LIMIT:
+ ip6tnl.EncapLimit = uint8(datum.Value[0])
+ case nl.IFLA_IPTUN_FLAGS:
+ ip6tnl.Flags = native.Uint32(datum.Value[:4])
+ case nl.IFLA_IPTUN_PROTO:
+ ip6tnl.Proto = uint8(datum.Value[0])
+ case nl.IFLA_IPTUN_FLOWINFO:
+ ip6tnl.FlowInfo = native.Uint32(datum.Value[:4])
+ }
+ }
+}
+
func addSittunAttrs(sittun *Sittun, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
if sittun.Link != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LINK, nl.Uint32Attr(sittun.Link))
+ data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(sittun.Link))
}
ip := sittun.Local.To4()
if ip != nil {
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LOCAL, []byte(ip))
+ data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip))
}
ip = sittun.Remote.To4()
if ip != nil {
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_REMOTE, []byte(ip))
+ data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip))
}
if sittun.Ttl > 0 {
// Would otherwise fail on 3.10 kernel
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TTL, nl.Uint8Attr(sittun.Ttl))
+ data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(sittun.Ttl))
}
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TOS, nl.Uint8Attr(sittun.Tos))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(sittun.PMtuDisc))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(sittun.EncapType))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(sittun.EncapFlags))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_SPORT, htons(sittun.EncapSport))
- nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_DPORT, htons(sittun.EncapDport))
+ data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(sittun.Tos))
+ data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(sittun.PMtuDisc))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(sittun.EncapType))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(sittun.EncapFlags))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(sittun.EncapSport))
+ data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(sittun.EncapDport))
}
func parseSittunData(link Link, data []syscall.NetlinkRouteAttr) {
@@ -2196,24 +2688,39 @@ func parseSittunData(link Link, data []syscall.NetlinkRouteAttr) {
}
func addVtiAttrs(vti *Vti, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+
+ family := FAMILY_V4
+ if vti.Local.To4() == nil {
+ family = FAMILY_V6
+ }
- ip := vti.Local.To4()
+ var ip net.IP
+
+ if family == FAMILY_V4 {
+ ip = vti.Local.To4()
+ } else {
+ ip = vti.Local
+ }
if ip != nil {
- nl.NewRtAttrChild(data, nl.IFLA_VTI_LOCAL, []byte(ip))
+ data.AddRtAttr(nl.IFLA_VTI_LOCAL, []byte(ip))
}
- ip = vti.Remote.To4()
+ if family == FAMILY_V4 {
+ ip = vti.Remote.To4()
+ } else {
+ ip = vti.Remote
+ }
if ip != nil {
- nl.NewRtAttrChild(data, nl.IFLA_VTI_REMOTE, []byte(ip))
+ data.AddRtAttr(nl.IFLA_VTI_REMOTE, []byte(ip))
}
if vti.Link != 0 {
- nl.NewRtAttrChild(data, nl.IFLA_VTI_LINK, nl.Uint32Attr(vti.Link))
+ data.AddRtAttr(nl.IFLA_VTI_LINK, nl.Uint32Attr(vti.Link))
}
- nl.NewRtAttrChild(data, nl.IFLA_VTI_IKEY, htonl(vti.IKey))
- nl.NewRtAttrChild(data, nl.IFLA_VTI_OKEY, htonl(vti.OKey))
+ data.AddRtAttr(nl.IFLA_VTI_IKEY, htonl(vti.IKey))
+ data.AddRtAttr(nl.IFLA_VTI_OKEY, htonl(vti.OKey))
}
func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) {
@@ -2221,9 +2728,9 @@ func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) {
for _, datum := range data {
switch datum.Attr.Type {
case nl.IFLA_VTI_LOCAL:
- vti.Local = net.IP(datum.Value[0:4])
+ vti.Local = net.IP(datum.Value)
case nl.IFLA_VTI_REMOTE:
- vti.Remote = net.IP(datum.Value[0:4])
+ vti.Remote = net.IP(datum.Value)
case nl.IFLA_VTI_IKEY:
vti.IKey = ntohl(datum.Value[0:4])
case nl.IFLA_VTI_OKEY:
@@ -2233,10 +2740,10 @@ func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) {
}
func addVrfAttrs(vrf *Vrf, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
b := make([]byte, 4)
native.PutUint32(b, uint32(vrf.Table))
- nl.NewRtAttrChild(data, nl.IFLA_VRF_TABLE, b)
+ data.AddRtAttr(nl.IFLA_VRF_TABLE, b)
}
func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) {
@@ -2250,12 +2757,15 @@ func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) {
}
func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
if bridge.MulticastSnooping != nil {
- nl.NewRtAttrChild(data, nl.IFLA_BR_MCAST_SNOOPING, boolToByte(*bridge.MulticastSnooping))
+ data.AddRtAttr(nl.IFLA_BR_MCAST_SNOOPING, boolToByte(*bridge.MulticastSnooping))
}
if bridge.HelloTime != nil {
- nl.NewRtAttrChild(data, nl.IFLA_BR_HELLO_TIME, nl.Uint32Attr(*bridge.HelloTime))
+ data.AddRtAttr(nl.IFLA_BR_HELLO_TIME, nl.Uint32Attr(*bridge.HelloTime))
+ }
+ if bridge.VlanFiltering != nil {
+ data.AddRtAttr(nl.IFLA_BR_VLAN_FILTERING, boolToByte(*bridge.VlanFiltering))
}
}
@@ -2269,17 +2779,20 @@ func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) {
case nl.IFLA_BR_MCAST_SNOOPING:
mcastSnooping := datum.Value[0] == 1
br.MulticastSnooping = &mcastSnooping
+ case nl.IFLA_BR_VLAN_FILTERING:
+ vlanFiltering := datum.Value[0] == 1
+ br.VlanFiltering = &vlanFiltering
}
}
}
func addGTPAttrs(gtp *GTP, linkInfo *nl.RtAttr) {
- data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
- nl.NewRtAttrChild(data, nl.IFLA_GTP_FD0, nl.Uint32Attr(uint32(gtp.FD0)))
- nl.NewRtAttrChild(data, nl.IFLA_GTP_FD1, nl.Uint32Attr(uint32(gtp.FD1)))
- nl.NewRtAttrChild(data, nl.IFLA_GTP_PDP_HASHSIZE, nl.Uint32Attr(131072))
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ data.AddRtAttr(nl.IFLA_GTP_FD0, nl.Uint32Attr(uint32(gtp.FD0)))
+ data.AddRtAttr(nl.IFLA_GTP_FD1, nl.Uint32Attr(uint32(gtp.FD1)))
+ data.AddRtAttr(nl.IFLA_GTP_PDP_HASHSIZE, nl.Uint32Attr(131072))
if gtp.Role != nl.GTP_ROLE_GGSN {
- nl.NewRtAttrChild(data, nl.IFLA_GTP_ROLE, nl.Uint32Attr(uint32(gtp.Role)))
+ data.AddRtAttr(nl.IFLA_GTP_ROLE, nl.Uint32Attr(uint32(gtp.Role)))
}
}
@@ -2299,6 +2812,70 @@ func parseGTPData(link Link, data []syscall.NetlinkRouteAttr) {
}
}
+func parseVfInfoList(data []syscall.NetlinkRouteAttr) ([]VfInfo, error) {
+ var vfs []VfInfo
+
+ for i, element := range data {
+ if element.Attr.Type != nl.IFLA_VF_INFO {
+ return nil, fmt.Errorf("Incorrect element type in vf info list: %d", element.Attr.Type)
+ }
+ vfAttrs, err := nl.ParseRouteAttr(element.Value)
+ if err != nil {
+ return nil, err
+ }
+ vfs = append(vfs, parseVfInfo(vfAttrs, i))
+ }
+ return vfs, nil
+}
+
+func parseVfInfo(data []syscall.NetlinkRouteAttr, id int) VfInfo {
+ vf := VfInfo{ID: id}
+ for _, element := range data {
+ switch element.Attr.Type {
+ case nl.IFLA_VF_MAC:
+ mac := nl.DeserializeVfMac(element.Value[:])
+ vf.Mac = mac.Mac[:6]
+ case nl.IFLA_VF_VLAN:
+ vl := nl.DeserializeVfVlan(element.Value[:])
+ vf.Vlan = int(vl.Vlan)
+ vf.Qos = int(vl.Qos)
+ case nl.IFLA_VF_TX_RATE:
+ txr := nl.DeserializeVfTxRate(element.Value[:])
+ vf.TxRate = int(txr.Rate)
+ case nl.IFLA_VF_SPOOFCHK:
+ sp := nl.DeserializeVfSpoofchk(element.Value[:])
+ vf.Spoofchk = sp.Setting != 0
+ case nl.IFLA_VF_LINK_STATE:
+ ls := nl.DeserializeVfLinkState(element.Value[:])
+ vf.LinkState = ls.LinkState
+ case nl.IFLA_VF_RATE:
+ vfr := nl.DeserializeVfRate(element.Value[:])
+ vf.MaxTxRate = vfr.MaxTxRate
+ vf.MinTxRate = vfr.MinTxRate
+ }
+ }
+ return vf
+}
+
+func addXfrmiAttrs(xfrmi *Xfrmi, linkInfo *nl.RtAttr) {
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ data.AddRtAttr(nl.IFLA_XFRM_LINK, nl.Uint32Attr(uint32(xfrmi.ParentIndex)))
+ data.AddRtAttr(nl.IFLA_XFRM_IF_ID, nl.Uint32Attr(xfrmi.Ifid))
+
+}
+
+func parseXfrmiData(link Link, data []syscall.NetlinkRouteAttr) {
+ xfrmi := link.(*Xfrmi)
+ for _, datum := range data {
+ switch datum.Attr.Type {
+ case nl.IFLA_XFRM_LINK:
+ xfrmi.ParentIndex = int(native.Uint32(datum.Value))
+ case nl.IFLA_XFRM_IF_ID:
+ xfrmi.Ifid = native.Uint32(datum.Value)
+ }
+ }
+}
+
// LinkSetBondSlave add slave to bond link via ioctl interface.
func LinkSetBondSlave(link Link, master *Bond) error {
fd, err := getSocketUDP()
@@ -2316,6 +2893,52 @@ func LinkSetBondSlave(link Link, master *Bond) error {
return nil
}
+// LinkSetBondSlaveQueueId modify bond slave queue-id.
+func (h *Handle) LinkSetBondSlaveQueueId(link Link, queueId uint16) error {
+ base := link.Attrs()
+ h.ensureIndex(base)
+ req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK)
+
+ msg := nl.NewIfInfomsg(unix.AF_UNSPEC)
+ msg.Index = int32(base.Index)
+ req.AddData(msg)
+
+ linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil)
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil)
+ data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(queueId))
+
+ req.AddData(linkInfo)
+ _, err := req.Execute(unix.NETLINK_ROUTE, 0)
+ return err
+}
+
+// LinkSetBondSlaveQueueId modify bond slave queue-id.
+func LinkSetBondSlaveQueueId(link Link, queueId uint16) error {
+ return pkgHandle.LinkSetBondSlaveQueueId(link, queueId)
+}
+
+func vethStatsSerialize(stats ethtoolStats) ([]byte, error) {
+ statsSize := int(unsafe.Sizeof(stats)) + int(stats.nStats)*int(unsafe.Sizeof(uint64(0)))
+ b := make([]byte, 0, statsSize)
+ buf := bytes.NewBuffer(b)
+ err := binary.Write(buf, nl.NativeEndian(), stats)
+ return buf.Bytes()[:statsSize], err
+}
+
+type vethEthtoolStats struct {
+ Cmd uint32
+ NStats uint32
+ Peer uint64
+ // Newer kernels have XDP stats in here, but we only care
+ // to extract the peer ifindex here.
+}
+
+func vethStatsDeserialize(b []byte) (vethEthtoolStats, error) {
+ var stats = vethEthtoolStats{}
+ err := binary.Read(bytes.NewReader(b), nl.NativeEndian(), &stats)
+ return stats, err
+}
+
// VethPeerIndex get veth peer index.
func VethPeerIndex(link *Veth) (int, error) {
fd, err := getSocketUDP()
@@ -2330,25 +2953,66 @@ func VethPeerIndex(link *Veth) (int, error) {
return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
}
- gstrings := &ethtoolGstrings{
- cmd: ETHTOOL_GSTRINGS,
- stringSet: ETH_SS_STATS,
- length: sSet.data[0],
+ stats := ethtoolStats{
+ cmd: ETHTOOL_GSTATS,
+ nStats: sSet.data[0],
+ }
+
+ buffer, err := vethStatsSerialize(stats)
+ if err != nil {
+ return -1, err
}
- ifreq.Data = uintptr(unsafe.Pointer(gstrings))
+
+ ifreq.Data = uintptr(unsafe.Pointer(&buffer[0]))
_, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
if errno != 0 {
return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
}
- stats := &ethtoolStats{
- cmd: ETHTOOL_GSTATS,
- nStats: gstrings.length,
+ vstats, err := vethStatsDeserialize(buffer)
+ if err != nil {
+ return -1, err
}
- ifreq.Data = uintptr(unsafe.Pointer(stats))
- _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq)))
- if errno != 0 {
- return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno)
+
+ return int(vstats.Peer), nil
+}
+
+func parseTuntapData(link Link, data []syscall.NetlinkRouteAttr) {
+ tuntap := link.(*Tuntap)
+ for _, datum := range data {
+ switch datum.Attr.Type {
+ case nl.IFLA_TUN_OWNER:
+ tuntap.Owner = native.Uint32(datum.Value)
+ case nl.IFLA_TUN_GROUP:
+ tuntap.Group = native.Uint32(datum.Value)
+ case nl.IFLA_TUN_TYPE:
+ tuntap.Mode = TuntapMode(uint8(datum.Value[0]))
+ case nl.IFLA_TUN_PERSIST:
+ tuntap.NonPersist = false
+ if uint8(datum.Value[0]) == 0 {
+ tuntap.NonPersist = true
+ }
+ }
+ }
+}
+
+func parseIPoIBData(link Link, data []syscall.NetlinkRouteAttr) {
+ ipoib := link.(*IPoIB)
+ for _, datum := range data {
+ switch datum.Attr.Type {
+ case nl.IFLA_IPOIB_PKEY:
+ ipoib.Pkey = uint16(native.Uint16(datum.Value))
+ case nl.IFLA_IPOIB_MODE:
+ ipoib.Mode = IPoIBMode(native.Uint16(datum.Value))
+ case nl.IFLA_IPOIB_UMCAST:
+ ipoib.Umcast = uint16(native.Uint16(datum.Value))
+ }
}
- return int(stats.data[0]), nil
+}
+
+func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) {
+ data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
+ data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey)))
+ data.AddRtAttr(nl.IFLA_IPOIB_MODE, nl.Uint16Attr(uint16(ipoib.Mode)))
+ data.AddRtAttr(nl.IFLA_IPOIB_UMCAST, nl.Uint16Attr(uint16(ipoib.Umcast)))
}
diff --git a/vendor/github.com/vishvananda/netlink/neigh.go b/vendor/github.com/vishvananda/netlink/neigh.go
index 3f5cd497a..379e5655f 100644
--- a/vendor/github.com/vishvananda/netlink/neigh.go
+++ b/vendor/github.com/vishvananda/netlink/neigh.go
@@ -17,9 +17,16 @@ type Neigh struct {
LLIPAddr net.IP //Used in the case of NHRP
Vlan int
VNI int
+ MasterIndex int
}
// String returns $ip/$hwaddr $label
func (neigh *Neigh) String() string {
return fmt.Sprintf("%s %s", neigh.IP, neigh.HardwareAddr)
}
+
+// NeighUpdate is sent when a neighbor changes - type is RTM_NEWNEIGH or RTM_DELNEIGH.
+type NeighUpdate struct {
+ Type uint16
+ Neigh
+}
diff --git a/vendor/github.com/vishvananda/netlink/neigh_linux.go b/vendor/github.com/vishvananda/netlink/neigh_linux.go
index f75c22649..cb3b55d35 100644
--- a/vendor/github.com/vishvananda/netlink/neigh_linux.go
+++ b/vendor/github.com/vishvananda/netlink/neigh_linux.go
@@ -1,10 +1,13 @@
package netlink
import (
+ "fmt"
"net"
+ "syscall"
"unsafe"
"github.com/vishvananda/netlink/nl"
+ "github.com/vishvananda/netns"
"golang.org/x/sys/unix"
)
@@ -18,7 +21,10 @@ const (
NDA_PORT
NDA_VNI
NDA_IFINDEX
- NDA_MAX = NDA_IFINDEX
+ NDA_MASTER
+ NDA_LINK_NETNSID
+ NDA_SRC_VNI
+ NDA_MAX = NDA_SRC_VNI
)
// Neighbor Cache Entry States.
@@ -43,6 +49,7 @@ const (
NTF_ROUTER = 0x80
)
+// Ndmsg is for adding, removing or receiving information about a neighbor table entry
type Ndmsg struct {
Family uint8
Index uint32
@@ -170,45 +177,58 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
req.AddData(vniData)
}
+ if neigh.MasterIndex != 0 {
+ masterData := nl.NewRtAttr(NDA_MASTER, nl.Uint32Attr(uint32(neigh.MasterIndex)))
+ req.AddData(masterData)
+ }
+
_, err := req.Execute(unix.NETLINK_ROUTE, 0)
return err
}
-// NeighList gets a list of IP-MAC mappings in the system (ARP table).
+// NeighList returns a list of IP-MAC mappings in the system (ARP table).
// Equivalent to: `ip neighbor show`.
// The list can be filtered by link and ip family.
func NeighList(linkIndex, family int) ([]Neigh, error) {
return pkgHandle.NeighList(linkIndex, family)
}
-// NeighProxyList gets a list of neighbor proxies in the system.
+// NeighProxyList returns a list of neighbor proxies in the system.
// Equivalent to: `ip neighbor show proxy`.
// The list can be filtered by link and ip family.
func NeighProxyList(linkIndex, family int) ([]Neigh, error) {
return pkgHandle.NeighProxyList(linkIndex, family)
}
-// NeighList gets a list of IP-MAC mappings in the system (ARP table).
+// NeighList returns a list of IP-MAC mappings in the system (ARP table).
// Equivalent to: `ip neighbor show`.
// The list can be filtered by link and ip family.
func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
- return h.neighList(linkIndex, family, 0)
+ return h.NeighListExecute(Ndmsg{
+ Family: uint8(family),
+ Index: uint32(linkIndex),
+ })
}
-// NeighProxyList gets a list of neighbor proxies in the system.
+// NeighProxyList returns a list of neighbor proxies in the system.
// Equivalent to: `ip neighbor show proxy`.
// The list can be filtered by link, ip family.
func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) {
- return h.neighList(linkIndex, family, NTF_PROXY)
+ return h.NeighListExecute(Ndmsg{
+ Family: uint8(family),
+ Index: uint32(linkIndex),
+ Flags: NTF_PROXY,
+ })
+}
+
+// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
+func NeighListExecute(msg Ndmsg) ([]Neigh, error) {
+ return pkgHandle.NeighListExecute(msg)
}
-func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
+// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state.
+func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) {
req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP)
- msg := Ndmsg{
- Family: uint8(family),
- Index: uint32(linkIndex),
- Flags: uint8(flags),
- }
req.AddData(&msg)
msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH)
@@ -219,7 +239,7 @@ func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) {
var res []Neigh
for _, m := range msgs {
ndm := deserializeNdmsg(m)
- if linkIndex != 0 && int(ndm.Index) != linkIndex {
+ if msg.Index != 0 && ndm.Index != msg.Index {
// Ignore messages from other interfaces
continue
}
@@ -251,14 +271,6 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
return nil, err
}
- // This should be cached for perfomance
- // once per table dump
- link, err := LinkByIndex(neigh.LinkIndex)
- if err != nil {
- return nil, err
- }
- encapType := link.Attrs().EncapType
-
for _, attr := range attrs {
switch attr.Attr.Type {
case NDA_DST:
@@ -268,13 +280,16 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
// #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
// #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
attrLen := attr.Attr.Len - unix.SizeofRtAttr
- if attrLen == 4 && (encapType == "ipip" ||
- encapType == "sit" ||
- encapType == "gre") {
+ if attrLen == 4 {
neigh.LLIPAddr = net.IP(attr.Value)
- } else if attrLen == 16 &&
- encapType == "tunnel6" {
- neigh.IP = net.IP(attr.Value)
+ } else if attrLen == 16 {
+ // Can be IPv6 or FireWire HWAddr
+ link, err := LinkByIndex(neigh.LinkIndex)
+ if err == nil && link.Attrs().EncapType == "tunnel6" {
+ neigh.IP = net.IP(attr.Value)
+ } else {
+ neigh.HardwareAddr = net.HardwareAddr(attr.Value)
+ }
} else {
neigh.HardwareAddr = net.HardwareAddr(attr.Value)
}
@@ -282,8 +297,126 @@ func NeighDeserialize(m []byte) (*Neigh, error) {
neigh.Vlan = int(native.Uint16(attr.Value[0:2]))
case NDA_VNI:
neigh.VNI = int(native.Uint32(attr.Value[0:4]))
+ case NDA_MASTER:
+ neigh.MasterIndex = int(native.Uint32(attr.Value[0:4]))
}
}
return &neigh, nil
}
+
+// NeighSubscribe takes a chan down which notifications will be sent
+// when neighbors are added or deleted. Close the 'done' chan to stop subscription.
+func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error {
+ return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false)
+}
+
+// NeighSubscribeAt works like NeighSubscribe plus it allows the caller
+// to choose the network namespace in which to subscribe (ns).
+func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error {
+ return neighSubscribeAt(ns, netns.None(), ch, done, nil, false)
+}
+
+// NeighSubscribeOptions contains a set of options to use with
+// NeighSubscribeWithOptions.
+type NeighSubscribeOptions struct {
+ Namespace *netns.NsHandle
+ ErrorCallback func(error)
+ ListExisting bool
+}
+
+// NeighSubscribeWithOptions work like NeighSubscribe but enable to
+// provide additional options to modify the behavior. Currently, the
+// namespace can be provided as well as an error callback.
+func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error {
+ if options.Namespace == nil {
+ none := netns.None()
+ options.Namespace = &none
+ }
+ return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting)
+}
+
+func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error {
+ s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH)
+ makeRequest := func(family int) error {
+ req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH,
+ unix.NLM_F_DUMP)
+ infmsg := nl.NewIfInfomsg(family)
+ req.AddData(infmsg)
+ if err := s.Send(req); err != nil {
+ return err
+ }
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ if done != nil {
+ go func() {
+ <-done
+ s.Close()
+ }()
+ }
+ if listExisting {
+ if err := makeRequest(unix.AF_UNSPEC); err != nil {
+ return err
+ }
+ // We have to wait for NLMSG_DONE before making AF_BRIDGE request
+ }
+ go func() {
+ defer close(ch)
+ for {
+ msgs, from, err := s.Receive()
+ if err != nil {
+ if cberr != nil {
+ cberr(err)
+ }
+ return
+ }
+ if from.Pid != nl.PidKernel {
+ if cberr != nil {
+ cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
+ }
+ continue
+ }
+ for _, m := range msgs {
+ if m.Header.Type == unix.NLMSG_DONE {
+ if listExisting {
+ // This will be called after handling AF_UNSPEC
+ // list request, we have to wait for NLMSG_DONE
+ // before making another request
+ if err := makeRequest(unix.AF_BRIDGE); err != nil {
+ if cberr != nil {
+ cberr(err)
+ }
+ return
+ }
+ listExisting = false
+ }
+ continue
+ }
+ if m.Header.Type == unix.NLMSG_ERROR {
+ native := nl.NativeEndian()
+ error := int32(native.Uint32(m.Data[0:4]))
+ if error == 0 {
+ continue
+ }
+ if cberr != nil {
+ cberr(syscall.Errno(-error))
+ }
+ return
+ }
+ neigh, err := NeighDeserialize(m.Data)
+ if err != nil {
+ if cberr != nil {
+ cberr(err)
+ }
+ return
+ }
+ ch <- NeighUpdate{Type: m.Header.Type, Neigh: *neigh}
+ }
+ }
+ }()
+
+ return nil
+}
diff --git a/vendor/github.com/vishvananda/netlink/netlink.go b/vendor/github.com/vishvananda/netlink/netlink.go
index fb159526e..9cb685dc8 100644
--- a/vendor/github.com/vishvananda/netlink/netlink.go
+++ b/vendor/github.com/vishvananda/netlink/netlink.go
@@ -27,7 +27,8 @@ func ParseIPNet(s string) (*net.IPNet, error) {
if err != nil {
return nil, err
}
- return &net.IPNet{IP: ip, Mask: ipNet.Mask}, nil
+ ipNet.IP = ip
+ return ipNet, nil
}
// NewIPNet generates an IPNet from an ip address using a netmask of 32 or 128.
diff --git a/vendor/github.com/vishvananda/netlink/netlink_unspecified.go b/vendor/github.com/vishvananda/netlink/netlink_unspecified.go
index 86111b92c..42d3acf91 100644
--- a/vendor/github.com/vishvananda/netlink/netlink_unspecified.go
+++ b/vendor/github.com/vishvananda/netlink/netlink_unspecified.go
@@ -48,10 +48,18 @@ func LinkSetVfVlan(link Link, vf, vlan int) error {
return ErrNotImplemented
}
+func LinkSetVfVlanQos(link Link, vf, vlan, qos int) error {
+ return ErrNotImplemented
+}
+
func LinkSetVfTxRate(link Link, vf, rate int) error {
return ErrNotImplemented
}
+func LinkSetVfRate(link Link, vf, minRate, maxRate int) error {
+ return ErrNotImplemented
+}
+
func LinkSetNoMaster(link Link) error {
return ErrNotImplemented
}
@@ -152,6 +160,10 @@ func AddrAdd(link Link, addr *Addr) error {
return ErrNotImplemented
}
+func AddrReplace(link Link, addr *Addr) error {
+ return ErrNotImplemented
+}
+
func AddrDel(link Link, addr *Addr) error {
return ErrNotImplemented
}
diff --git a/vendor/github.com/vishvananda/netlink/netns_linux.go b/vendor/github.com/vishvananda/netlink/netns_linux.go
new file mode 100644
index 000000000..77cf6f469
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/netns_linux.go
@@ -0,0 +1,141 @@
+package netlink
+
+// Network namespace ID functions
+//
+// The kernel has a weird concept called the network namespace ID.
+// This is different from the file reference in proc (and any bind-mounted
+// namespaces, etc.)
+//
+// Instead, namespaces can be assigned a numeric ID at any time. Once set,
+// the ID is fixed. The ID can either be set manually by the user, or
+// automatically, triggered by certain kernel actions. The most common kernel
+// action that triggers namespace ID creation is moving one end of a veth pair
+// in to that namespace.
+
+import (
+ "fmt"
+
+ "github.com/vishvananda/netlink/nl"
+ "golang.org/x/sys/unix"
+)
+
+// These can be replaced by the values from sys/unix when it is next released.
+const (
+ _ = iota
+ NETNSA_NSID
+ NETNSA_PID
+ NETNSA_FD
+)
+
+// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
+// Returns -1 if the namespace does not have an ID set.
+func (h *Handle) GetNetNsIdByPid(pid int) (int, error) {
+ return h.getNetNsId(NETNSA_PID, uint32(pid))
+}
+
+// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id).
+// Returns -1 if the namespace does not have an ID set.
+func GetNetNsIdByPid(pid int) (int, error) {
+ return pkgHandle.GetNetNsIdByPid(pid)
+}
+
+// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
+// The ID can only be set for namespaces without an ID already set.
+func (h *Handle) SetNetNsIdByPid(pid, nsid int) error {
+ return h.setNetNsId(NETNSA_PID, uint32(pid), uint32(nsid))
+}
+
+// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id).
+// The ID can only be set for namespaces without an ID already set.
+func SetNetNsIdByPid(pid, nsid int) error {
+ return pkgHandle.SetNetNsIdByPid(pid, nsid)
+}
+
+// GetNetNsIdByFd looks up the network namespace ID for a given fd.
+// fd must be an open file descriptor to a namespace file.
+// Returns -1 if the namespace does not have an ID set.
+func (h *Handle) GetNetNsIdByFd(fd int) (int, error) {
+ return h.getNetNsId(NETNSA_FD, uint32(fd))
+}
+
+// GetNetNsIdByFd looks up the network namespace ID for a given fd.
+// fd must be an open file descriptor to a namespace file.
+// Returns -1 if the namespace does not have an ID set.
+func GetNetNsIdByFd(fd int) (int, error) {
+ return pkgHandle.GetNetNsIdByFd(fd)
+}
+
+// SetNetNSIdByFd sets the ID of the network namespace for a given fd.
+// fd must be an open file descriptor to a namespace file.
+// The ID can only be set for namespaces without an ID already set.
+func (h *Handle) SetNetNsIdByFd(fd, nsid int) error {
+ return h.setNetNsId(NETNSA_FD, uint32(fd), uint32(nsid))
+}
+
+// SetNetNSIdByFd sets the ID of the network namespace for a given fd.
+// fd must be an open file descriptor to a namespace file.
+// The ID can only be set for namespaces without an ID already set.
+func SetNetNsIdByFd(fd, nsid int) error {
+ return pkgHandle.SetNetNsIdByFd(fd, nsid)
+}
+
+// getNetNsId requests the netnsid for a given type-val pair
+// type should be either NETNSA_PID or NETNSA_FD
+func (h *Handle) getNetNsId(attrType int, val uint32) (int, error) {
+ req := h.newNetlinkRequest(unix.RTM_GETNSID, unix.NLM_F_REQUEST)
+
+ rtgen := nl.NewRtGenMsg()
+ req.AddData(rtgen)
+
+ b := make([]byte, 4, 4)
+ native.PutUint32(b, val)
+ attr := nl.NewRtAttr(attrType, b)
+ req.AddData(attr)
+
+ msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
+
+ if err != nil {
+ return 0, err
+ }
+
+ for _, m := range msgs {
+ msg := nl.DeserializeRtGenMsg(m)
+
+ attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+ if err != nil {
+ return 0, err
+ }
+
+ for _, attr := range attrs {
+ switch attr.Attr.Type {
+ case NETNSA_NSID:
+ return int(int32(native.Uint32(attr.Value))), nil
+ }
+ }
+ }
+
+ return 0, fmt.Errorf("unexpected empty result")
+}
+
+// setNetNsId sets the netnsid for a given type-val pair
+// type should be either NETNSA_PID or NETNSA_FD
+// The ID can only be set for namespaces without an ID already set
+func (h *Handle) setNetNsId(attrType int, val uint32, newnsid uint32) error {
+ req := h.newNetlinkRequest(unix.RTM_NEWNSID, unix.NLM_F_REQUEST|unix.NLM_F_ACK)
+
+ rtgen := nl.NewRtGenMsg()
+ req.AddData(rtgen)
+
+ b := make([]byte, 4, 4)
+ native.PutUint32(b, val)
+ attr := nl.NewRtAttr(attrType, b)
+ req.AddData(attr)
+
+ b1 := make([]byte, 4, 4)
+ native.PutUint32(b1, newnsid)
+ attr1 := nl.NewRtAttr(NETNSA_NSID, b1)
+ req.AddData(attr1)
+
+ _, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID)
+ return err
+}
diff --git a/vendor/github.com/vishvananda/netlink/netns_unspecified.go b/vendor/github.com/vishvananda/netlink/netns_unspecified.go
new file mode 100644
index 000000000..5c5899e36
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/netns_unspecified.go
@@ -0,0 +1,19 @@
+// +build !linux
+
+package netlink
+
+func GetNetNsIdByPid(pid int) (int, error) {
+ return 0, ErrNotImplemented
+}
+
+func SetNetNsIdByPid(pid, nsid int) error {
+ return ErrNotImplemented
+}
+
+func GetNetNsIdByFd(fd int) (int, error) {
+ return 0, ErrNotImplemented
+}
+
+func SetNetNsIdByFd(fd, nsid int) error {
+ return ErrNotImplemented
+}
diff --git a/vendor/github.com/vishvananda/netlink/nl/bridge_linux.go b/vendor/github.com/vishvananda/netlink/nl/bridge_linux.go
index 6c0d33338..34e78ba8d 100644
--- a/vendor/github.com/vishvananda/netlink/nl/bridge_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/bridge_linux.go
@@ -11,8 +11,8 @@ const (
/* Bridge Flags */
const (
- BRIDGE_FLAGS_MASTER = iota /* Bridge command to/from master */
- BRIDGE_FLAGS_SELF /* Bridge command to/from lowerdev */
+ BRIDGE_FLAGS_MASTER = iota + 1 /* Bridge command to/from master */
+ BRIDGE_FLAGS_SELF /* Bridge command to/from lowerdev */
)
/* Bridge management nested attributes
diff --git a/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go b/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
index 380cc5967..79d2b6b89 100644
--- a/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go
@@ -76,12 +76,17 @@ const (
// __CTA_MAX
// };
const (
- CTA_TUPLE_ORIG = 1
- CTA_TUPLE_REPLY = 2
- CTA_STATUS = 3
- CTA_TIMEOUT = 7
- CTA_MARK = 8
- CTA_PROTOINFO = 4
+ CTA_TUPLE_ORIG = 1
+ CTA_TUPLE_REPLY = 2
+ CTA_STATUS = 3
+ CTA_PROTOINFO = 4
+ CTA_TIMEOUT = 7
+ CTA_MARK = 8
+ CTA_COUNTERS_ORIG = 9
+ CTA_COUNTERS_REPLY = 10
+ CTA_USE = 11
+ CTA_ID = 12
+ CTA_TIMESTAMP = 20
)
// enum ctattr_tuple {
@@ -163,6 +168,29 @@ const (
CTA_PROTOINFO_TCP_FLAGS_REPLY = 5
)
+// enum ctattr_counters {
+// CTA_COUNTERS_UNSPEC,
+// CTA_COUNTERS_PACKETS, /* 64bit counters */
+// CTA_COUNTERS_BYTES, /* 64bit counters */
+// CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */
+// CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */
+// CTA_COUNTERS_PAD,
+// __CTA_COUNTERS_M
+// };
+// #define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
+const (
+ CTA_COUNTERS_PACKETS = 1
+ CTA_COUNTERS_BYTES = 2
+)
+
+// enum CTA TIMESTAMP TLVs
+// CTA_TIMESTAMP_START /* 64bit value */
+// CTA_TIMESTAMP_STOP /* 64bit value */
+const (
+ CTA_TIMESTAMP_START = 1
+ CTA_TIMESTAMP_STOP = 2
+)
+
// /* General form of address family dependent message.
// */
// struct nfgenmsg {
diff --git a/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go b/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go
new file mode 100644
index 000000000..db66faaad
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go
@@ -0,0 +1,40 @@
+package nl
+
+// All the following constants are coming from:
+// https://github.com/torvalds/linux/blob/master/include/uapi/linux/devlink.h
+
+const (
+ GENL_DEVLINK_VERSION = 1
+ GENL_DEVLINK_NAME = "devlink"
+)
+
+const (
+ DEVLINK_CMD_GET = 1
+ DEVLINK_CMD_ESWITCH_GET = 29
+ DEVLINK_CMD_ESWITCH_SET = 30
+)
+
+const (
+ DEVLINK_ATTR_BUS_NAME = 1
+ DEVLINK_ATTR_DEV_NAME = 2
+ DEVLINK_ATTR_ESWITCH_MODE = 25
+ DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26
+ DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62
+)
+
+const (
+ DEVLINK_ESWITCH_MODE_LEGACY = 0
+ DEVLINK_ESWITCH_MODE_SWITCHDEV = 1
+)
+
+const (
+ DEVLINK_ESWITCH_INLINE_MODE_NONE = 0
+ DEVLINK_ESWITCH_INLINE_MODE_LINK = 1
+ DEVLINK_ESWITCH_INLINE_MODE_NETWORK = 2
+ DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT = 3
+)
+
+const (
+ DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0
+ DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1
+)
diff --git a/vendor/github.com/vishvananda/netlink/nl/link_linux.go b/vendor/github.com/vishvananda/netlink/nl/link_linux.go
index 84a3498dd..afb16a9c1 100644
--- a/vendor/github.com/vishvananda/netlink/nl/link_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/link_linux.go
@@ -13,7 +13,9 @@ const (
IFLA_INFO_KIND
IFLA_INFO_DATA
IFLA_INFO_XSTATS
- IFLA_INFO_MAX = IFLA_INFO_XSTATS
+ IFLA_INFO_SLAVE_KIND
+ IFLA_INFO_SLAVE_DATA
+ IFLA_INFO_MAX = IFLA_INFO_SLAVE_DATA
)
const (
@@ -87,7 +89,8 @@ const (
const (
IFLA_IPVLAN_UNSPEC = iota
IFLA_IPVLAN_MODE
- IFLA_IPVLAN_MAX = IFLA_IPVLAN_MODE
+ IFLA_IPVLAN_FLAG
+ IFLA_IPVLAN_MAX = IFLA_IPVLAN_FLAG
)
const (
@@ -164,6 +167,8 @@ const (
IFLA_BOND_SLAVE_PERM_HWADDR
IFLA_BOND_SLAVE_QUEUE_ID
IFLA_BOND_SLAVE_AD_AGGREGATOR_ID
+ IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE
+ IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE
)
const (
@@ -217,9 +222,11 @@ const (
IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query
* on/off switch
*/
- IFLA_VF_STATS /* network device statistics */
- IFLA_VF_TRUST /* Trust state of VF */
- IFLA_VF_MAX = IFLA_VF_TRUST
+ IFLA_VF_STATS /* network device statistics */
+ IFLA_VF_TRUST /* Trust state of VF */
+ IFLA_VF_IB_NODE_GUID /* VF Infiniband node GUID */
+ IFLA_VF_IB_PORT_GUID /* VF Infiniband port GUID */
+ IFLA_VF_MAX = IFLA_VF_IB_PORT_GUID
)
const (
@@ -248,6 +255,7 @@ const (
SizeofVfLinkState = 0x08
SizeofVfRssQueryEn = 0x08
SizeofVfTrust = 0x08
+ SizeofVfGUID = 0x10
)
// struct ifla_vf_mac {
@@ -430,6 +438,30 @@ func (msg *VfTrust) Serialize() []byte {
return (*(*[SizeofVfTrust]byte)(unsafe.Pointer(msg)))[:]
}
+// struct ifla_vf_guid {
+// __u32 vf;
+// __u32 rsvd;
+// __u64 guid;
+// };
+
+type VfGUID struct {
+ Vf uint32
+ Rsvd uint32
+ GUID uint64
+}
+
+func (msg *VfGUID) Len() int {
+ return SizeofVfGUID
+}
+
+func DeserializeVfGUID(b []byte) *VfGUID {
+ return (*VfGUID)(unsafe.Pointer(&b[0:SizeofVfGUID][0]))
+}
+
+func (msg *VfGUID) Serialize() []byte {
+ return (*(*[SizeofVfGUID]byte)(unsafe.Pointer(msg)))[:]
+}
+
const (
XDP_FLAGS_UPDATE_IF_NOEXIST = 1 << iota
XDP_FLAGS_SKB_MODE
@@ -546,3 +578,33 @@ const (
GTP_ROLE_GGSN = iota
GTP_ROLE_SGSN
)
+
+const (
+ IFLA_XFRM_UNSPEC = iota
+ IFLA_XFRM_LINK
+ IFLA_XFRM_IF_ID
+
+ IFLA_XFRM_MAX = iota - 1
+)
+
+const (
+ IFLA_TUN_UNSPEC = iota
+ IFLA_TUN_OWNER
+ IFLA_TUN_GROUP
+ IFLA_TUN_TYPE
+ IFLA_TUN_PI
+ IFLA_TUN_VNET_HDR
+ IFLA_TUN_PERSIST
+ IFLA_TUN_MULTI_QUEUE
+ IFLA_TUN_NUM_QUEUES
+ IFLA_TUN_NUM_DISABLED_QUEUES
+ IFLA_TUN_MAX = IFLA_TUN_NUM_DISABLED_QUEUES
+)
+
+const (
+ IFLA_IPOIB_UNSPEC = iota
+ IFLA_IPOIB_PKEY
+ IFLA_IPOIB_MODE
+ IFLA_IPOIB_UMCAST
+ IFLA_IPOIB_MAX = IFLA_IPOIB_UMCAST
+)
diff --git a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
index bc8e82c2c..aaf56c671 100644
--- a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go
@@ -21,7 +21,13 @@ const (
FAMILY_ALL = unix.AF_UNSPEC
FAMILY_V4 = unix.AF_INET
FAMILY_V6 = unix.AF_INET6
- FAMILY_MPLS = AF_MPLS
+ FAMILY_MPLS = unix.AF_MPLS
+ // Arbitrary set value (greater than default 4k) to allow receiving
+ // from kernel more verbose messages e.g. for statistics,
+ // tc rules or filters, or other more memory requiring data.
+ RECEIVE_BUFFER_SIZE = 65536
+ // Kernel netlink pid
+ PidKernel uint32 = 0
)
// SupportedNlFamilies contains the list of netlink families this netlink package supports
@@ -42,7 +48,7 @@ func GetIPFamily(ip net.IP) int {
var nativeEndian binary.ByteOrder
-// Get native endianness for the system
+// NativeEndian gets native endianness for the system
func NativeEndian() binary.ByteOrder {
if nativeEndian == nil {
var x uint32 = 0x01020304
@@ -271,15 +277,22 @@ func NewRtAttr(attrType int, data []byte) *RtAttr {
}
}
-// Create a new RtAttr obj anc add it as a child of an existing object
+// NewRtAttrChild adds an RtAttr as a child to the parent and returns the new attribute
+//
+// Deprecated: Use AddRtAttr() on the parent object
func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
+ return parent.AddRtAttr(attrType, data)
+}
+
+// AddRtAttr adds an RtAttr as a child and returns the new attribute
+func (a *RtAttr) AddRtAttr(attrType int, data []byte) *RtAttr {
attr := NewRtAttr(attrType, data)
- parent.children = append(parent.children, attr)
+ a.children = append(a.children, attr)
return attr
}
-// AddChild adds an existing RtAttr as a child.
-func (a *RtAttr) AddChild(attr *RtAttr) {
+// AddChild adds an existing NetlinkRequestData as a child.
+func (a *RtAttr) AddChild(attr NetlinkRequestData) {
a.children = append(a.children, attr)
}
@@ -360,16 +373,12 @@ func (req *NetlinkRequest) Serialize() []byte {
}
func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
- if data != nil {
- req.Data = append(req.Data, data)
- }
+ req.Data = append(req.Data, data)
}
// AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization
func (req *NetlinkRequest) AddRawData(data []byte) {
- if data != nil {
- req.RawData = append(req.RawData, data...)
- }
+ req.RawData = append(req.RawData, data...)
}
// Execute the request against a the given sockType.
@@ -413,10 +422,13 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
done:
for {
- msgs, err := s.Receive()
+ msgs, from, err := s.Receive()
if err != nil {
return nil, err
}
+ if from.Pid != PidKernel {
+ return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, PidKernel)
+ }
for _, m := range msgs {
if m.Header.Seq != req.Seq {
if sharedSocket {
@@ -425,7 +437,7 @@ done:
return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
}
if m.Header.Pid != pid {
- return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
+ continue
}
if m.Header.Type == unix.NLMSG_DONE {
break done
@@ -610,21 +622,31 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
return nil
}
-func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
+func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, *unix.SockaddrNetlink, error) {
fd := int(atomic.LoadInt32(&s.fd))
if fd < 0 {
- return nil, fmt.Errorf("Receive called on a closed socket")
+ return nil, nil, fmt.Errorf("Receive called on a closed socket")
}
- rb := make([]byte, unix.Getpagesize())
- nr, _, err := unix.Recvfrom(fd, rb, 0)
+ var fromAddr *unix.SockaddrNetlink
+ var rb [RECEIVE_BUFFER_SIZE]byte
+ nr, from, err := unix.Recvfrom(fd, rb[:], 0)
if err != nil {
- return nil, err
+ return nil, nil, err
+ }
+ fromAddr, ok := from.(*unix.SockaddrNetlink)
+ if !ok {
+ return nil, nil, fmt.Errorf("Error converting to netlink sockaddr")
}
if nr < unix.NLMSG_HDRLEN {
- return nil, fmt.Errorf("Got short response from netlink")
+ return nil, nil, fmt.Errorf("Got short response from netlink")
+ }
+ rb2 := make([]byte, nr)
+ copy(rb2, rb[:nr])
+ nl, err := syscall.ParseNetlinkMessage(rb2)
+ if err != nil {
+ return nil, nil, err
}
- rb = rb[:nr]
- return syscall.ParseNetlinkMessage(rb)
+ return nl, fromAddr, nil
}
// SetSendTimeout allows to set a send timeout on the socket
diff --git a/vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go b/vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go
new file mode 100644
index 000000000..1224b747d
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go
@@ -0,0 +1,35 @@
+package nl
+
+const (
+ RDMA_NL_GET_CLIENT_SHIFT = 10
+)
+
+const (
+ RDMA_NL_NLDEV = 5
+)
+
+const (
+ RDMA_NLDEV_CMD_GET = 1
+ RDMA_NLDEV_CMD_SET = 2
+ RDMA_NLDEV_CMD_SYS_GET = 6
+ RDMA_NLDEV_CMD_SYS_SET = 7
+)
+
+const (
+ RDMA_NLDEV_ATTR_DEV_INDEX = 1
+ RDMA_NLDEV_ATTR_DEV_NAME = 2
+ RDMA_NLDEV_ATTR_PORT_INDEX = 3
+ RDMA_NLDEV_ATTR_CAP_FLAGS = 4
+ RDMA_NLDEV_ATTR_FW_VERSION = 5
+ RDMA_NLDEV_ATTR_NODE_GUID = 6
+ RDMA_NLDEV_ATTR_SYS_IMAGE_GUID = 7
+ RDMA_NLDEV_ATTR_SUBNET_PREFIX = 8
+ RDMA_NLDEV_ATTR_LID = 9
+ RDMA_NLDEV_ATTR_SM_LID = 10
+ RDMA_NLDEV_ATTR_LMC = 11
+ RDMA_NLDEV_ATTR_PORT_STATE = 12
+ RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13
+ RDMA_NLDEV_ATTR_DEV_NODE_TYPE = 14
+ RDMA_NLDEV_SYS_ATTR_NETNS_MODE = 66
+ RDMA_NLDEV_NET_NS_FD = 68
+)
diff --git a/vendor/github.com/vishvananda/netlink/nl/route_linux.go b/vendor/github.com/vishvananda/netlink/nl/route_linux.go
index f6906fcaf..03c1900ff 100644
--- a/vendor/github.com/vishvananda/netlink/nl/route_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/route_linux.go
@@ -79,3 +79,29 @@ func (msg *RtNexthop) Serialize() []byte {
}
return buf
}
+
+type RtGenMsg struct {
+ unix.RtGenmsg
+}
+
+func NewRtGenMsg() *RtGenMsg {
+ return &RtGenMsg{
+ RtGenmsg: unix.RtGenmsg{
+ Family: unix.AF_UNSPEC,
+ },
+ }
+}
+
+func (msg *RtGenMsg) Len() int {
+ return rtaAlignOf(unix.SizeofRtGenmsg)
+}
+
+func DeserializeRtGenMsg(b []byte) *RtGenMsg {
+ return &RtGenMsg{RtGenmsg: unix.RtGenmsg{Family: b[0]}}
+}
+
+func (msg *RtGenMsg) Serialize() []byte {
+ out := make([]byte, msg.Len())
+ out[0] = msg.Family
+ return out
+}
diff --git a/vendor/github.com/vishvananda/netlink/nl/seg6_linux.go b/vendor/github.com/vishvananda/netlink/nl/seg6_linux.go
index b3425f6b0..5774cbb15 100644
--- a/vendor/github.com/vishvananda/netlink/nl/seg6_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/seg6_linux.go
@@ -99,6 +99,49 @@ func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) {
return mode, srh.Segments, nil
}
+func DecodeSEG6Srh(buf []byte) ([]net.IP, error) {
+ native := NativeEndian()
+ srh := IPv6SrHdr{
+ nextHdr: buf[0],
+ hdrLen: buf[1],
+ routingType: buf[2],
+ segmentsLeft: buf[3],
+ firstSegment: buf[4],
+ flags: buf[5],
+ reserved: native.Uint16(buf[6:8]),
+ }
+ buf = buf[8:]
+ if len(buf)%16 != 0 {
+ err := fmt.Errorf("DecodeSEG6Srh: error parsing Segment List (buf len: %d)", len(buf))
+ return nil, err
+ }
+ for len(buf) > 0 {
+ srh.Segments = append(srh.Segments, net.IP(buf[:16]))
+ buf = buf[16:]
+ }
+ return srh.Segments, nil
+}
+func EncodeSEG6Srh(segments []net.IP) ([]byte, error) {
+ nsegs := len(segments) // nsegs: number of segments
+ if nsegs == 0 {
+ return nil, errors.New("EncodeSEG6Srh: No Segments")
+ }
+ b := make([]byte, 8, 8+len(segments)*16)
+ native := NativeEndian()
+ b[0] = 0 // srh.nextHdr (0 when calling netlink)
+ b[1] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit)
+ b[2] = IPV6_SRCRT_TYPE_4 // srh.routingType (assigned by IANA)
+ b[3] = uint8(nsegs - 1) // srh.segmentsLeft
+ b[4] = uint8(nsegs - 1) // srh.firstSegment
+ b[5] = 0 // srh.flags (SR6_FLAG1_HMAC for srh_hmac)
+ // srh.reserved: Defined as "Tag" in draft-ietf-6man-segment-routing-header-07
+ native.PutUint16(b[6:], 0) // srh.reserved
+ for _, netIP := range segments {
+ b = append(b, netIP...) // srh.Segments
+ }
+ return b, nil
+}
+
// Helper functions
func SEG6EncapModeString(mode int) string {
switch mode {
diff --git a/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go b/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go
new file mode 100644
index 000000000..150017726
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go
@@ -0,0 +1,76 @@
+package nl
+
+import ()
+
+// seg6local parameters
+const (
+ SEG6_LOCAL_UNSPEC = iota
+ SEG6_LOCAL_ACTION
+ SEG6_LOCAL_SRH
+ SEG6_LOCAL_TABLE
+ SEG6_LOCAL_NH4
+ SEG6_LOCAL_NH6
+ SEG6_LOCAL_IIF
+ SEG6_LOCAL_OIF
+ __SEG6_LOCAL_MAX
+)
+const (
+ SEG6_LOCAL_MAX = __SEG6_LOCAL_MAX
+)
+
+// seg6local actions
+const (
+ SEG6_LOCAL_ACTION_END = iota + 1 // 1
+ SEG6_LOCAL_ACTION_END_X // 2
+ SEG6_LOCAL_ACTION_END_T // 3
+ SEG6_LOCAL_ACTION_END_DX2 // 4
+ SEG6_LOCAL_ACTION_END_DX6 // 5
+ SEG6_LOCAL_ACTION_END_DX4 // 6
+ SEG6_LOCAL_ACTION_END_DT6 // 7
+ SEG6_LOCAL_ACTION_END_DT4 // 8
+ SEG6_LOCAL_ACTION_END_B6 // 9
+ SEG6_LOCAL_ACTION_END_B6_ENCAPS // 10
+ SEG6_LOCAL_ACTION_END_BM // 11
+ SEG6_LOCAL_ACTION_END_S // 12
+ SEG6_LOCAL_ACTION_END_AS // 13
+ SEG6_LOCAL_ACTION_END_AM // 14
+ __SEG6_LOCAL_ACTION_MAX
+)
+const (
+ SEG6_LOCAL_ACTION_MAX = __SEG6_LOCAL_ACTION_MAX - 1
+)
+
+// Helper functions
+func SEG6LocalActionString(action int) string {
+ switch action {
+ case SEG6_LOCAL_ACTION_END:
+ return "End"
+ case SEG6_LOCAL_ACTION_END_X:
+ return "End.X"
+ case SEG6_LOCAL_ACTION_END_T:
+ return "End.T"
+ case SEG6_LOCAL_ACTION_END_DX2:
+ return "End.DX2"
+ case SEG6_LOCAL_ACTION_END_DX6:
+ return "End.DX6"
+ case SEG6_LOCAL_ACTION_END_DX4:
+ return "End.DX4"
+ case SEG6_LOCAL_ACTION_END_DT6:
+ return "End.DT6"
+ case SEG6_LOCAL_ACTION_END_DT4:
+ return "End.DT4"
+ case SEG6_LOCAL_ACTION_END_B6:
+ return "End.B6"
+ case SEG6_LOCAL_ACTION_END_B6_ENCAPS:
+ return "End.B6.Encaps"
+ case SEG6_LOCAL_ACTION_END_BM:
+ return "End.BM"
+ case SEG6_LOCAL_ACTION_END_S:
+ return "End.S"
+ case SEG6_LOCAL_ACTION_END_AS:
+ return "End.AS"
+ case SEG6_LOCAL_ACTION_END_AM:
+ return "End.AM"
+ }
+ return "unknown"
+}
diff --git a/vendor/github.com/vishvananda/netlink/nl/syscall.go b/vendor/github.com/vishvananda/netlink/nl/syscall.go
index fc631e0e5..f7f7f92e6 100644
--- a/vendor/github.com/vishvananda/netlink/nl/syscall.go
+++ b/vendor/github.com/vishvananda/netlink/nl/syscall.go
@@ -42,16 +42,6 @@ const (
TCPDIAG_NOCOOKIE = 0xFFFFFFFF /* TCPDIAG_NOCOOKIE in net/ipv4/tcp_diag.h*/
)
-const (
- AF_MPLS = 28
-)
-
-const (
- RTA_NEWDST = 0x13
- RTA_ENCAP_TYPE = 0x15
- RTA_ENCAP = 0x16
-)
-
// RTA_ENCAP subtype
const (
MPLS_IPTUNNEL_UNSPEC = iota
@@ -67,6 +57,7 @@ const (
LWTUNNEL_ENCAP_IP6
LWTUNNEL_ENCAP_SEG6
LWTUNNEL_ENCAP_BPF
+ LWTUNNEL_ENCAP_SEG6_LOCAL
)
// routing header types
diff --git a/vendor/github.com/vishvananda/netlink/nl/tc_linux.go b/vendor/github.com/vishvananda/netlink/nl/tc_linux.go
index 94ebc290a..501f554b2 100644
--- a/vendor/github.com/vishvananda/netlink/nl/tc_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/tc_linux.go
@@ -1,6 +1,7 @@
package nl
import (
+ "encoding/binary"
"unsafe"
)
@@ -65,6 +66,15 @@ const (
)
const (
+ TCA_STATS_UNSPEC = iota
+ TCA_STATS_BASIC
+ TCA_STATS_RATE_EST
+ TCA_STATS_QUEUE
+ TCA_STATS_APP
+ TCA_STATS_MAX = TCA_STATS_APP
+)
+
+const (
SizeofTcMsg = 0x14
SizeofTcActionMsg = 0x04
SizeofTcPrioMap = 0x14
@@ -79,7 +89,10 @@ const (
SizeofTcU32Key = 0x10
SizeofTcU32Sel = 0x10 // without keys
SizeofTcGen = 0x14
+ SizeofTcConnmark = SizeofTcGen + 0x04
SizeofTcMirred = SizeofTcGen + 0x08
+ SizeofTcTunnelKey = SizeofTcGen + 0x04
+ SizeofTcSkbEdit = SizeofTcGen
SizeofTcPolice = 2*SizeofTcRateSpec + 0x20
)
@@ -412,6 +425,57 @@ func (x *TcHtbGlob) Serialize() []byte {
return (*(*[SizeofTcHtbGlob]byte)(unsafe.Pointer(x)))[:]
}
+// HFSC
+
+type Curve struct {
+ m1 uint32
+ d uint32
+ m2 uint32
+}
+
+type HfscCopt struct {
+ Rsc Curve
+ Fsc Curve
+ Usc Curve
+}
+
+func (c *Curve) Attrs() (uint32, uint32, uint32) {
+ return c.m1, c.d, c.m2
+}
+
+func (c *Curve) Set(m1 uint32, d uint32, m2 uint32) {
+ c.m1 = m1
+ c.d = d
+ c.m2 = m2
+}
+
+func DeserializeHfscCurve(b []byte) *Curve {
+ return &Curve{
+ m1: binary.LittleEndian.Uint32(b[0:4]),
+ d: binary.LittleEndian.Uint32(b[4:8]),
+ m2: binary.LittleEndian.Uint32(b[8:12]),
+ }
+}
+
+func SerializeHfscCurve(c *Curve) (b []byte) {
+ t := make([]byte, binary.MaxVarintLen32)
+ binary.LittleEndian.PutUint32(t, c.m1)
+ b = append(b, t[:4]...)
+ binary.LittleEndian.PutUint32(t, c.d)
+ b = append(b, t[:4]...)
+ binary.LittleEndian.PutUint32(t, c.m2)
+ b = append(b, t[:4]...)
+ return b
+}
+
+type TcHfscOpt struct {
+ Defcls uint16
+}
+
+func (x *TcHfscOpt) Serialize() []byte {
+ return (*(*[2]byte)(unsafe.Pointer(x)))[:]
+}
+
const (
TCA_U32_UNSPEC = iota
TCA_U32_CLASSID
@@ -586,12 +650,48 @@ const (
TCA_BPF_FD
TCA_BPF_NAME
TCA_BPF_FLAGS
- TCA_BPF_MAX = TCA_BPF_FLAGS
+ TCA_BPF_FLAGS_GEN
+ TCA_BPF_TAG
+ TCA_BPF_ID
+ TCA_BPF_MAX = TCA_BPF_ID
)
type TcBpf TcGen
const (
+ TCA_ACT_CONNMARK = 14
+)
+
+const (
+ TCA_CONNMARK_UNSPEC = iota
+ TCA_CONNMARK_PARMS
+ TCA_CONNMARK_TM
+ TCA_CONNMARK_MAX = TCA_CONNMARK_TM
+)
+
+// struct tc_connmark {
+// tc_gen;
+// __u16 zone;
+// };
+
+type TcConnmark struct {
+ TcGen
+ Zone uint16
+}
+
+func (msg *TcConnmark) Len() int {
+ return SizeofTcConnmark
+}
+
+func DeserializeTcConnmark(b []byte) *TcConnmark {
+ return (*TcConnmark)(unsafe.Pointer(&b[0:SizeofTcConnmark][0]))
+}
+
+func (x *TcConnmark) Serialize() []byte {
+ return (*(*[SizeofTcConnmark]byte)(unsafe.Pointer(x)))[:]
+}
+
+const (
TCA_ACT_MIRRED = 8
)
@@ -626,6 +726,63 @@ func (x *TcMirred) Serialize() []byte {
return (*(*[SizeofTcMirred]byte)(unsafe.Pointer(x)))[:]
}
+const (
+ TCA_TUNNEL_KEY_UNSPEC = iota
+ TCA_TUNNEL_KEY_TM
+ TCA_TUNNEL_KEY_PARMS
+ TCA_TUNNEL_KEY_ENC_IPV4_SRC
+ TCA_TUNNEL_KEY_ENC_IPV4_DST
+ TCA_TUNNEL_KEY_ENC_IPV6_SRC
+ TCA_TUNNEL_KEY_ENC_IPV6_DST
+ TCA_TUNNEL_KEY_ENC_KEY_ID
+ TCA_TUNNEL_KEY_MAX = TCA_TUNNEL_KEY_ENC_KEY_ID
+)
+
+type TcTunnelKey struct {
+ TcGen
+ Action int32
+}
+
+func (x *TcTunnelKey) Len() int {
+ return SizeofTcTunnelKey
+}
+
+func DeserializeTunnelKey(b []byte) *TcTunnelKey {
+ return (*TcTunnelKey)(unsafe.Pointer(&b[0:SizeofTcTunnelKey][0]))
+}
+
+func (x *TcTunnelKey) Serialize() []byte {
+ return (*(*[SizeofTcTunnelKey]byte)(unsafe.Pointer(x)))[:]
+}
+
+const (
+ TCA_SKBEDIT_UNSPEC = iota
+ TCA_SKBEDIT_TM
+ TCA_SKBEDIT_PARMS
+ TCA_SKBEDIT_PRIORITY
+ TCA_SKBEDIT_QUEUE_MAPPING
+ TCA_SKBEDIT_MARK
+ TCA_SKBEDIT_PAD
+ TCA_SKBEDIT_PTYPE
+ TCA_SKBEDIT_MAX = TCA_SKBEDIT_MARK
+)
+
+type TcSkbEdit struct {
+ TcGen
+}
+
+func (x *TcSkbEdit) Len() int {
+ return SizeofTcSkbEdit
+}
+
+func DeserializeSkbEdit(b []byte) *TcSkbEdit {
+ return (*TcSkbEdit)(unsafe.Pointer(&b[0:SizeofTcSkbEdit][0]))
+}
+
+func (x *TcSkbEdit) Serialize() []byte {
+ return (*(*[SizeofTcSkbEdit]byte)(unsafe.Pointer(x)))[:]
+}
+
// struct tc_police {
// __u32 index;
// int action;
@@ -708,3 +865,10 @@ const (
TCA_FQ_CODEL_DROP_BATCH_SIZE
TCA_FQ_CODEL_MEMORY_LIMIT
)
+
+const (
+ TCA_HFSC_UNSPEC = iota
+ TCA_HFSC_RSC
+ TCA_HFSC_FSC
+ TCA_HFSC_USC
+)
diff --git a/vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go b/vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go
index 09a2ffa10..dce9073f7 100644
--- a/vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go
+++ b/vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go
@@ -50,34 +50,44 @@ const (
// Attribute types
const (
/* Netlink message attributes. */
- XFRMA_UNSPEC = 0x00
- XFRMA_ALG_AUTH = 0x01 /* struct xfrm_algo */
- XFRMA_ALG_CRYPT = 0x02 /* struct xfrm_algo */
- XFRMA_ALG_COMP = 0x03 /* struct xfrm_algo */
- XFRMA_ENCAP = 0x04 /* struct xfrm_algo + struct xfrm_encap_tmpl */
- XFRMA_TMPL = 0x05 /* 1 or more struct xfrm_user_tmpl */
- XFRMA_SA = 0x06 /* struct xfrm_usersa_info */
- XFRMA_POLICY = 0x07 /* struct xfrm_userpolicy_info */
- XFRMA_SEC_CTX = 0x08 /* struct xfrm_sec_ctx */
- XFRMA_LTIME_VAL = 0x09
- XFRMA_REPLAY_VAL = 0x0a
- XFRMA_REPLAY_THRESH = 0x0b
- XFRMA_ETIMER_THRESH = 0x0c
- XFRMA_SRCADDR = 0x0d /* xfrm_address_t */
- XFRMA_COADDR = 0x0e /* xfrm_address_t */
- XFRMA_LASTUSED = 0x0f /* unsigned long */
- XFRMA_POLICY_TYPE = 0x10 /* struct xfrm_userpolicy_type */
- XFRMA_MIGRATE = 0x11
- XFRMA_ALG_AEAD = 0x12 /* struct xfrm_algo_aead */
- XFRMA_KMADDRESS = 0x13 /* struct xfrm_user_kmaddress */
- XFRMA_ALG_AUTH_TRUNC = 0x14 /* struct xfrm_algo_auth */
- XFRMA_MARK = 0x15 /* struct xfrm_mark */
- XFRMA_TFCPAD = 0x16 /* __u32 */
- XFRMA_REPLAY_ESN_VAL = 0x17 /* struct xfrm_replay_esn */
- XFRMA_SA_EXTRA_FLAGS = 0x18 /* __u32 */
- XFRMA_MAX = 0x18
+ XFRMA_UNSPEC = iota
+ XFRMA_ALG_AUTH /* struct xfrm_algo */
+ XFRMA_ALG_CRYPT /* struct xfrm_algo */
+ XFRMA_ALG_COMP /* struct xfrm_algo */
+ XFRMA_ENCAP /* struct xfrm_algo + struct xfrm_encap_tmpl */
+ XFRMA_TMPL /* 1 or more struct xfrm_user_tmpl */
+ XFRMA_SA /* struct xfrm_usersa_info */
+ XFRMA_POLICY /* struct xfrm_userpolicy_info */
+ XFRMA_SEC_CTX /* struct xfrm_sec_ctx */
+ XFRMA_LTIME_VAL
+ XFRMA_REPLAY_VAL
+ XFRMA_REPLAY_THRESH
+ XFRMA_ETIMER_THRESH
+ XFRMA_SRCADDR /* xfrm_address_t */
+ XFRMA_COADDR /* xfrm_address_t */
+ XFRMA_LASTUSED /* unsigned long */
+ XFRMA_POLICY_TYPE /* struct xfrm_userpolicy_type */
+ XFRMA_MIGRATE
+ XFRMA_ALG_AEAD /* struct xfrm_algo_aead */
+ XFRMA_KMADDRESS /* struct xfrm_user_kmaddress */
+ XFRMA_ALG_AUTH_TRUNC /* struct xfrm_algo_auth */
+ XFRMA_MARK /* struct xfrm_mark */
+ XFRMA_TFCPAD /* __u32 */
+ XFRMA_REPLAY_ESN_VAL /* struct xfrm_replay_esn */
+ XFRMA_SA_EXTRA_FLAGS /* __u32 */
+ XFRMA_PROTO /* __u8 */
+ XFRMA_ADDRESS_FILTER /* struct xfrm_address_filter */
+ XFRMA_PAD
+ XFRMA_OFFLOAD_DEV /* struct xfrm_state_offload */
+ XFRMA_SET_MARK /* __u32 */
+ XFRMA_SET_MARK_MASK /* __u32 */
+ XFRMA_IF_ID /* __u32 */
+
+ XFRMA_MAX = iota - 1
)
+const XFRMA_OUTPUT_MARK = XFRMA_SET_MARK
+
const (
SizeofXfrmAddress = 0x10
SizeofXfrmSelector = 0x38
diff --git a/vendor/github.com/vishvananda/netlink/protinfo.go b/vendor/github.com/vishvananda/netlink/protinfo.go
index 0087c4438..60b23b374 100644
--- a/vendor/github.com/vishvananda/netlink/protinfo.go
+++ b/vendor/github.com/vishvananda/netlink/protinfo.go
@@ -18,6 +18,10 @@ type Protinfo struct {
// String returns a list of enabled flags
func (prot *Protinfo) String() string {
+ if prot == nil {
+ return "<nil>"
+ }
+
var boolStrings []string
if prot.Hairpin {
boolStrings = append(boolStrings, "Hairpin")
diff --git a/vendor/github.com/vishvananda/netlink/protinfo_linux.go b/vendor/github.com/vishvananda/netlink/protinfo_linux.go
index 43c465f05..15b65123c 100644
--- a/vendor/github.com/vishvananda/netlink/protinfo_linux.go
+++ b/vendor/github.com/vishvananda/netlink/protinfo_linux.go
@@ -41,7 +41,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
if err != nil {
return pi, err
}
- pi = *parseProtinfo(infos)
+ pi = parseProtinfo(infos)
return pi, nil
}
@@ -49,8 +49,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
return pi, fmt.Errorf("Device with index %d not found", base.Index)
}
-func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
- var pi Protinfo
+func parseProtinfo(infos []syscall.NetlinkRouteAttr) (pi Protinfo) {
for _, info := range infos {
switch info.Attr.Type {
case nl.IFLA_BRPORT_MODE:
@@ -71,5 +70,5 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo {
pi.ProxyArpWiFi = byteToBool(info.Value[0])
}
}
- return &pi
+ return
}
diff --git a/vendor/github.com/vishvananda/netlink/qdisc.go b/vendor/github.com/vishvananda/netlink/qdisc.go
index 3df4b5c29..af78305ac 100644
--- a/vendor/github.com/vishvananda/netlink/qdisc.go
+++ b/vendor/github.com/vishvananda/netlink/qdisc.go
@@ -176,6 +176,13 @@ type Netem struct {
CorruptCorr uint32
}
+func (netem *Netem) String() string {
+ return fmt.Sprintf(
+ "{Latency: %v, Limit: %v, Loss: %v, Gap: %v, Duplicate: %v, Jitter: %v}",
+ netem.Latency, netem.Limit, netem.Loss, netem.Gap, netem.Duplicate, netem.Jitter,
+ )
+}
+
func (qdisc *Netem) Attrs() *QdiscAttrs {
return &qdisc.QdiscAttrs
}
@@ -231,6 +238,33 @@ func (qdisc *GenericQdisc) Type() string {
return qdisc.QdiscType
}
+type Hfsc struct {
+ QdiscAttrs
+ Defcls uint16
+}
+
+func NewHfsc(attrs QdiscAttrs) *Hfsc {
+ return &Hfsc{
+ QdiscAttrs: attrs,
+ Defcls: 1,
+ }
+}
+
+func (hfsc *Hfsc) Attrs() *QdiscAttrs {
+ return &hfsc.QdiscAttrs
+}
+
+func (hfsc *Hfsc) Type() string {
+ return "hfsc"
+}
+
+func (hfsc *Hfsc) String() string {
+ return fmt.Sprintf(
+ "{%v -- default: %d}",
+ hfsc.Attrs(), hfsc.Defcls,
+ )
+}
+
// Fq is a classless packet scheduler meant to be mostly used for locally generated traffic.
type Fq struct {
QdiscAttrs
@@ -249,6 +283,13 @@ type Fq struct {
LowRateThreshold uint32
}
+func (fq *Fq) String() string {
+ return fmt.Sprintf(
+ "{PacketLimit: %v, FlowPacketLimit: %v, Quantum: %v, InitialQuantum: %v, Pacing: %v, FlowDefaultRate: %v, FlowMaxRate: %v, Buckets: %v, FlowRefillDelay: %v, LowRateThreshold: %v}",
+ fq.PacketLimit, fq.FlowPacketLimit, fq.Quantum, fq.InitialQuantum, fq.Pacing, fq.FlowDefaultRate, fq.FlowMaxRate, fq.Buckets, fq.FlowRefillDelay, fq.LowRateThreshold,
+ )
+}
+
func NewFq(attrs QdiscAttrs) *Fq {
return &Fq{
QdiscAttrs: attrs,
@@ -276,6 +317,13 @@ type FqCodel struct {
// There are some more attributes here, but support for them seems not ubiquitous
}
+func (fqcodel *FqCodel) String() string {
+ return fmt.Sprintf(
+ "{%v -- Target: %v, Limit: %v, Interval: %v, ECM: %v, Flows: %v, Quantum: %v}",
+ fqcodel.Attrs(), fqcodel.Target, fqcodel.Limit, fqcodel.Interval, fqcodel.ECN, fqcodel.Flows, fqcodel.Quantum,
+ )
+}
+
func NewFqCodel(attrs QdiscAttrs) *FqCodel {
return &FqCodel{
QdiscAttrs: attrs,
diff --git a/vendor/github.com/vishvananda/netlink/qdisc_linux.go b/vendor/github.com/vishvananda/netlink/qdisc_linux.go
index 3794ac18a..e9eee5908 100644
--- a/vendor/github.com/vishvananda/netlink/qdisc_linux.go
+++ b/vendor/github.com/vishvananda/netlink/qdisc_linux.go
@@ -175,15 +175,15 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
opt.Peakrate.Rate = uint32(qdisc.Peakrate)
opt.Limit = qdisc.Limit
opt.Buffer = qdisc.Buffer
- nl.NewRtAttrChild(options, nl.TCA_TBF_PARMS, opt.Serialize())
+ options.AddRtAttr(nl.TCA_TBF_PARMS, opt.Serialize())
if qdisc.Rate >= uint64(1<<32) {
- nl.NewRtAttrChild(options, nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate))
+ options.AddRtAttr(nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate))
}
if qdisc.Peakrate >= uint64(1<<32) {
- nl.NewRtAttrChild(options, nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate))
+ options.AddRtAttr(nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate))
}
if qdisc.Peakrate > 0 {
- nl.NewRtAttrChild(options, nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst))
+ options.AddRtAttr(nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst))
}
case *Htb:
opt := nl.TcHtbGlob{}
@@ -193,8 +193,12 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
// TODO: Handle Debug properly. For now default to 0
opt.Debug = qdisc.Debug
opt.DirectPkts = qdisc.DirectPkts
- nl.NewRtAttrChild(options, nl.TCA_HTB_INIT, opt.Serialize())
- // nl.NewRtAttrChild(options, nl.TCA_HTB_DIRECT_QLEN, opt.Serialize())
+ options.AddRtAttr(nl.TCA_HTB_INIT, opt.Serialize())
+ // options.AddRtAttr(nl.TCA_HTB_DIRECT_QLEN, opt.Serialize())
+ case *Hfsc:
+ opt := nl.TcHfscOpt{}
+ opt.Defcls = qdisc.Defcls
+ options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize())
case *Netem:
opt := nl.TcNetemQopt{}
opt.Latency = qdisc.Latency
@@ -211,21 +215,21 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
corr.DupCorr = qdisc.DuplicateCorr
if corr.DelayCorr > 0 || corr.LossCorr > 0 || corr.DupCorr > 0 {
- nl.NewRtAttrChild(options, nl.TCA_NETEM_CORR, corr.Serialize())
+ options.AddRtAttr(nl.TCA_NETEM_CORR, corr.Serialize())
}
// Corruption
corruption := nl.TcNetemCorrupt{}
corruption.Probability = qdisc.CorruptProb
corruption.Correlation = qdisc.CorruptCorr
if corruption.Probability > 0 {
- nl.NewRtAttrChild(options, nl.TCA_NETEM_CORRUPT, corruption.Serialize())
+ options.AddRtAttr(nl.TCA_NETEM_CORRUPT, corruption.Serialize())
}
// Reorder
reorder := nl.TcNetemReorder{}
reorder.Probability = qdisc.ReorderProb
reorder.Correlation = qdisc.ReorderCorr
if reorder.Probability > 0 {
- nl.NewRtAttrChild(options, nl.TCA_NETEM_REORDER, reorder.Serialize())
+ options.AddRtAttr(nl.TCA_NETEM_REORDER, reorder.Serialize())
}
case *Ingress:
// ingress filters must use the proper handle
@@ -233,50 +237,54 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS")
}
case *FqCodel:
- nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
+ options.AddRtAttr(nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN))))
if qdisc.Limit > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
+ options.AddRtAttr(nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit))))
}
if qdisc.Interval > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
+ options.AddRtAttr(nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval))))
}
if qdisc.Flows > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
+ options.AddRtAttr(nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows))))
}
if qdisc.Quantum > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
+ options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
}
case *Fq:
- nl.NewRtAttrChild(options, nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
+ options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing))))
if qdisc.Buckets > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets))))
+ options.AddRtAttr(nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets))))
}
if qdisc.LowRateThreshold > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold))))
+ options.AddRtAttr(nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold))))
}
if qdisc.Quantum > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
+ options.AddRtAttr(nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum))))
}
if qdisc.InitialQuantum > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum))))
+ options.AddRtAttr(nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum))))
}
if qdisc.FlowRefillDelay > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay))))
+ options.AddRtAttr(nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay))))
}
if qdisc.FlowPacketLimit > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit))))
+ options.AddRtAttr(nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit))))
}
if qdisc.FlowMaxRate > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate))))
+ options.AddRtAttr(nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate))))
}
if qdisc.FlowDefaultRate > 0 {
- nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
+ options.AddRtAttr(nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate))))
}
+ default:
+ options = nil
}
- req.AddData(options)
+ if options != nil {
+ req.AddData(options)
+ }
return nil
}
@@ -348,6 +356,8 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
qdisc = &Htb{}
case "fq":
qdisc = &Fq{}
+ case "hfsc":
+ qdisc = &Hfsc{}
case "fq_codel":
qdisc = &FqCodel{}
case "netem":
@@ -375,6 +385,10 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
if err := parseTbfData(qdisc, data); err != nil {
return nil, err
}
+ case "hfsc":
+ if err := parseHfscData(qdisc, attr.Value); err != nil {
+ return nil, err
+ }
case "htb":
data, err := nl.ParseRouteAttr(attr.Value)
if err != nil {
@@ -474,6 +488,13 @@ func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
return nil
}
+func parseHfscData(qdisc Qdisc, data []byte) error {
+ Hfsc := qdisc.(*Hfsc)
+ native = nl.NativeEndian()
+ Hfsc.Defcls = native.Uint16(data)
+ return nil
+}
+
func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error {
native = nl.NativeEndian()
fq := qdisc.(*Fq)
diff --git a/vendor/github.com/vishvananda/netlink/rdma_link_linux.go b/vendor/github.com/vishvananda/netlink/rdma_link_linux.go
new file mode 100644
index 000000000..2d0bdc8c3
--- /dev/null
+++ b/vendor/github.com/vishvananda/netlink/rdma_link_linux.go
@@ -0,0 +1,264 @@
+package netlink
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "net"
+
+ "github.com/vishvananda/netlink/nl"
+ "golang.org/x/sys/unix"
+)
+
+// LinkAttrs represents data shared by most link types
+type RdmaLinkAttrs struct {
+ Index uint32
+ Name string
+ FirmwareVersion string
+ NodeGuid string
+ SysImageGuid string
+}
+
+// Link represents a rdma device from netlink.
+type RdmaLink struct {
+ Attrs RdmaLinkAttrs
+}
+
+func getProtoField(clientType int, op int) int {
+ return ((clientType << nl.RDMA_NL_GET_CLIENT_SHIFT) | op)
+}
+
+func uint64ToGuidString(guid uint64) string {
+ //Convert to byte array
+ sysGuidBytes := new(bytes.Buffer)
+ binary.Write(sysGuidBytes, binary.LittleEndian, guid)
+
+ //Convert to HardwareAddr
+ sysGuidNet := net.HardwareAddr(sysGuidBytes.Bytes())
+
+ //Get the String
+ return sysGuidNet.String()
+}
+
+func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) {
+
+ link := RdmaLink{}
+
+ reader := bytes.NewReader(data)
+ for reader.Len() >= 4 {
+ _, attrType, len, value := parseNfAttrTLV(reader)
+
+ switch attrType {
+ case nl.RDMA_NLDEV_ATTR_DEV_INDEX:
+ var Index uint32
+ r := bytes.NewReader(value)
+ binary.Read(r, nl.NativeEndian(), &Index)
+ link.Attrs.Index = Index
+ case nl.RDMA_NLDEV_ATTR_DEV_NAME:
+ link.Attrs.Name = string(value[0 : len-1])
+ case nl.RDMA_NLDEV_ATTR_FW_VERSION:
+ link.Attrs.FirmwareVersion = string(value[0 : len-1])
+ case nl.RDMA_NLDEV_ATTR_NODE_GUID:
+ var guid uint64
+ r := bytes.NewReader(value)
+ binary.Read(r, nl.NativeEndian(), &guid)
+ link.Attrs.NodeGuid = uint64ToGuidString(guid)
+ case nl.RDMA_NLDEV_ATTR_SYS_IMAGE_GUID:
+ var sysGuid uint64
+ r := bytes.NewReader(value)
+ binary.Read(r, nl.NativeEndian(), &sysGuid)
+ link.Attrs.SysImageGuid = uint64ToGuidString(sysGuid)
+ }
+ if (len % 4) != 0 {
+ // Skip pad bytes
+ reader.Seek(int64(4-(len%4)), seekCurrent)
+ }
+ }
+ return &link, nil
+}
+
+func execRdmaGetLink(req *nl.NetlinkRequest, name string) (*RdmaLink, error) {
+
+ msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
+ if err != nil {
+ return nil, err
+ }
+ for _, m := range msgs {
+ link, err := executeOneGetRdmaLink(m)
+ if err != nil {
+ return nil, err
+ }
+ if link.Attrs.Name == name {
+ return link, nil
+ }
+ }
+ return nil, fmt.Errorf("Rdma device %v not found", name)
+}
+
+func execRdmaSetLink(req *nl.NetlinkRequest) error {
+
+ _, err := req.Execute(unix.NETLINK_RDMA, 0)
+ return err
+}
+
+// RdmaLinkByName finds a link by name and returns a pointer to the object if
+// found and nil error, otherwise returns error code.
+func RdmaLinkByName(name string) (*RdmaLink, error) {
+ return pkgHandle.RdmaLinkByName(name)
+}
+
+// RdmaLinkByName finds a link by name and returns a pointer to the object if
+// found and nil error, otherwise returns error code.
+func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) {
+
+ proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET)
+ req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP)
+
+ return execRdmaGetLink(req, name)
+}
+
+// RdmaLinkSetName sets the name of the rdma link device. Return nil on success
+// or error otherwise.
+// Equivalent to: `rdma dev set $old_devname name $name`
+func RdmaLinkSetName(link *RdmaLink, name string) error {
+ return pkgHandle.RdmaLinkSetName(link, name)
+}
+
+// RdmaLinkSetName sets the name of the rdma link device. Return nil on success
+// or error otherwise.
+// Equivalent to: `rdma dev set $old_devname name $name`
+func (h *Handle) RdmaLinkSetName(link *RdmaLink, name string) error {
+ proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
+ req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
+
+ b := make([]byte, 4)
+ native.PutUint32(b, uint32(link.Attrs.Index))
+ data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b)
+ req.AddData(data)
+
+ b = make([]byte, len(name)+1)
+ copy(b, name)
+ data = nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, b)
+ req.AddData(data)
+
+ return execRdmaSetLink(req)
+}
+
+func netnsModeToString(mode uint8) string {
+ switch mode {
+ case 0:
+ return "exclusive"
+ case 1:
+ return "shared"
+ default:
+ return "unknown"
+ }
+}
+
+func executeOneGetRdmaNetnsMode(data []byte) (string, error) {
+ reader := bytes.NewReader(data)
+ for reader.Len() >= 4 {
+ _, attrType, len, value := parseNfAttrTLV(reader)
+
+ switch attrType {
+ case nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE:
+ var mode uint8
+ r := bytes.NewReader(value)
+ binary.Read(r, nl.NativeEndian(), &mode)
+ return netnsModeToString(mode), nil
+ }
+ if (len % 4) != 0 {
+ // Skip pad bytes
+ reader.Seek(int64(4-(len%4)), seekCurrent)
+ }
+ }
+ return "", fmt.Errorf("Invalid netns mode")
+}
+
+// RdmaSystemGetNetnsMode gets the net namespace mode for RDMA subsystem
+// Returns mode string and error status as nil on success or returns error
+// otherwise.
+// Equivalent to: `rdma system show netns'
+func RdmaSystemGetNetnsMode() (string, error) {
+ return pkgHandle.RdmaSystemGetNetnsMode()
+}
+
+// RdmaSystemGetNetnsMode gets the net namespace mode for RDMA subsystem
+// Returns mode string and error status as nil on success or returns error
+// otherwise.
+// Equivalent to: `rdma system show netns'
+func (h *Handle) RdmaSystemGetNetnsMode() (string, error) {
+
+ proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_GET)
+ req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
+
+ msgs, err := req.Execute(unix.NETLINK_RDMA, 0)
+ if err != nil {
+ return "", err
+ }
+ if len(msgs) == 0 {
+ return "", fmt.Errorf("No valid response from kernel")
+ }
+ return executeOneGetRdmaNetnsMode(msgs[0])
+}
+
+func netnsModeStringToUint8(mode string) (uint8, error) {
+ switch mode {
+ case "exclusive":
+ return 0, nil
+ case "shared":
+ return 1, nil
+ default:
+ return 0, fmt.Errorf("Invalid mode; %q", mode)
+ }
+}
+
+// RdmaSystemSetNetnsMode sets the net namespace mode for RDMA subsystem
+// Returns nil on success or appropriate error code.
+// Equivalent to: `rdma system set netns { shared | exclusive }'
+func RdmaSystemSetNetnsMode(NewMode string) error {
+ return pkgHandle.RdmaSystemSetNetnsMode(NewMode)
+}
+
+// RdmaSystemSetNetnsMode sets the net namespace mode for RDMA subsystem
+// Returns nil on success or appropriate error code.
+// Equivalent to: `rdma system set netns { shared | exclusive }'
+func (h *Handle) RdmaSystemSetNetnsMode(NewMode string) error {
+ value, err := netnsModeStringToUint8(NewMode)
+ if err != nil {
+ return err
+ }
+
+ proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_SET)
+ req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
+
+ data := nl.NewRtAttr(nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE, []byte{value})
+ req.AddData(data)
+
+ _, err = req.Execute(unix.NETLINK_RDMA, 0)
+ return err
+}
+
+// RdmaLinkSetNsFd puts the RDMA device into a new network namespace. The
+// fd must be an open file descriptor to a network namespace.
+// Similar to: `rdma dev set $dev netns $ns`
+func RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
+ return pkgHandle.RdmaLinkSetNsFd(link, fd)
+}
+
+// RdmaLinkSetNsFd puts the RDMA device into a new network namespace. The
+// fd must be an open file descriptor to a network namespace.
+// Similar to: `rdma dev set $dev netns $ns`
+func (h *Handle) RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error {
+ proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET)
+ req := h.newNetlinkRequest(proto, unix.NLM_F_ACK)
+
+ data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX,
+ nl.Uint32Attr(link.Attrs.Index))
+ req.AddData(data)
+
+ data = nl.NewRtAttr(nl.RDMA_NLDEV_NET_NS_FD, nl.Uint32Attr(fd))
+ req.AddData(data)
+
+ return execRdmaSetLink(req)
+}
diff --git a/vendor/github.com/vishvananda/netlink/route.go b/vendor/github.com/vishvananda/netlink/route.go
index 2cd58ee33..58ff1af60 100644
--- a/vendor/github.com/vishvananda/netlink/route.go
+++ b/vendor/github.com/vishvananda/netlink/route.go
@@ -47,6 +47,7 @@ type Route struct {
Encap Encap
MTU int
AdvMSS int
+ Hoplimit int
}
func (r Route) String() string {
@@ -89,6 +90,7 @@ func (r Route) Equal(x Route) bool {
r.Table == x.Table &&
r.Type == x.Type &&
r.Tos == x.Tos &&
+ r.Hoplimit == x.Hoplimit &&
r.Flags == x.Flags &&
(r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) &&
(r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) &&
diff --git a/vendor/github.com/vishvananda/netlink/route_linux.go b/vendor/github.com/vishvananda/netlink/route_linux.go
index 3f856711f..c69c595ed 100644
--- a/vendor/github.com/vishvananda/netlink/route_linux.go
+++ b/vendor/github.com/vishvananda/netlink/route_linux.go
@@ -32,6 +32,7 @@ const (
RT_FILTER_SRC
RT_FILTER_GW
RT_FILTER_TABLE
+ RT_FILTER_HOPLIMIT
)
const (
@@ -207,6 +208,7 @@ func (e *SEG6Encap) Decode(buf []byte) error {
}
buf = buf[:l] // make sure buf size upper limit is Length
typ := native.Uint16(buf[2:])
+ // LWTUNNEL_ENCAP_SEG6 has only one attr type SEG6_IPTUNNEL_SRH
if typ != nl.SEG6_IPTUNNEL_SRH {
return fmt.Errorf("unknown SEG6 Type: %d", typ)
}
@@ -259,6 +261,188 @@ func (e *SEG6Encap) Equal(x Encap) bool {
return true
}
+// SEG6LocalEncap definitions
+type SEG6LocalEncap struct {
+ Flags [nl.SEG6_LOCAL_MAX]bool
+ Action int
+ Segments []net.IP // from SRH in seg6_local_lwt
+ Table int // table id for End.T and End.DT6
+ InAddr net.IP
+ In6Addr net.IP
+ Iif int
+ Oif int
+}
+
+func (e *SEG6LocalEncap) Type() int {
+ return nl.LWTUNNEL_ENCAP_SEG6_LOCAL
+}
+func (e *SEG6LocalEncap) Decode(buf []byte) error {
+ attrs, err := nl.ParseRouteAttr(buf)
+ if err != nil {
+ return err
+ }
+ native := nl.NativeEndian()
+ for _, attr := range attrs {
+ switch attr.Attr.Type {
+ case nl.SEG6_LOCAL_ACTION:
+ e.Action = int(native.Uint32(attr.Value[0:4]))
+ e.Flags[nl.SEG6_LOCAL_ACTION] = true
+ case nl.SEG6_LOCAL_SRH:
+ e.Segments, err = nl.DecodeSEG6Srh(attr.Value[:])
+ e.Flags[nl.SEG6_LOCAL_SRH] = true
+ case nl.SEG6_LOCAL_TABLE:
+ e.Table = int(native.Uint32(attr.Value[0:4]))
+ e.Flags[nl.SEG6_LOCAL_TABLE] = true
+ case nl.SEG6_LOCAL_NH4:
+ e.InAddr = net.IP(attr.Value[0:4])
+ e.Flags[nl.SEG6_LOCAL_NH4] = true
+ case nl.SEG6_LOCAL_NH6:
+ e.In6Addr = net.IP(attr.Value[0:16])
+ e.Flags[nl.SEG6_LOCAL_NH6] = true
+ case nl.SEG6_LOCAL_IIF:
+ e.Iif = int(native.Uint32(attr.Value[0:4]))
+ e.Flags[nl.SEG6_LOCAL_IIF] = true
+ case nl.SEG6_LOCAL_OIF:
+ e.Oif = int(native.Uint32(attr.Value[0:4]))
+ e.Flags[nl.SEG6_LOCAL_OIF] = true
+ }
+ }
+ return err
+}
+func (e *SEG6LocalEncap) Encode() ([]byte, error) {
+ var err error
+ native := nl.NativeEndian()
+ res := make([]byte, 8)
+ native.PutUint16(res, 8) // length
+ native.PutUint16(res[2:], nl.SEG6_LOCAL_ACTION)
+ native.PutUint32(res[4:], uint32(e.Action))
+ if e.Flags[nl.SEG6_LOCAL_SRH] {
+ srh, err := nl.EncodeSEG6Srh(e.Segments)
+ if err != nil {
+ return nil, err
+ }
+ attr := make([]byte, 4)
+ native.PutUint16(attr, uint16(len(srh)+4))
+ native.PutUint16(attr[2:], nl.SEG6_LOCAL_SRH)
+ attr = append(attr, srh...)
+ res = append(res, attr...)
+ }
+ if e.Flags[nl.SEG6_LOCAL_TABLE] {
+ attr := make([]byte, 8)
+ native.PutUint16(attr, 8)
+ native.PutUint16(attr[2:], nl.SEG6_LOCAL_TABLE)
+ native.PutUint32(attr[4:], uint32(e.Table))
+ res = append(res, attr...)
+ }
+ if e.Flags[nl.SEG6_LOCAL_NH4] {
+ attr := make([]byte, 4)
+ native.PutUint16(attr, 8)
+ native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH4)
+ ipv4 := e.InAddr.To4()
+ if ipv4 == nil {
+ err = fmt.Errorf("SEG6_LOCAL_NH4 has invalid IPv4 address")
+ return nil, err
+ }
+ attr = append(attr, ipv4...)
+ res = append(res, attr...)
+ }
+ if e.Flags[nl.SEG6_LOCAL_NH6] {
+ attr := make([]byte, 4)
+ native.PutUint16(attr, 20)
+ native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH6)
+ attr = append(attr, e.In6Addr...)
+ res = append(res, attr...)
+ }
+ if e.Flags[nl.SEG6_LOCAL_IIF] {
+ attr := make([]byte, 8)
+ native.PutUint16(attr, 8)
+ native.PutUint16(attr[2:], nl.SEG6_LOCAL_IIF)
+ native.PutUint32(attr[4:], uint32(e.Iif))
+ res = append(res, attr...)
+ }
+ if e.Flags[nl.SEG6_LOCAL_OIF] {
+ attr := make([]byte, 8)
+ native.PutUint16(attr, 8)
+ native.PutUint16(attr[2:], nl.SEG6_LOCAL_OIF)
+ native.PutUint32(attr[4:], uint32(e.Oif))
+ res = append(res, attr...)
+ }
+ return res, err
+}
+func (e *SEG6LocalEncap) String() string {
+ strs := make([]string, 0, nl.SEG6_LOCAL_MAX)
+ strs = append(strs, fmt.Sprintf("action %s", nl.SEG6LocalActionString(e.Action)))
+
+ if e.Flags[nl.SEG6_LOCAL_TABLE] {
+ strs = append(strs, fmt.Sprintf("table %d", e.Table))
+ }
+ if e.Flags[nl.SEG6_LOCAL_NH4] {
+ strs = append(strs, fmt.Sprintf("nh4 %s", e.InAddr))
+ }
+ if e.Flags[nl.SEG6_LOCAL_NH6] {
+ strs = append(strs, fmt.Sprintf("nh6 %s", e.In6Addr))
+ }
+ if e.Flags[nl.SEG6_LOCAL_IIF] {
+ link, err := LinkByIndex(e.Iif)
+ if err != nil {
+ strs = append(strs, fmt.Sprintf("iif %d", e.Iif))
+ } else {
+ strs = append(strs, fmt.Sprintf("iif %s", link.Attrs().Name))
+ }
+ }
+ if e.Flags[nl.SEG6_LOCAL_OIF] {
+ link, err := LinkByIndex(e.Oif)
+ if err != nil {
+ strs = append(strs, fmt.Sprintf("oif %d", e.Oif))
+ } else {
+ strs = append(strs, fmt.Sprintf("oif %s", link.Attrs().Name))
+ }
+ }
+ if e.Flags[nl.SEG6_LOCAL_SRH] {
+ segs := make([]string, 0, len(e.Segments))
+ //append segment backwards (from n to 0) since seg#0 is the last segment.
+ for i := len(e.Segments); i > 0; i-- {
+ segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1]))
+ }
+ strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " ")))
+ }
+ return strings.Join(strs, " ")
+}
+func (e *SEG6LocalEncap) Equal(x Encap) bool {
+ o, ok := x.(*SEG6LocalEncap)
+ if !ok {
+ return false
+ }
+ if e == o {
+ return true
+ }
+ if e == nil || o == nil {
+ return false
+ }
+ // compare all arrays first
+ for i := range e.Flags {
+ if e.Flags[i] != o.Flags[i] {
+ return false
+ }
+ }
+ if len(e.Segments) != len(o.Segments) {
+ return false
+ }
+ for i := range e.Segments {
+ if !e.Segments[i].Equal(o.Segments[i]) {
+ return false
+ }
+ }
+ // compare values
+ if !e.InAddr.Equal(o.InAddr) || !e.In6Addr.Equal(o.In6Addr) {
+ return false
+ }
+ if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif {
+ return false
+ }
+ return true
+}
+
// RouteAdd will add a route to the system.
// Equivalent to: `ip route add $route`
func RouteAdd(route *Route) error {
@@ -335,18 +519,18 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
if err != nil {
return err
}
- rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_NEWDST, buf))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_NEWDST, buf))
}
if route.Encap != nil {
buf := make([]byte, 2)
native.PutUint16(buf, uint16(route.Encap.Type()))
- rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP_TYPE, buf))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf))
buf, err := route.Encap.Encode()
if err != nil {
return err
}
- rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP, buf))
+ rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP, buf))
}
if route.Src != nil {
@@ -410,17 +594,17 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
if err != nil {
return err
}
- children = append(children, nl.NewRtAttr(nl.RTA_NEWDST, buf))
+ children = append(children, nl.NewRtAttr(unix.RTA_NEWDST, buf))
}
if nh.Encap != nil {
buf := make([]byte, 2)
native.PutUint16(buf, uint16(nh.Encap.Type()))
- rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP_TYPE, buf))
+ children = append(children, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf))
buf, err := nh.Encap.Encode()
if err != nil {
return err
}
- children = append(children, nl.NewRtAttr(nl.RTA_ENCAP, buf))
+ children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf))
}
rtnh.Children = children
buf = append(buf, rtnh.Serialize()...)
@@ -464,6 +648,10 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg
b := nl.Uint32Attr(uint32(route.AdvMSS))
metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b))
}
+ if route.Hoplimit > 0 {
+ b := nl.Uint32Attr(uint32(route.Hoplimit))
+ metrics = append(metrics, nl.NewRtAttr(unix.RTAX_HOPLIMIT, b))
+ }
if metrics != nil {
attr := nl.NewRtAttr(unix.RTA_METRICS, nil)
@@ -574,6 +762,8 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64)
continue
}
}
+ case filterMask&RT_FILTER_HOPLIMIT != 0 && route.Hoplimit != filter.Hoplimit:
+ continue
}
}
res = append(res, route)
@@ -649,7 +839,7 @@ func deserializeRoute(m []byte) (Route, error) {
switch attr.Attr.Type {
case unix.RTA_GATEWAY:
info.Gw = net.IP(attr.Value)
- case nl.RTA_NEWDST:
+ case unix.RTA_NEWDST:
var d Destination
switch msg.Family {
case nl.FAMILY_MPLS:
@@ -659,9 +849,9 @@ func deserializeRoute(m []byte) (Route, error) {
return nil, nil, err
}
info.NewDst = d
- case nl.RTA_ENCAP_TYPE:
+ case unix.RTA_ENCAP_TYPE:
encapType = attr
- case nl.RTA_ENCAP:
+ case unix.RTA_ENCAP:
encap = attr
}
}
@@ -690,7 +880,7 @@ func deserializeRoute(m []byte) (Route, error) {
route.MultiPath = append(route.MultiPath, info)
rest = buf
}
- case nl.RTA_NEWDST:
+ case unix.RTA_NEWDST:
var d Destination
switch msg.Family {
case nl.FAMILY_MPLS:
@@ -700,9 +890,9 @@ func deserializeRoute(m []byte) (Route, error) {
return route, err
}
route.NewDst = d
- case nl.RTA_ENCAP_TYPE:
+ case unix.RTA_ENCAP_TYPE:
encapType = attr
- case nl.RTA_ENCAP:
+ case unix.RTA_ENCAP:
encap = attr
case unix.RTA_METRICS:
metrics, err := nl.ParseRouteAttr(attr.Value)
@@ -715,6 +905,8 @@ func deserializeRoute(m []byte) (Route, error) {
route.MTU = int(native.Uint32(metric.Value[0:4]))
case unix.RTAX_ADVMSS:
route.AdvMSS = int(native.Uint32(metric.Value[0:4]))
+ case unix.RTAX_HOPLIMIT:
+ route.Hoplimit = int(native.Uint32(metric.Value[0:4]))
}
}
}
@@ -734,6 +926,11 @@ func deserializeRoute(m []byte) (Route, error) {
if err := e.Decode(encap.Value); err != nil {
return route, err
}
+ case nl.LWTUNNEL_ENCAP_SEG6_LOCAL:
+ e = &SEG6LocalEncap{}
+ if err := e.Decode(encap.Value); err != nil {
+ return route, err
+ }
}
route.Encap = e
}
@@ -840,13 +1037,19 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <
go func() {
defer close(ch)
for {
- msgs, err := s.Receive()
+ msgs, from, err := s.Receive()
if err != nil {
if cberr != nil {
cberr(err)
}
return
}
+ if from.Pid != nl.PidKernel {
+ if cberr != nil {
+ cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel))
+ }
+ continue
+ }
for _, m := range msgs {
if m.Header.Type == unix.NLMSG_DONE {
continue
diff --git a/vendor/github.com/vishvananda/netlink/rule_linux.go b/vendor/github.com/vishvananda/netlink/rule_linux.go
index 6238ae458..e12569fe4 100644
--- a/vendor/github.com/vishvananda/netlink/rule_linux.go
+++ b/vendor/github.com/vishvananda/netlink/rule_linux.go
@@ -144,7 +144,7 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
req.AddData(nl.NewRtAttr(nl.FRA_OIFNAME, []byte(rule.OifName)))
}
if rule.Goto >= 0 {
- msg.Type = nl.FR_ACT_NOP
+ msg.Type = nl.FR_ACT_GOTO
b := make([]byte, 4)
native.PutUint32(b, uint32(rule.Goto))
req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b))
diff --git a/vendor/github.com/vishvananda/netlink/socket_linux.go b/vendor/github.com/vishvananda/netlink/socket_linux.go
index 99e9fb4d8..c4d89c17e 100644
--- a/vendor/github.com/vishvananda/netlink/socket_linux.go
+++ b/vendor/github.com/vishvananda/netlink/socket_linux.go
@@ -141,10 +141,13 @@ func SocketGet(local, remote net.Addr) (*Socket, error) {
},
})
s.Send(req)
- msgs, err := s.Receive()
+ msgs, from, err := s.Receive()
if err != nil {
return nil, err
}
+ if from.Pid != nl.PidKernel {
+ return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
+ }
if len(msgs) == 0 {
return nil, errors.New("no message nor error from netlink")
}
diff --git a/vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go
index efe72ddf2..985d3a915 100644
--- a/vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go
+++ b/vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go
@@ -54,11 +54,15 @@ func XfrmMonitor(ch chan<- XfrmMsg, done <-chan struct{}, errorChan chan<- error
go func() {
defer close(ch)
for {
- msgs, err := s.Receive()
+ msgs, from, err := s.Receive()
if err != nil {
errorChan <- err
return
}
+ if from.Pid != nl.PidKernel {
+ errorChan <- fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)
+ return
+ }
for _, m := range msgs {
switch m.Header.Type {
case nl.XFRM_MSG_EXPIRE:
diff --git a/vendor/github.com/vishvananda/netlink/xfrm_policy.go b/vendor/github.com/vishvananda/netlink/xfrm_policy.go
index c97ec43a2..6219d2772 100644
--- a/vendor/github.com/vishvananda/netlink/xfrm_policy.go
+++ b/vendor/github.com/vishvananda/netlink/xfrm_policy.go
@@ -35,6 +35,25 @@ func (d Dir) String() string {
return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN)
}
+// PolicyAction is an enum representing an ipsec policy action.
+type PolicyAction uint8
+
+const (
+ XFRM_POLICY_ALLOW PolicyAction = 0
+ XFRM_POLICY_BLOCK PolicyAction = 1
+)
+
+func (a PolicyAction) String() string {
+ switch a {
+ case XFRM_POLICY_ALLOW:
+ return "allow"
+ case XFRM_POLICY_BLOCK:
+ return "block"
+ default:
+ return fmt.Sprintf("action %d", a)
+ }
+}
+
// XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec
// policy. These rules are matched with XfrmState to determine encryption
// and authentication algorithms.
@@ -64,11 +83,14 @@ type XfrmPolicy struct {
Dir Dir
Priority int
Index int
+ Action PolicyAction
+ Ifindex int
+ Ifid int
Mark *XfrmMark
Tmpls []XfrmPolicyTmpl
}
func (p XfrmPolicy) String() string {
- return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Mark: %s, Tmpls: %s}",
- p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Mark, p.Tmpls)
+ return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Action: %s, Ifindex: %d, Ifid: %d, Mark: %s, Tmpls: %s}",
+ p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Action, p.Ifindex, p.Ifid, p.Mark, p.Tmpls)
}
diff --git a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go
index fde0c2ca5..a4e132ef5 100644
--- a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go
+++ b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go
@@ -27,6 +27,7 @@ func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
if sel.Sport != 0 {
sel.SportMask = ^uint16(0)
}
+ sel.Ifindex = int32(policy.Ifindex)
}
// XfrmPolicyAdd will add an xfrm policy to the system.
@@ -61,6 +62,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
msg.Priority = uint32(policy.Priority)
msg.Index = uint32(policy.Index)
msg.Dir = uint8(policy.Dir)
+ msg.Action = uint8(policy.Action)
msg.Lft.SoftByteLimit = nl.XFRM_INF
msg.Lft.HardByteLimit = nl.XFRM_INF
msg.Lft.SoftPacketLimit = nl.XFRM_INF
@@ -90,6 +92,9 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
req.AddData(out)
}
+ ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
+ req.AddData(ifId)
+
_, err := req.Execute(unix.NETLINK_XFRM, 0)
return err
}
@@ -183,6 +188,9 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
req.AddData(out)
}
+ ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid)))
+ req.AddData(ifId)
+
resType := nl.XFRM_MSG_NEWPOLICY
if nlProto == nl.XFRM_MSG_DELPOLICY {
resType = 0
@@ -197,12 +205,7 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo
return nil, err
}
- p, err := parseXfrmPolicy(msgs[0], FAMILY_ALL)
- if err != nil {
- return nil, err
- }
-
- return p, nil
+ return parseXfrmPolicy(msgs[0], FAMILY_ALL)
}
func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
@@ -220,9 +223,11 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
policy.Proto = Proto(msg.Sel.Proto)
policy.DstPort = int(nl.Swap16(msg.Sel.Dport))
policy.SrcPort = int(nl.Swap16(msg.Sel.Sport))
+ policy.Ifindex = int(msg.Sel.Ifindex)
policy.Priority = int(msg.Priority)
policy.Index = int(msg.Index)
policy.Dir = Dir(msg.Dir)
+ policy.Action = PolicyAction(msg.Action)
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
if err != nil {
@@ -249,6 +254,8 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
policy.Mark = new(XfrmMark)
policy.Mark.Value = mark.Value
policy.Mark.Mask = mark.Mask
+ case nl.XFRMA_IF_ID:
+ policy.Ifid = int(native.Uint32(attr.Value))
}
}
diff --git a/vendor/github.com/vishvananda/netlink/xfrm_state.go b/vendor/github.com/vishvananda/netlink/xfrm_state.go
index d14740dc5..483d8934a 100644
--- a/vendor/github.com/vishvananda/netlink/xfrm_state.go
+++ b/vendor/github.com/vishvananda/netlink/xfrm_state.go
@@ -94,6 +94,8 @@ type XfrmState struct {
Limits XfrmStateLimits
Statistics XfrmStateStats
Mark *XfrmMark
+ OutputMark int
+ Ifid int
Auth *XfrmStateAlgo
Crypt *XfrmStateAlgo
Aead *XfrmStateAlgo
@@ -102,8 +104,8 @@ type XfrmState struct {
}
func (sa XfrmState) String() string {
- return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t",
- sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN)
+ return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, OutputMark: %d, Ifid: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t",
+ sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.OutputMark, sa.Ifid, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN)
}
func (sa XfrmState) Print(stats bool) string {
if !stats {
diff --git a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go
index 5dfdb33e4..66c99423c 100644
--- a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go
+++ b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go
@@ -158,6 +158,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow))
req.AddData(out)
}
+ if state.OutputMark != 0 {
+ out := nl.NewRtAttr(nl.XFRMA_OUTPUT_MARK, nl.Uint32Attr(uint32(state.OutputMark)))
+ req.AddData(out)
+ }
+
+ ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
+ req.AddData(ifId)
_, err := req.Execute(unix.NETLINK_XFRM, 0)
return err
@@ -184,12 +191,7 @@ func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
return nil, err
}
- s, err := parseXfrmState(msgs[0], FAMILY_ALL)
- if err != nil {
- return nil, err
- }
-
- return s, err
+ return parseXfrmState(msgs[0], FAMILY_ALL)
}
// XfrmStateDel will delete an xfrm state from the system. Note that
@@ -275,6 +277,9 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState
req.AddData(out)
}
+ ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid)))
+ req.AddData(ifId)
+
resType := nl.XFRM_MSG_NEWSA
if nlProto == nl.XFRM_MSG_DELSA {
resType = 0
@@ -372,6 +377,10 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
state.Mark = new(XfrmMark)
state.Mark.Value = mark.Value
state.Mark.Mask = mark.Mask
+ case nl.XFRMA_OUTPUT_MARK:
+ state.OutputMark = int(native.Uint32(attr.Value))
+ case nl.XFRMA_IF_ID:
+ state.Ifid = int(native.Uint32(attr.Value))
}
}
@@ -394,11 +403,7 @@ func (h *Handle) XfrmStateFlush(proto Proto) error {
req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)})
_, err := req.Execute(unix.NETLINK_XFRM, 0)
- if err != nil {
- return err
- }
-
- return nil
+ return err
}
func limitsToLft(lmts XfrmStateLimits, lft *nl.XfrmLifetimeCfg) {
diff --git a/vendor/github.com/vishvananda/netns/go.mod b/vendor/github.com/vishvananda/netns/go.mod
new file mode 100644
index 000000000..8221f782c
--- /dev/null
+++ b/vendor/github.com/vishvananda/netns/go.mod
@@ -0,0 +1,3 @@
+module github.com/vishvananda/netns
+
+go 1.12
diff --git a/vendor/github.com/vishvananda/netns/go.sum b/vendor/github.com/vishvananda/netns/go.sum
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/github.com/vishvananda/netns/go.sum
diff --git a/vendor/gopkg.in/yaml.v2/scannerc.go b/vendor/gopkg.in/yaml.v2/scannerc.go
index b33bdbaec..0b9bb6030 100644
--- a/vendor/gopkg.in/yaml.v2/scannerc.go
+++ b/vendor/gopkg.in/yaml.v2/scannerc.go
@@ -626,32 +626,18 @@ func trace(args ...interface{}) func() {
func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
// While we need more tokens to fetch, do it.
for {
- // Check if we really need to fetch more tokens.
- need_more_tokens := false
-
- if parser.tokens_head == len(parser.tokens) {
- // Queue is empty.
- need_more_tokens = true
- } else {
- // Check if any potential simple key may occupy the head position.
- for i := len(parser.simple_keys) - 1; i >= 0; i-- {
- simple_key := &parser.simple_keys[i]
- if simple_key.token_number < parser.tokens_parsed {
- break
- }
- if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
- return false
- } else if valid && simple_key.token_number == parser.tokens_parsed {
- need_more_tokens = true
- break
- }
+ if parser.tokens_head != len(parser.tokens) {
+ // If queue is non-empty, check if any potential simple key may
+ // occupy the head position.
+ head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
+ if !ok {
+ break
+ } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
+ return false
+ } else if !valid {
+ break
}
}
-
- // We are finished.
- if !need_more_tokens {
- break
- }
// Fetch the next token.
if !yaml_parser_fetch_next_token(parser) {
return false
@@ -883,6 +869,7 @@ func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
return false
}
parser.simple_keys[len(parser.simple_keys)-1] = simple_key
+ parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
}
return true
}
@@ -897,9 +884,10 @@ func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
"while scanning a simple key", parser.simple_keys[i].mark,
"could not find expected ':'")
}
+ // Remove the key from the stack.
+ parser.simple_keys[i].possible = false
+ delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
}
- // Remove the key from the stack.
- parser.simple_keys[i].possible = false
return true
}
@@ -930,7 +918,9 @@ func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
if parser.flow_level > 0 {
parser.flow_level--
- parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]
+ last := len(parser.simple_keys) - 1
+ delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
+ parser.simple_keys = parser.simple_keys[:last]
}
return true
}
@@ -1007,6 +997,8 @@ func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
// Initialize the simple key stack.
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+ parser.simple_keys_by_tok = make(map[int]int)
+
// A simple key is allowed at the beginning of the stream.
parser.simple_key_allowed = true
@@ -1310,6 +1302,7 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
// Remove the simple key.
simple_key.possible = false
+ delete(parser.simple_keys_by_tok, simple_key.token_number)
// A simple key cannot follow another simple key.
parser.simple_key_allowed = false
diff --git a/vendor/gopkg.in/yaml.v2/yamlh.go b/vendor/gopkg.in/yaml.v2/yamlh.go
index e25cee563..f6a9c8e34 100644
--- a/vendor/gopkg.in/yaml.v2/yamlh.go
+++ b/vendor/gopkg.in/yaml.v2/yamlh.go
@@ -579,6 +579,7 @@ type yaml_parser_t struct {
simple_key_allowed bool // May a simple key occur at the current position?
simple_keys []yaml_simple_key_t // The stack of simple keys.
+ simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
// Parser stuff
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 8fa756fbb..6385ab250 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -54,7 +54,7 @@ github.com/containernetworking/cni/pkg/types/020
github.com/containernetworking/cni/pkg/types/current
github.com/containernetworking/cni/pkg/utils
github.com/containernetworking/cni/pkg/version
-# github.com/containernetworking/plugins v0.8.2
+# github.com/containernetworking/plugins v0.8.5
github.com/containernetworking/plugins/pkg/ip
github.com/containernetworking/plugins/pkg/ns
github.com/containernetworking/plugins/pkg/utils/hwaddr
@@ -78,7 +78,7 @@ github.com/containers/buildah/util
# github.com/containers/common v0.0.7
github.com/containers/common/pkg/cgroups
github.com/containers/common/pkg/unshare
-# github.com/containers/conmon v2.0.9+incompatible
+# github.com/containers/conmon v2.0.10+incompatible
github.com/containers/conmon/runner/config
# github.com/containers/image/v5 v5.1.0
github.com/containers/image/v5/copy
@@ -138,7 +138,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
-# github.com/containers/storage v1.15.5
+# github.com/containers/storage v1.15.7
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs
@@ -178,7 +178,7 @@ github.com/containers/storage/pkg/stringutils
github.com/containers/storage/pkg/system
github.com/containers/storage/pkg/tarlog
github.com/containers/storage/pkg/truncindex
-# github.com/coreos/go-iptables v0.4.2
+# github.com/coreos/go-iptables v0.4.5
github.com/coreos/go-iptables/iptables
# github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
github.com/coreos/go-systemd/activation
@@ -261,8 +261,6 @@ github.com/docker/spdystream
github.com/docker/spdystream/spdy
# github.com/etcd-io/bbolt v1.3.3
github.com/etcd-io/bbolt
-# github.com/fatih/camelcase v1.0.0
-github.com/fatih/camelcase
# github.com/fsnotify/fsnotify v1.4.7
github.com/fsnotify/fsnotify
# github.com/fsouza/go-dockerclient v1.6.0
@@ -312,9 +310,9 @@ github.com/imdario/mergo
github.com/inconshreveable/mousetrap
# github.com/ishidawataru/sctp v0.0.0-20180918013207-6e2cb1366111
github.com/ishidawataru/sctp
-# github.com/json-iterator/go v1.1.8
+# github.com/json-iterator/go v1.1.9
github.com/json-iterator/go
-# github.com/klauspost/compress v1.9.4
+# github.com/klauspost/compress v1.9.7
github.com/klauspost/compress/flate
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0
@@ -325,7 +323,7 @@ github.com/klauspost/compress/zstd/internal/xxhash
github.com/klauspost/pgzip
# github.com/konsorten/go-windows-terminal-sequences v1.0.2
github.com/konsorten/go-windows-terminal-sequences
-# github.com/mattn/go-shellwords v1.0.6
+# github.com/mattn/go-shellwords v1.0.7
github.com/mattn/go-shellwords
# github.com/matttproud/golang_protobuf_extensions v1.0.1
github.com/matttproud/golang_protobuf_extensions/pbutil
@@ -423,7 +421,7 @@ github.com/opentracing/opentracing-go/log
# github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913
github.com/ostreedev/ostree-go/pkg/glibobject
github.com/ostreedev/ostree-go/pkg/otbuiltin
-# github.com/pkg/errors v0.9.0
+# github.com/pkg/errors v0.9.1
github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.0
github.com/pmezard/go-difflib/difflib
@@ -478,11 +476,12 @@ github.com/stretchr/testify/require
github.com/syndtr/gocapability/capability
# github.com/tchap/go-patricia v2.3.0+incompatible
github.com/tchap/go-patricia/patricia
-# github.com/uber/jaeger-client-go v2.20.1+incompatible
+# github.com/uber/jaeger-client-go v2.22.1+incompatible
github.com/uber/jaeger-client-go
github.com/uber/jaeger-client-go/config
github.com/uber/jaeger-client-go/internal/baggage
github.com/uber/jaeger-client-go/internal/baggage/remote
+github.com/uber/jaeger-client-go/internal/reporterstats
github.com/uber/jaeger-client-go/internal/spanlog
github.com/uber/jaeger-client-go/internal/throttler
github.com/uber/jaeger-client-go/internal/throttler/remote
@@ -516,10 +515,10 @@ github.com/vbauerster/mpb/v4
github.com/vbauerster/mpb/v4/cwriter
github.com/vbauerster/mpb/v4/decor
github.com/vbauerster/mpb/v4/internal
-# github.com/vishvananda/netlink v1.0.0
+# github.com/vishvananda/netlink v1.1.0
github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl
-# github.com/vishvananda/netns v0.0.0-20190625233234-7109fa855b0f
+# github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
github.com/vishvananda/netns
# github.com/xeipuuv/gojsonpointer v0.0.0-20190809123943-df4f5c81cb3b
github.com/xeipuuv/gojsonpointer
@@ -626,11 +625,11 @@ gopkg.in/square/go-jose.v2/cipher
gopkg.in/square/go-jose.v2/json
# gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
gopkg.in/tomb.v1
-# gopkg.in/yaml.v2 v2.2.7
+# gopkg.in/yaml.v2 v2.2.8
gopkg.in/yaml.v2
-# k8s.io/api v0.17.0
+# k8s.io/api v0.17.2
k8s.io/api/core/v1
-# k8s.io/apimachinery v0.17.0
+# k8s.io/apimachinery v0.17.2
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/resource
k8s.io/apimachinery/pkg/apis/meta/v1