mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Merge pull request #103483 from odinuge/revert-102508-runc-1.0
Revert "Update runc to 1.0.0"
This commit is contained in:
commit
eae87bfe7e
@ -1,4 +1,4 @@
|
||||
= vendor/github.com/bits-and-blooms/bitset licensed under: =
|
||||
= vendor/github.com/willf/bitset licensed under: =
|
||||
|
||||
Copyright (c) 2014 Will Fitzgerald. All rights reserved.
|
||||
|
||||
@ -28,4 +28,4 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
= vendor/github.com/bits-and-blooms/bitset/LICENSE 0d2b5d66dabaff0df8e1ffe191a21bd1
|
||||
= vendor/github.com/willf/bitset/LICENSE 0d2b5d66dabaff0df8e1ffe191a21bd1
|
14
go.mod
14
go.mod
@ -67,8 +67,8 @@ require (
|
||||
github.com/onsi/ginkgo v1.14.0
|
||||
github.com/onsi/gomega v1.10.1
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/runc v1.0.0
|
||||
github.com/opencontainers/selinux v1.8.2
|
||||
github.com/opencontainers/runc v1.0.0-rc95
|
||||
github.com/opencontainers/selinux v1.8.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pmezard/go-difflib v1.0.0
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
@ -179,7 +179,6 @@ replace (
|
||||
github.com/benbjohnson/clock => github.com/benbjohnson/clock v1.0.3
|
||||
github.com/beorn7/perks => github.com/beorn7/perks v1.0.1
|
||||
github.com/bgentry/speakeasy => github.com/bgentry/speakeasy v0.1.0
|
||||
github.com/bits-and-blooms/bitset => github.com/bits-and-blooms/bitset v1.2.0
|
||||
github.com/bketelsen/crypt => github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c
|
||||
github.com/blang/semver => github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/boltdb/bolt => github.com/boltdb/bolt v1.3.1
|
||||
@ -191,7 +190,7 @@ replace (
|
||||
github.com/chzyer/logex => github.com/chzyer/logex v1.1.10
|
||||
github.com/chzyer/readline => github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
||||
github.com/chzyer/test => github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1
|
||||
github.com/cilium/ebpf => github.com/cilium/ebpf v0.6.1
|
||||
github.com/cilium/ebpf => github.com/cilium/ebpf v0.5.0
|
||||
github.com/clusterhq/flocker-go => github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313
|
||||
github.com/cncf/udpa/go => github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403
|
||||
github.com/cockroachdb/datadriven => github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5
|
||||
@ -367,9 +366,9 @@ replace (
|
||||
github.com/onsi/gomega => github.com/onsi/gomega v1.10.1
|
||||
github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1
|
||||
github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.0
|
||||
github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.0-rc95
|
||||
github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
|
||||
github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.8.2
|
||||
github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.8.0
|
||||
github.com/opentracing/opentracing-go => github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/pascaldekloe/goe => github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c
|
||||
github.com/pelletier/go-toml => github.com/pelletier/go-toml v1.2.0
|
||||
@ -395,7 +394,7 @@ replace (
|
||||
github.com/seccomp/libseccomp-golang => github.com/seccomp/libseccomp-golang v0.9.1
|
||||
github.com/sergi/go-diff => github.com/sergi/go-diff v1.1.0
|
||||
github.com/shurcooL/sanitized_anchor_name => github.com/shurcooL/sanitized_anchor_name v1.0.0
|
||||
github.com/sirupsen/logrus => github.com/sirupsen/logrus v1.8.1
|
||||
github.com/sirupsen/logrus => github.com/sirupsen/logrus v1.7.0
|
||||
github.com/smartystreets/assertions => github.com/smartystreets/assertions v1.1.0
|
||||
github.com/smartystreets/goconvey => github.com/smartystreets/goconvey v1.6.4
|
||||
github.com/soheilhy/cmux => github.com/soheilhy/cmux v0.1.5
|
||||
@ -417,6 +416,7 @@ replace (
|
||||
github.com/vishvananda/netlink => github.com/vishvananda/netlink v1.1.0
|
||||
github.com/vishvananda/netns => github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae
|
||||
github.com/vmware/govmomi => github.com/vmware/govmomi v0.20.3
|
||||
github.com/willf/bitset => github.com/willf/bitset v1.1.11
|
||||
github.com/xiang90/probing => github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2
|
||||
github.com/xlab/treeprint => github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca
|
||||
github.com/yuin/goldmark => github.com/yuin/goldmark v1.3.5
|
||||
|
20
go.sum
20
go.sum
@ -67,8 +67,6 @@ github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiU
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bits-and-blooms/bitset v1.2.0 h1:Kn4yilvwNtMACtf1eYDlG8H77R07mZSPbMjLyS07ChA=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
@ -86,8 +84,8 @@ github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d8
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cilium/ebpf v0.6.1 h1:n6ZUOkSFi6OwcMeTCFaDQx2Onx2rEikQo69315MNbdc=
|
||||
github.com/cilium/ebpf v0.6.1/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.5.0 h1:E1KshmrMEtkMP2UjlWzfmUV1owWY+BnbL5FxxuatnrU=
|
||||
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313 h1:eIHD9GNM3Hp7kcRW5mvcz7WTR3ETeoYYKwpgA04kaXE=
|
||||
github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@ -374,12 +372,12 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opencontainers/runc v1.0.0 h1:QOhAQAYUlKeofuyeKdR6ITvOnXLPbEAjPMjz9wCUXcU=
|
||||
github.com/opencontainers/runc v1.0.0/go.mod h1:MU2S3KEB2ZExnhnAQYbwjdYV6HwKtDlNbA2Z2OeNDeA=
|
||||
github.com/opencontainers/runc v1.0.0-rc95 h1:RMuWVfY3E1ILlVsC3RhIq38n4sJtlOFwU9gfFZSqrd0=
|
||||
github.com/opencontainers/runc v1.0.0-rc95/go.mod h1:z+bZxa/+Tz/FmYVWkhUajJdzFeOqjc5vrqskhVyHGUM=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.8.2 h1:c4ca10UMgRcvZ6h0K4HtS15UaVSBEaE+iln2LVpAuGc=
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
|
||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
@ -421,8 +419,8 @@ github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||
@ -457,6 +455,8 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae h1:4hwBBUfQCFe3C
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vmware/govmomi v0.20.3 h1:gpw/0Ku+6RgF3jsi7fnCLmlcikBHfKBCUcu1qgc16OU=
|
||||
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
|
||||
github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE=
|
||||
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI=
|
||||
|
@ -33,6 +33,7 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
cgroupsystemd "github.com/opencontainers/runc/libcontainer/cgroups/systemd"
|
||||
libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs"
|
||||
libcontainerdevices "github.com/opencontainers/runc/libcontainer/devices"
|
||||
"k8s.io/klog/v2"
|
||||
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||
|
||||
@ -375,6 +376,15 @@ func getSupportedUnifiedControllers() sets.String {
|
||||
|
||||
func (m *cgroupManagerImpl) toResources(resourceConfig *ResourceConfig) *libcontainerconfigs.Resources {
|
||||
resources := &libcontainerconfigs.Resources{
|
||||
Devices: []*libcontainerdevices.Rule{
|
||||
{
|
||||
Type: 'a',
|
||||
Permissions: "rwm",
|
||||
Allow: true,
|
||||
Minor: libcontainerdevices.Wildcard,
|
||||
Major: libcontainerdevices.Wildcard,
|
||||
},
|
||||
},
|
||||
SkipDevices: true,
|
||||
}
|
||||
if resourceConfig == nil {
|
||||
|
@ -38,6 +38,7 @@ import (
|
||||
utilio "k8s.io/utils/io"
|
||||
utilpath "k8s.io/utils/path"
|
||||
|
||||
libcontainerdevices "github.com/opencontainers/runc/libcontainer/devices"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
@ -392,6 +393,15 @@ func createManager(containerName string) (cgroups.Manager, error) {
|
||||
Parent: "/",
|
||||
Name: containerName,
|
||||
Resources: &configs.Resources{
|
||||
Devices: []*libcontainerdevices.Rule{
|
||||
{
|
||||
Type: 'a',
|
||||
Permissions: "rwm",
|
||||
Allow: true,
|
||||
Minor: libcontainerdevices.Wildcard,
|
||||
Major: libcontainerdevices.Wildcard,
|
||||
},
|
||||
},
|
||||
SkipDevices: true,
|
||||
},
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
libcontainerdevices "github.com/opencontainers/runc/libcontainer/devices"
|
||||
utilversion "k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/klog/v2"
|
||||
@ -126,6 +127,15 @@ func createCgroupManager(name string) (cgroups.Manager, error) {
|
||||
Memory: int64(memoryLimit),
|
||||
MemorySwap: -1,
|
||||
SkipDevices: true,
|
||||
Devices: []*libcontainerdevices.Rule{
|
||||
{
|
||||
Minor: libcontainerdevices.Wildcard,
|
||||
Major: libcontainerdevices.Wildcard,
|
||||
Type: 'a',
|
||||
Permissions: "rwm",
|
||||
Allow: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return cgroupfs.NewManager(cg, nil, false), nil
|
||||
|
@ -383,9 +383,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
@ -23,7 +23,6 @@ require (
|
||||
github.com/hashicorp/golang-lru v0.5.1
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
go.etcd.io/etcd/api/v3 v3.5.0
|
||||
|
3
staging/src/k8s.io/apiserver/go.sum
generated
3
staging/src/k8s.io/apiserver/go.sum
generated
@ -377,9 +377,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
3
staging/src/k8s.io/cloud-provider/go.sum
generated
3
staging/src/k8s.io/cloud-provider/go.sum
generated
@ -372,9 +372,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
3
staging/src/k8s.io/controller-manager/go.sum
generated
3
staging/src/k8s.io/controller-manager/go.sum
generated
@ -480,9 +480,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
3
staging/src/k8s.io/kube-aggregator/go.sum
generated
3
staging/src/k8s.io/kube-aggregator/go.sum
generated
@ -373,9 +373,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
@ -324,7 +324,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
1
staging/src/k8s.io/legacy-cloud-providers/go.sum
generated
1
staging/src/k8s.io/legacy-cloud-providers/go.sum
generated
@ -380,7 +380,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
1
staging/src/k8s.io/pod-security-admission/go.sum
generated
1
staging/src/k8s.io/pod-security-admission/go.sum
generated
@ -336,7 +336,6 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
3
staging/src/k8s.io/sample-apiserver/go.sum
generated
3
staging/src/k8s.io/sample-apiserver/go.sum
generated
@ -370,9 +370,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
3
vendor/github.com/bits-and-blooms/bitset/go.mod
generated
vendored
3
vendor/github.com/bits-and-blooms/bitset/go.mod
generated
vendored
@ -1,3 +0,0 @@
|
||||
module github.com/bits-and-blooms/bitset
|
||||
|
||||
go 1.14
|
21
vendor/github.com/cilium/ebpf/CONTRIBUTING.md
generated
vendored
21
vendor/github.com/cilium/ebpf/CONTRIBUTING.md
generated
vendored
@ -18,23 +18,6 @@ reason about the proposed changes.
|
||||
## Running the tests
|
||||
|
||||
Many of the tests require privileges to set resource limits and load eBPF code.
|
||||
The easiest way to obtain these is to run the tests with `sudo`.
|
||||
|
||||
To test the current package with your local kernel you can simply run:
|
||||
```
|
||||
go test -exec sudo ./...
|
||||
```
|
||||
|
||||
To test the current package with a different kernel version you can use the [run-tests.sh](run-tests.sh) script.
|
||||
It requires [virtme](https://github.com/amluto/virtme) and qemu to be installed.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Run all tests on a 5.4 kernel
|
||||
./run-tests.sh 5.4
|
||||
|
||||
# Run a subset of tests:
|
||||
./run-tests.sh 5.4 go test ./link
|
||||
```
|
||||
The easiest way to obtain these is to run the tests with `sudo`:
|
||||
|
||||
sudo go test ./...
|
7
vendor/github.com/cilium/ebpf/Makefile
generated
vendored
7
vendor/github.com/cilium/ebpf/Makefile
generated
vendored
@ -1,7 +1,7 @@
|
||||
# The development version of clang is distributed as the 'clang' binary,
|
||||
# while stable/released versions have a version number attached.
|
||||
# Pin the default clang to a stable version.
|
||||
CLANG ?= clang-12
|
||||
CLANG ?= clang-11
|
||||
CFLAGS := -target bpf -O2 -g -Wall -Werror $(CFLAGS)
|
||||
|
||||
# Obtain an absolute path to the directory of the Makefile.
|
||||
@ -17,7 +17,7 @@ VERSION := $(shell cat ${REPODIR}/testdata/docker/VERSION)
|
||||
TARGETS := \
|
||||
testdata/loader-clang-7 \
|
||||
testdata/loader-clang-9 \
|
||||
testdata/loader-$(CLANG) \
|
||||
testdata/loader-clang-11 \
|
||||
testdata/invalid_map \
|
||||
testdata/raw_tracepoint \
|
||||
testdata/invalid_map_static \
|
||||
@ -33,7 +33,6 @@ TARGETS := \
|
||||
docker-all:
|
||||
docker run --rm --user "${UIDGID}" \
|
||||
-v "${REPODIR}":/ebpf -w /ebpf --env MAKEFLAGS \
|
||||
--env CFLAGS="-fdebug-prefix-map=/ebpf=." \
|
||||
"${IMAGE}:${VERSION}" \
|
||||
make all
|
||||
|
||||
@ -48,8 +47,6 @@ clean:
|
||||
-$(RM) internal/btf/testdata/*.elf
|
||||
|
||||
all: $(addsuffix -el.elf,$(TARGETS)) $(addsuffix -eb.elf,$(TARGETS))
|
||||
ln -srf testdata/loader-$(CLANG)-el.elf testdata/loader-el.elf
|
||||
ln -srf testdata/loader-$(CLANG)-eb.elf testdata/loader-eb.elf
|
||||
|
||||
testdata/loader-%-el.elf: testdata/loader.c
|
||||
$* $(CFLAGS) -mlittle-endian -c $< -o $@
|
||||
|
32
vendor/github.com/cilium/ebpf/asm/instruction.go
generated
vendored
32
vendor/github.com/cilium/ebpf/asm/instruction.go
generated
vendored
@ -57,7 +57,7 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
|
||||
return 0, fmt.Errorf("can't unmarshal registers: %s", err)
|
||||
}
|
||||
|
||||
if !bi.OpCode.IsDWordLoad() {
|
||||
if !bi.OpCode.isDWordLoad() {
|
||||
return InstructionSize, nil
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error)
|
||||
return 0, errors.New("invalid opcode")
|
||||
}
|
||||
|
||||
isDWordLoad := ins.OpCode.IsDWordLoad()
|
||||
isDWordLoad := ins.OpCode.isDWordLoad()
|
||||
|
||||
cons := int32(ins.Constant)
|
||||
if isDWordLoad {
|
||||
@ -123,7 +123,7 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error)
|
||||
//
|
||||
// Returns an error if the instruction doesn't load a map.
|
||||
func (ins *Instruction) RewriteMapPtr(fd int) error {
|
||||
if !ins.OpCode.IsDWordLoad() {
|
||||
if !ins.OpCode.isDWordLoad() {
|
||||
return fmt.Errorf("%s is not a 64 bit load", ins.OpCode)
|
||||
}
|
||||
|
||||
@ -138,19 +138,15 @@ func (ins *Instruction) RewriteMapPtr(fd int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MapPtr returns the map fd for this instruction.
|
||||
//
|
||||
// The result is undefined if the instruction is not a load from a map,
|
||||
// see IsLoadFromMap.
|
||||
func (ins *Instruction) MapPtr() int {
|
||||
return int(int32(uint64(ins.Constant) & math.MaxUint32))
|
||||
func (ins *Instruction) mapPtr() uint32 {
|
||||
return uint32(uint64(ins.Constant) & math.MaxUint32)
|
||||
}
|
||||
|
||||
// RewriteMapOffset changes the offset of a direct load from a map.
|
||||
//
|
||||
// Returns an error if the instruction is not a direct load.
|
||||
func (ins *Instruction) RewriteMapOffset(offset uint32) error {
|
||||
if !ins.OpCode.IsDWordLoad() {
|
||||
if !ins.OpCode.isDWordLoad() {
|
||||
return fmt.Errorf("%s is not a 64 bit load", ins.OpCode)
|
||||
}
|
||||
|
||||
@ -167,10 +163,10 @@ func (ins *Instruction) mapOffset() uint32 {
|
||||
return uint32(uint64(ins.Constant) >> 32)
|
||||
}
|
||||
|
||||
// IsLoadFromMap returns true if the instruction loads from a map.
|
||||
// isLoadFromMap returns true if the instruction loads from a map.
|
||||
//
|
||||
// This covers both loading the map pointer and direct map value loads.
|
||||
func (ins *Instruction) IsLoadFromMap() bool {
|
||||
func (ins *Instruction) isLoadFromMap() bool {
|
||||
return ins.OpCode == LoadImmOp(DWord) && (ins.Src == PseudoMapFD || ins.Src == PseudoMapValue)
|
||||
}
|
||||
|
||||
@ -181,12 +177,6 @@ func (ins *Instruction) IsFunctionCall() bool {
|
||||
return ins.OpCode.JumpOp() == Call && ins.Src == PseudoCall
|
||||
}
|
||||
|
||||
// IsConstantLoad returns true if the instruction loads a constant of the
|
||||
// given size.
|
||||
func (ins *Instruction) IsConstantLoad(size Size) bool {
|
||||
return ins.OpCode == LoadImmOp(size) && ins.Src == R0 && ins.Offset == 0
|
||||
}
|
||||
|
||||
// Format implements fmt.Formatter.
|
||||
func (ins Instruction) Format(f fmt.State, c rune) {
|
||||
if c != 'v' {
|
||||
@ -207,8 +197,8 @@ func (ins Instruction) Format(f fmt.State, c rune) {
|
||||
return
|
||||
}
|
||||
|
||||
if ins.IsLoadFromMap() {
|
||||
fd := ins.MapPtr()
|
||||
if ins.isLoadFromMap() {
|
||||
fd := int32(ins.mapPtr())
|
||||
switch ins.Src {
|
||||
case PseudoMapFD:
|
||||
fmt.Fprintf(f, "LoadMapPtr dst: %s fd: %d", ins.Dst, fd)
|
||||
@ -413,7 +403,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
|
||||
func (insns Instructions) Tag(bo binary.ByteOrder) (string, error) {
|
||||
h := sha1.New()
|
||||
for i, ins := range insns {
|
||||
if ins.IsLoadFromMap() {
|
||||
if ins.isLoadFromMap() {
|
||||
ins.Constant = 0
|
||||
}
|
||||
_, err := ins.Marshal(h, bo)
|
||||
|
2
vendor/github.com/cilium/ebpf/asm/load_store.go
generated
vendored
2
vendor/github.com/cilium/ebpf/asm/load_store.go
generated
vendored
@ -111,7 +111,7 @@ func LoadMapPtr(dst Register, fd int) Instruction {
|
||||
OpCode: LoadImmOp(DWord),
|
||||
Dst: dst,
|
||||
Src: PseudoMapFD,
|
||||
Constant: int64(uint32(fd)),
|
||||
Constant: int64(fd),
|
||||
}
|
||||
}
|
||||
|
||||
|
4
vendor/github.com/cilium/ebpf/asm/opcode.go
generated
vendored
4
vendor/github.com/cilium/ebpf/asm/opcode.go
generated
vendored
@ -69,13 +69,13 @@ const InvalidOpCode OpCode = 0xff
|
||||
// rawInstructions returns the number of BPF instructions required
|
||||
// to encode this opcode.
|
||||
func (op OpCode) rawInstructions() int {
|
||||
if op.IsDWordLoad() {
|
||||
if op.isDWordLoad() {
|
||||
return 2
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func (op OpCode) IsDWordLoad() bool {
|
||||
func (op OpCode) isDWordLoad() bool {
|
||||
return op == LoadImmOp(DWord)
|
||||
}
|
||||
|
||||
|
59
vendor/github.com/cilium/ebpf/collection.go
generated
vendored
59
vendor/github.com/cilium/ebpf/collection.go
generated
vendored
@ -3,7 +3,6 @@ package ebpf
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
@ -90,8 +89,8 @@ func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error {
|
||||
//
|
||||
// The constant must be defined like so in the C program:
|
||||
//
|
||||
// volatile const type foobar;
|
||||
// volatile const type foobar = default;
|
||||
// static volatile const type foobar;
|
||||
// static volatile const type foobar = default;
|
||||
//
|
||||
// Replacement values must be of the same length as the C sizeof(type).
|
||||
// If necessary, they are marshalled according to the same rules as
|
||||
@ -270,21 +269,11 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Co
|
||||
}, nil
|
||||
}
|
||||
|
||||
type handleCache struct {
|
||||
btfHandles map[*btf.Spec]*btf.Handle
|
||||
btfSpecs map[io.ReaderAt]*btf.Spec
|
||||
}
|
||||
type btfHandleCache map[*btf.Spec]*btf.Handle
|
||||
|
||||
func newHandleCache() *handleCache {
|
||||
return &handleCache{
|
||||
btfHandles: make(map[*btf.Spec]*btf.Handle),
|
||||
btfSpecs: make(map[io.ReaderAt]*btf.Spec),
|
||||
}
|
||||
}
|
||||
|
||||
func (hc handleCache) btfHandle(spec *btf.Spec) (*btf.Handle, error) {
|
||||
if hc.btfHandles[spec] != nil {
|
||||
return hc.btfHandles[spec], nil
|
||||
func (btfs btfHandleCache) load(spec *btf.Spec) (*btf.Handle, error) {
|
||||
if btfs[spec] != nil {
|
||||
return btfs[spec], nil
|
||||
}
|
||||
|
||||
handle, err := btf.NewHandle(spec)
|
||||
@ -292,30 +281,14 @@ func (hc handleCache) btfHandle(spec *btf.Spec) (*btf.Handle, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hc.btfHandles[spec] = handle
|
||||
btfs[spec] = handle
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (hc handleCache) btfSpec(rd io.ReaderAt) (*btf.Spec, error) {
|
||||
if hc.btfSpecs[rd] != nil {
|
||||
return hc.btfSpecs[rd], nil
|
||||
}
|
||||
|
||||
spec, err := btf.LoadSpecFromReader(rd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hc.btfSpecs[rd] = spec
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func (hc handleCache) close() {
|
||||
for _, handle := range hc.btfHandles {
|
||||
func (btfs btfHandleCache) close() {
|
||||
for _, handle := range btfs {
|
||||
handle.Close()
|
||||
}
|
||||
hc.btfHandles = nil
|
||||
hc.btfSpecs = nil
|
||||
}
|
||||
|
||||
func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) (
|
||||
@ -327,12 +300,12 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) (
|
||||
var (
|
||||
maps = make(map[string]*Map)
|
||||
progs = make(map[string]*Program)
|
||||
handles = newHandleCache()
|
||||
btfs = make(btfHandleCache)
|
||||
skipMapsAndProgs = false
|
||||
)
|
||||
|
||||
cleanup = func() {
|
||||
handles.close()
|
||||
btfs.close()
|
||||
|
||||
if skipMapsAndProgs {
|
||||
return
|
||||
@ -362,7 +335,7 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) (
|
||||
return nil, fmt.Errorf("missing map %s", mapName)
|
||||
}
|
||||
|
||||
m, err := newMapWithOptions(mapSpec, opts.Maps, handles)
|
||||
m, err := newMapWithOptions(mapSpec, opts.Maps, btfs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("map %s: %w", mapName, err)
|
||||
}
|
||||
@ -387,7 +360,7 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) (
|
||||
for i := range progSpec.Instructions {
|
||||
ins := &progSpec.Instructions[i]
|
||||
|
||||
if !ins.IsLoadFromMap() || ins.Reference == "" {
|
||||
if ins.OpCode != asm.LoadImmOp(asm.DWord) || ins.Reference == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -399,7 +372,7 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) (
|
||||
|
||||
m, err := loadMap(ins.Reference)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("program %s: %w", progName, err)
|
||||
return nil, fmt.Errorf("program %s: %s", progName, err)
|
||||
}
|
||||
|
||||
fd := m.FD()
|
||||
@ -411,7 +384,7 @@ func lazyLoadCollection(coll *CollectionSpec, opts *CollectionOptions) (
|
||||
}
|
||||
}
|
||||
|
||||
prog, err := newProgramWithOptions(progSpec, opts.Programs, handles)
|
||||
prog, err := newProgramWithOptions(progSpec, opts.Programs, btfs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("program %s: %w", progName, err)
|
||||
}
|
||||
@ -561,7 +534,7 @@ func assignValues(to interface{}, valueOf func(reflect.Type, string) (reflect.Va
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("field %s: %w", field.Name, err)
|
||||
return fmt.Errorf("field %s: %s", field.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
47
vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
47
vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
@ -96,7 +96,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
||||
}
|
||||
|
||||
btfSpec, err := btf.LoadSpecFromReader(rd)
|
||||
if err != nil && !errors.Is(err, btf.ErrNotFound) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load BTF: %w", err)
|
||||
}
|
||||
|
||||
@ -159,7 +159,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
||||
}
|
||||
|
||||
if target.Flags&elf.SHF_STRINGS > 0 {
|
||||
return nil, fmt.Errorf("section %q: string is not stack allocated: %w", section.Name, ErrNotSupported)
|
||||
return nil, fmt.Errorf("section %q: string %q is not stack allocated: %w", section.Name, rel.Name, ErrNotSupported)
|
||||
}
|
||||
|
||||
target.references++
|
||||
@ -374,25 +374,17 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
|
||||
}
|
||||
|
||||
case dataSection:
|
||||
var offset uint32
|
||||
switch typ {
|
||||
case elf.STT_SECTION:
|
||||
if bind != elf.STB_LOCAL {
|
||||
return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind)
|
||||
}
|
||||
|
||||
// This is really a reference to a static symbol, which clang doesn't
|
||||
// emit a symbol table entry for. Instead it encodes the offset in
|
||||
// the instruction itself.
|
||||
offset = uint32(uint64(ins.Constant))
|
||||
|
||||
case elf.STT_OBJECT:
|
||||
if bind != elf.STB_GLOBAL {
|
||||
return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind)
|
||||
}
|
||||
|
||||
offset = uint32(rel.Value)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("incorrect relocation type %v for direct map load", typ)
|
||||
}
|
||||
@ -402,8 +394,10 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
|
||||
// it's not clear how to encode that into Instruction.
|
||||
name = target.Name
|
||||
|
||||
// The kernel expects the offset in the second basic BPF instruction.
|
||||
ins.Constant = int64(uint64(offset) << 32)
|
||||
// For some reason, clang encodes the offset of the symbol its
|
||||
// section in the first basic BPF instruction, while the kernel
|
||||
// expects it in the second one.
|
||||
ins.Constant <<= 32
|
||||
ins.Src = asm.PseudoMapValue
|
||||
|
||||
// Mark the instruction as needing an update when creating the
|
||||
@ -497,38 +491,33 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error {
|
||||
return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
|
||||
}
|
||||
|
||||
mapName := mapSym.Name
|
||||
if maps[mapName] != nil {
|
||||
if maps[mapSym.Name] != nil {
|
||||
return fmt.Errorf("section %v: map %v already exists", sec.Name, mapSym)
|
||||
}
|
||||
|
||||
lr := io.LimitReader(r, int64(size))
|
||||
|
||||
spec := MapSpec{
|
||||
Name: SanitizeName(mapName, -1),
|
||||
Name: SanitizeName(mapSym.Name, -1),
|
||||
}
|
||||
switch {
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil:
|
||||
return fmt.Errorf("map %s: missing type", mapName)
|
||||
return fmt.Errorf("map %v: missing type", mapSym)
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil:
|
||||
return fmt.Errorf("map %s: missing key size", mapName)
|
||||
return fmt.Errorf("map %v: missing key size", mapSym)
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil:
|
||||
return fmt.Errorf("map %s: missing value size", mapName)
|
||||
return fmt.Errorf("map %v: missing value size", mapSym)
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil:
|
||||
return fmt.Errorf("map %s: missing max entries", mapName)
|
||||
return fmt.Errorf("map %v: missing max entries", mapSym)
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil:
|
||||
return fmt.Errorf("map %s: missing flags", mapName)
|
||||
return fmt.Errorf("map %v: missing flags", mapSym)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil {
|
||||
return fmt.Errorf("map %s: unknown and non-zero fields in definition", mapName)
|
||||
return fmt.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
|
||||
}
|
||||
|
||||
if err := spec.clampPerfEventArraySize(); err != nil {
|
||||
return fmt.Errorf("map %s: %w", mapName, err)
|
||||
}
|
||||
|
||||
maps[mapName] = &spec
|
||||
maps[mapSym.Name] = &spec
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,10 +565,6 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
|
||||
return fmt.Errorf("map %v: %w", name, err)
|
||||
}
|
||||
|
||||
if err := mapSpec.clampPerfEventArraySize(); err != nil {
|
||||
return fmt.Errorf("map %v: %w", name, err)
|
||||
}
|
||||
|
||||
maps[name] = mapSpec
|
||||
}
|
||||
}
|
||||
@ -862,8 +847,6 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
|
||||
"uretprobe/": {Kprobe, AttachNone, 0},
|
||||
"tracepoint/": {TracePoint, AttachNone, 0},
|
||||
"raw_tracepoint/": {RawTracepoint, AttachNone, 0},
|
||||
"raw_tp/": {RawTracepoint, AttachNone, 0},
|
||||
"tp_btf/": {Tracing, AttachTraceRawTp, 0},
|
||||
"xdp": {XDP, AttachNone, 0},
|
||||
"perf_event": {PerfEvent, AttachNone, 0},
|
||||
"lwt_in": {LWTIn, AttachNone, 0},
|
||||
|
28
vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
28
vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
@ -35,7 +35,7 @@ type Spec struct {
|
||||
namedTypes map[string][]namedType
|
||||
funcInfos map[string]extInfo
|
||||
lineInfos map[string]extInfo
|
||||
coreRelos map[string]coreRelos
|
||||
coreRelos map[string]bpfCoreRelos
|
||||
byteOrder binary.ByteOrder
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ type btfHeader struct {
|
||||
|
||||
// LoadSpecFromReader reads BTF sections from an ELF.
|
||||
//
|
||||
// Returns ErrNotFound if the reader contains no BTF.
|
||||
// Returns a nil Spec and no error if no BTF was present.
|
||||
func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
file, err := internal.NewSafeELFFile(rd)
|
||||
if err != nil {
|
||||
@ -67,7 +67,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
}
|
||||
|
||||
if btfSection == nil {
|
||||
return nil, fmt.Errorf("btf: %w", ErrNotFound)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
symbols, err := file.Symbols()
|
||||
@ -438,13 +438,13 @@ func (s *Spec) Program(name string, length uint64) (*Program, error) {
|
||||
|
||||
funcInfos, funcOK := s.funcInfos[name]
|
||||
lineInfos, lineOK := s.lineInfos[name]
|
||||
relos, coreOK := s.coreRelos[name]
|
||||
coreRelos, coreOK := s.coreRelos[name]
|
||||
|
||||
if !funcOK && !lineOK && !coreOK {
|
||||
return nil, fmt.Errorf("no extended BTF info for section %s", name)
|
||||
}
|
||||
|
||||
return &Program{s, length, funcInfos, lineInfos, relos}, nil
|
||||
return &Program{s, length, funcInfos, lineInfos, coreRelos}, nil
|
||||
}
|
||||
|
||||
// Datasec returns the BTF required to create maps which represent data sections.
|
||||
@ -491,8 +491,7 @@ func (s *Spec) FindType(name string, typ Type) error {
|
||||
return fmt.Errorf("type %s: %w", name, ErrNotFound)
|
||||
}
|
||||
|
||||
cpy, _ := copyType(candidate, nil)
|
||||
value := reflect.Indirect(reflect.ValueOf(cpy))
|
||||
value := reflect.Indirect(reflect.ValueOf(copyType(candidate)))
|
||||
reflect.Indirect(reflect.ValueOf(typ)).Set(value)
|
||||
return nil
|
||||
}
|
||||
@ -607,7 +606,7 @@ type Program struct {
|
||||
spec *Spec
|
||||
length uint64
|
||||
funcInfos, lineInfos extInfo
|
||||
coreRelos coreRelos
|
||||
coreRelos bpfCoreRelos
|
||||
}
|
||||
|
||||
// ProgramSpec returns the Spec needed for loading function and line infos into the kernel.
|
||||
@ -666,23 +665,16 @@ func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
|
||||
return s.lineInfos.recordSize, bytes, nil
|
||||
}
|
||||
|
||||
// ProgramFixups returns the changes required to adjust the program to the target.
|
||||
// ProgramRelocations returns the CO-RE relocations required to adjust the
|
||||
// program to the target.
|
||||
//
|
||||
// This is a free function instead of a method to hide it from users
|
||||
// of package ebpf.
|
||||
func ProgramFixups(s *Program, target *Spec) (COREFixups, error) {
|
||||
func ProgramRelocations(s *Program, target *Spec) (map[uint64]Relocation, error) {
|
||||
if len(s.coreRelos) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if target == nil {
|
||||
var err error
|
||||
target, err = LoadKernelSpec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return coreRelocate(s.spec, target, s.coreRelos)
|
||||
}
|
||||
|
||||
|
783
vendor/github.com/cilium/ebpf/internal/btf/core.go
generated
vendored
783
vendor/github.com/cilium/ebpf/internal/btf/core.go
generated
vendored
@ -3,160 +3,43 @@ package btf
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cilium/ebpf/asm"
|
||||
)
|
||||
|
||||
// Code in this file is derived from libbpf, which is available under a BSD
|
||||
// 2-Clause license.
|
||||
|
||||
// COREFixup is the result of computing a CO-RE relocation for a target.
|
||||
type COREFixup struct {
|
||||
Kind COREKind
|
||||
Local uint32
|
||||
Target uint32
|
||||
Poison bool
|
||||
// Relocation describes a CO-RE relocation.
|
||||
type Relocation struct {
|
||||
Current uint32
|
||||
New uint32
|
||||
}
|
||||
|
||||
func (f COREFixup) equal(other COREFixup) bool {
|
||||
return f.Local == other.Local && f.Target == other.Target
|
||||
func (r Relocation) equal(other Relocation) bool {
|
||||
return r.Current == other.Current && r.New == other.New
|
||||
}
|
||||
|
||||
func (f COREFixup) String() string {
|
||||
if f.Poison {
|
||||
return fmt.Sprintf("%s=poison", f.Kind)
|
||||
}
|
||||
return fmt.Sprintf("%s=%d->%d", f.Kind, f.Local, f.Target)
|
||||
}
|
||||
|
||||
func (f COREFixup) apply(ins *asm.Instruction) error {
|
||||
if f.Poison {
|
||||
return errors.New("can't poison individual instruction")
|
||||
}
|
||||
|
||||
switch class := ins.OpCode.Class(); class {
|
||||
case asm.LdXClass, asm.StClass, asm.StXClass:
|
||||
if want := int16(f.Local); want != ins.Offset {
|
||||
return fmt.Errorf("invalid offset %d, expected %d", ins.Offset, want)
|
||||
}
|
||||
|
||||
if f.Target > math.MaxInt16 {
|
||||
return fmt.Errorf("offset %d exceeds MaxInt16", f.Target)
|
||||
}
|
||||
|
||||
ins.Offset = int16(f.Target)
|
||||
|
||||
case asm.LdClass:
|
||||
if !ins.IsConstantLoad(asm.DWord) {
|
||||
return fmt.Errorf("not a dword-sized immediate load")
|
||||
}
|
||||
|
||||
if want := int64(f.Local); want != ins.Constant {
|
||||
return fmt.Errorf("invalid immediate %d, expected %d", ins.Constant, want)
|
||||
}
|
||||
|
||||
ins.Constant = int64(f.Target)
|
||||
|
||||
case asm.ALUClass:
|
||||
if ins.OpCode.ALUOp() == asm.Swap {
|
||||
return fmt.Errorf("relocation against swap")
|
||||
}
|
||||
|
||||
fallthrough
|
||||
|
||||
case asm.ALU64Class:
|
||||
if src := ins.OpCode.Source(); src != asm.ImmSource {
|
||||
return fmt.Errorf("invalid source %s", src)
|
||||
}
|
||||
|
||||
if want := int64(f.Local); want != ins.Constant {
|
||||
return fmt.Errorf("invalid immediate %d, expected %d", ins.Constant, want)
|
||||
}
|
||||
|
||||
if f.Target > math.MaxInt32 {
|
||||
return fmt.Errorf("immediate %d exceeds MaxInt32", f.Target)
|
||||
}
|
||||
|
||||
ins.Constant = int64(f.Target)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("invalid class %s", class)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f COREFixup) isNonExistant() bool {
|
||||
return f.Kind.checksForExistence() && f.Target == 0
|
||||
}
|
||||
|
||||
type COREFixups map[uint64]COREFixup
|
||||
|
||||
// Apply a set of CO-RE relocations to a BPF program.
|
||||
func (fs COREFixups) Apply(insns asm.Instructions) (asm.Instructions, error) {
|
||||
if len(fs) == 0 {
|
||||
cpy := make(asm.Instructions, len(insns))
|
||||
copy(cpy, insns)
|
||||
return insns, nil
|
||||
}
|
||||
|
||||
cpy := make(asm.Instructions, 0, len(insns))
|
||||
iter := insns.Iterate()
|
||||
for iter.Next() {
|
||||
fixup, ok := fs[iter.Offset.Bytes()]
|
||||
if !ok {
|
||||
cpy = append(cpy, *iter.Ins)
|
||||
continue
|
||||
}
|
||||
|
||||
ins := *iter.Ins
|
||||
if fixup.Poison {
|
||||
const badRelo = asm.BuiltinFunc(0xbad2310)
|
||||
|
||||
cpy = append(cpy, badRelo.Call())
|
||||
if ins.OpCode.IsDWordLoad() {
|
||||
// 64 bit constant loads occupy two raw bpf instructions, so
|
||||
// we need to add another instruction as padding.
|
||||
cpy = append(cpy, badRelo.Call())
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if err := fixup.apply(&ins); err != nil {
|
||||
return nil, fmt.Errorf("instruction %d, offset %d: %s: %w", iter.Index, iter.Offset.Bytes(), fixup.Kind, err)
|
||||
}
|
||||
|
||||
cpy = append(cpy, ins)
|
||||
}
|
||||
|
||||
return cpy, nil
|
||||
}
|
||||
|
||||
// COREKind is the type of CO-RE relocation
|
||||
type COREKind uint32
|
||||
// coreReloKind is the type of CO-RE relocation
|
||||
type coreReloKind uint32
|
||||
|
||||
const (
|
||||
reloFieldByteOffset COREKind = iota /* field byte offset */
|
||||
reloFieldByteSize /* field size in bytes */
|
||||
reloFieldExists /* field existence in target kernel */
|
||||
reloFieldSigned /* field signedness (0 - unsigned, 1 - signed) */
|
||||
reloFieldLShiftU64 /* bitfield-specific left bitshift */
|
||||
reloFieldRShiftU64 /* bitfield-specific right bitshift */
|
||||
reloTypeIDLocal /* type ID in local BPF object */
|
||||
reloTypeIDTarget /* type ID in target kernel */
|
||||
reloTypeExists /* type existence in target kernel */
|
||||
reloTypeSize /* type size in bytes */
|
||||
reloEnumvalExists /* enum value existence in target kernel */
|
||||
reloEnumvalValue /* enum value integer value */
|
||||
reloFieldByteOffset coreReloKind = iota /* field byte offset */
|
||||
reloFieldByteSize /* field size in bytes */
|
||||
reloFieldExists /* field existence in target kernel */
|
||||
reloFieldSigned /* field signedness (0 - unsigned, 1 - signed) */
|
||||
reloFieldLShiftU64 /* bitfield-specific left bitshift */
|
||||
reloFieldRShiftU64 /* bitfield-specific right bitshift */
|
||||
reloTypeIDLocal /* type ID in local BPF object */
|
||||
reloTypeIDTarget /* type ID in target kernel */
|
||||
reloTypeExists /* type existence in target kernel */
|
||||
reloTypeSize /* type size in bytes */
|
||||
reloEnumvalExists /* enum value existence in target kernel */
|
||||
reloEnumvalValue /* enum value integer value */
|
||||
)
|
||||
|
||||
func (k COREKind) String() string {
|
||||
func (k coreReloKind) String() string {
|
||||
switch k {
|
||||
case reloFieldByteOffset:
|
||||
return "byte_off"
|
||||
@ -187,249 +70,103 @@ func (k COREKind) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (k COREKind) checksForExistence() bool {
|
||||
return k == reloEnumvalExists || k == reloTypeExists || k == reloFieldExists
|
||||
}
|
||||
func coreRelocate(local, target *Spec, coreRelos bpfCoreRelos) (map[uint64]Relocation, error) {
|
||||
if target == nil {
|
||||
var err error
|
||||
target, err = loadKernelSpec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func coreRelocate(local, target *Spec, relos coreRelos) (COREFixups, error) {
|
||||
if local.byteOrder != target.byteOrder {
|
||||
return nil, fmt.Errorf("can't relocate %s against %s", local.byteOrder, target.byteOrder)
|
||||
}
|
||||
|
||||
var ids []TypeID
|
||||
relosByID := make(map[TypeID]coreRelos)
|
||||
result := make(COREFixups, len(relos))
|
||||
for _, relo := range relos {
|
||||
if relo.kind == reloTypeIDLocal {
|
||||
// Filtering out reloTypeIDLocal here makes our lives a lot easier
|
||||
// down the line, since it doesn't have a target at all.
|
||||
if len(relo.accessor) > 1 || relo.accessor[0] != 0 {
|
||||
return nil, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor)
|
||||
}
|
||||
|
||||
result[uint64(relo.insnOff)] = COREFixup{
|
||||
relo.kind,
|
||||
uint32(relo.typeID),
|
||||
uint32(relo.typeID),
|
||||
false,
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
relos, ok := relosByID[relo.typeID]
|
||||
if !ok {
|
||||
ids = append(ids, relo.typeID)
|
||||
}
|
||||
relosByID[relo.typeID] = append(relos, relo)
|
||||
}
|
||||
|
||||
// Ensure we work on relocations in a deterministic order.
|
||||
sort.Slice(ids, func(i, j int) bool {
|
||||
return ids[i] < ids[j]
|
||||
})
|
||||
|
||||
for _, id := range ids {
|
||||
if int(id) >= len(local.types) {
|
||||
return nil, fmt.Errorf("invalid type id %d", id)
|
||||
}
|
||||
|
||||
localType := local.types[id]
|
||||
named, ok := localType.(namedType)
|
||||
if !ok || named.name() == "" {
|
||||
return nil, fmt.Errorf("relocate unnamed or anonymous type %s: %w", localType, ErrNotSupported)
|
||||
}
|
||||
|
||||
relos := relosByID[id]
|
||||
targets := target.namedTypes[named.essentialName()]
|
||||
fixups, err := coreCalculateFixups(localType, targets, relos)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("relocate %s: %w", localType, err)
|
||||
}
|
||||
|
||||
for i, relo := range relos {
|
||||
result[uint64(relo.insnOff)] = fixups[i]
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
var errAmbiguousRelocation = errors.New("ambiguous relocation")
|
||||
var errImpossibleRelocation = errors.New("impossible relocation")
|
||||
|
||||
// coreCalculateFixups calculates the fixups for the given relocations using
|
||||
// the "best" target.
|
||||
//
|
||||
// The best target is determined by scoring: the less poisoning we have to do
|
||||
// the better the target is.
|
||||
func coreCalculateFixups(local Type, targets []namedType, relos coreRelos) ([]COREFixup, error) {
|
||||
localID := local.ID()
|
||||
local, err := copyType(local, skipQualifierAndTypedef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bestScore := len(relos)
|
||||
var bestFixups []COREFixup
|
||||
for i := range targets {
|
||||
targetID := targets[i].ID()
|
||||
target, err := copyType(targets[i], skipQualifierAndTypedef)
|
||||
relocations := make(map[uint64]Relocation, len(coreRelos))
|
||||
for _, relo := range coreRelos {
|
||||
accessorStr, err := local.strings.Lookup(relo.AccessStrOff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
score := 0 // lower is better
|
||||
fixups := make([]COREFixup, 0, len(relos))
|
||||
for _, relo := range relos {
|
||||
fixup, err := coreCalculateFixup(local, localID, target, targetID, relo)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("target %s: %w", target, err)
|
||||
}
|
||||
if fixup.Poison || fixup.isNonExistant() {
|
||||
score++
|
||||
}
|
||||
fixups = append(fixups, fixup)
|
||||
accessor, err := parseCoreAccessor(accessorStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("accessor %q: %s", accessorStr, err)
|
||||
}
|
||||
|
||||
if score > bestScore {
|
||||
// We have a better target already, ignore this one.
|
||||
if int(relo.TypeID) >= len(local.types) {
|
||||
return nil, fmt.Errorf("invalid type id %d", relo.TypeID)
|
||||
}
|
||||
|
||||
typ := local.types[relo.TypeID]
|
||||
|
||||
if relo.ReloKind == reloTypeIDLocal {
|
||||
relocations[uint64(relo.InsnOff)] = Relocation{
|
||||
uint32(typ.ID()),
|
||||
uint32(typ.ID()),
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if score < bestScore {
|
||||
// This is the best target yet, use it.
|
||||
bestScore = score
|
||||
bestFixups = fixups
|
||||
continue
|
||||
named, ok := typ.(namedType)
|
||||
if !ok || named.name() == "" {
|
||||
return nil, fmt.Errorf("relocate anonymous type %s: %w", typ.String(), ErrNotSupported)
|
||||
}
|
||||
|
||||
// Some other target has the same score as the current one. Make sure
|
||||
// the fixups agree with each other.
|
||||
for i, fixup := range bestFixups {
|
||||
if !fixup.equal(fixups[i]) {
|
||||
return nil, fmt.Errorf("%s: multiple types match: %w", fixup.Kind, errAmbiguousRelocation)
|
||||
}
|
||||
name := essentialName(named.name())
|
||||
res, err := coreCalculateRelocation(typ, target.namedTypes[name], relo.ReloKind, accessor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("relocate %s: %w", name, err)
|
||||
}
|
||||
|
||||
relocations[uint64(relo.InsnOff)] = res
|
||||
}
|
||||
|
||||
if bestFixups == nil {
|
||||
// Nothing at all matched, probably because there are no suitable
|
||||
// targets at all. Poison everything!
|
||||
bestFixups = make([]COREFixup, len(relos))
|
||||
for i, relo := range relos {
|
||||
bestFixups[i] = COREFixup{Kind: relo.kind, Poison: true}
|
||||
}
|
||||
}
|
||||
|
||||
return bestFixups, nil
|
||||
return relocations, nil
|
||||
}
|
||||
|
||||
// coreCalculateFixup calculates the fixup for a single local type, target type
|
||||
// and relocation.
|
||||
func coreCalculateFixup(local Type, localID TypeID, target Type, targetID TypeID, relo coreRelo) (COREFixup, error) {
|
||||
fixup := func(local, target uint32) (COREFixup, error) {
|
||||
return COREFixup{relo.kind, local, target, false}, nil
|
||||
}
|
||||
poison := func() (COREFixup, error) {
|
||||
if relo.kind.checksForExistence() {
|
||||
return fixup(1, 0)
|
||||
}
|
||||
return COREFixup{relo.kind, 0, 0, true}, nil
|
||||
}
|
||||
zero := COREFixup{}
|
||||
|
||||
switch relo.kind {
|
||||
case reloTypeIDTarget, reloTypeSize, reloTypeExists:
|
||||
if len(relo.accessor) > 1 || relo.accessor[0] != 0 {
|
||||
return zero, fmt.Errorf("%s: unexpected accessor %v", relo.kind, relo.accessor)
|
||||
}
|
||||
|
||||
err := coreAreTypesCompatible(local, target)
|
||||
if errors.Is(err, errImpossibleRelocation) {
|
||||
return poison()
|
||||
}
|
||||
if err != nil {
|
||||
return zero, fmt.Errorf("relocation %s: %w", relo.kind, err)
|
||||
}
|
||||
|
||||
switch relo.kind {
|
||||
case reloTypeExists:
|
||||
return fixup(1, 1)
|
||||
var errAmbiguousRelocation = errors.New("ambiguous relocation")
|
||||
|
||||
func coreCalculateRelocation(local Type, targets []namedType, kind coreReloKind, localAccessor coreAccessor) (Relocation, error) {
|
||||
var relos []Relocation
|
||||
var matches []Type
|
||||
for _, target := range targets {
|
||||
switch kind {
|
||||
case reloTypeIDTarget:
|
||||
return fixup(uint32(localID), uint32(targetID))
|
||||
|
||||
case reloTypeSize:
|
||||
localSize, err := Sizeof(local)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
if localAccessor[0] != 0 {
|
||||
return Relocation{}, fmt.Errorf("%s: unexpected non-zero accessor", kind)
|
||||
}
|
||||
|
||||
targetSize, err := Sizeof(target)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
if compat, err := coreAreTypesCompatible(local, target); err != nil {
|
||||
return Relocation{}, fmt.Errorf("%s: %s", kind, err)
|
||||
} else if !compat {
|
||||
continue
|
||||
}
|
||||
|
||||
return fixup(uint32(localSize), uint32(targetSize))
|
||||
relos = append(relos, Relocation{uint32(target.ID()), uint32(target.ID())})
|
||||
|
||||
default:
|
||||
return Relocation{}, fmt.Errorf("relocation %s: %w", kind, ErrNotSupported)
|
||||
}
|
||||
matches = append(matches, target)
|
||||
}
|
||||
|
||||
case reloEnumvalValue, reloEnumvalExists:
|
||||
localValue, targetValue, err := coreFindEnumValue(local, relo.accessor, target)
|
||||
if errors.Is(err, errImpossibleRelocation) {
|
||||
return poison()
|
||||
}
|
||||
if err != nil {
|
||||
return zero, fmt.Errorf("relocation %s: %w", relo.kind, err)
|
||||
}
|
||||
if len(relos) == 0 {
|
||||
// TODO: Add switch for existence checks like reloEnumvalExists here.
|
||||
|
||||
switch relo.kind {
|
||||
case reloEnumvalExists:
|
||||
return fixup(1, 1)
|
||||
|
||||
case reloEnumvalValue:
|
||||
return fixup(uint32(localValue.Value), uint32(targetValue.Value))
|
||||
}
|
||||
|
||||
case reloFieldByteOffset, reloFieldByteSize, reloFieldExists:
|
||||
if _, ok := target.(*Fwd); ok {
|
||||
// We can't relocate fields using a forward declaration, so
|
||||
// skip it. If a non-forward declaration is present in the BTF
|
||||
// we'll find it in one of the other iterations.
|
||||
return poison()
|
||||
}
|
||||
|
||||
localField, targetField, err := coreFindField(local, relo.accessor, target)
|
||||
if errors.Is(err, errImpossibleRelocation) {
|
||||
return poison()
|
||||
}
|
||||
if err != nil {
|
||||
return zero, fmt.Errorf("target %s: %w", target, err)
|
||||
}
|
||||
|
||||
switch relo.kind {
|
||||
case reloFieldExists:
|
||||
return fixup(1, 1)
|
||||
|
||||
case reloFieldByteOffset:
|
||||
return fixup(localField.offset/8, targetField.offset/8)
|
||||
|
||||
case reloFieldByteSize:
|
||||
localSize, err := Sizeof(localField.Type)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
|
||||
targetSize, err := Sizeof(targetField.Type)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
|
||||
return fixup(uint32(localSize), uint32(targetSize))
|
||||
// TODO: This might have to be poisoned.
|
||||
return Relocation{}, fmt.Errorf("no relocation found, tried %v", targets)
|
||||
}
|
||||
|
||||
relo := relos[0]
|
||||
for _, altRelo := range relos[1:] {
|
||||
if !altRelo.equal(relo) {
|
||||
return Relocation{}, fmt.Errorf("multiple types %v match: %w", matches, errAmbiguousRelocation)
|
||||
}
|
||||
}
|
||||
|
||||
return zero, fmt.Errorf("relocation %s: %w", relo.kind, ErrNotSupported)
|
||||
return relo, nil
|
||||
}
|
||||
|
||||
/* coreAccessor contains a path through a struct. It contains at least one index.
|
||||
@ -482,240 +219,6 @@ func parseCoreAccessor(accessor string) (coreAccessor, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (ca coreAccessor) String() string {
|
||||
strs := make([]string, 0, len(ca))
|
||||
for _, i := range ca {
|
||||
strs = append(strs, strconv.Itoa(i))
|
||||
}
|
||||
return strings.Join(strs, ":")
|
||||
}
|
||||
|
||||
func (ca coreAccessor) enumValue(t Type) (*EnumValue, error) {
|
||||
e, ok := t.(*Enum)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not an enum: %s", t)
|
||||
}
|
||||
|
||||
if len(ca) > 1 {
|
||||
return nil, fmt.Errorf("invalid accessor %s for enum", ca)
|
||||
}
|
||||
|
||||
i := ca[0]
|
||||
if i >= len(e.Values) {
|
||||
return nil, fmt.Errorf("invalid index %d for %s", i, e)
|
||||
}
|
||||
|
||||
return &e.Values[i], nil
|
||||
}
|
||||
|
||||
type coreField struct {
|
||||
Type Type
|
||||
offset uint32
|
||||
}
|
||||
|
||||
func adjustOffset(base uint32, t Type, n int) (uint32, error) {
|
||||
size, err := Sizeof(t)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return base + (uint32(n) * uint32(size) * 8), nil
|
||||
}
|
||||
|
||||
// coreFindField descends into the local type using the accessor and tries to
|
||||
// find an equivalent field in target at each step.
|
||||
//
|
||||
// Returns the field and the offset of the field from the start of
|
||||
// target in bits.
|
||||
func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreField, _ error) {
|
||||
// The first index is used to offset a pointer of the base type like
|
||||
// when accessing an array.
|
||||
localOffset, err := adjustOffset(0, local, localAcc[0])
|
||||
if err != nil {
|
||||
return coreField{}, coreField{}, err
|
||||
}
|
||||
|
||||
targetOffset, err := adjustOffset(0, target, localAcc[0])
|
||||
if err != nil {
|
||||
return coreField{}, coreField{}, err
|
||||
}
|
||||
|
||||
if err := coreAreMembersCompatible(local, target); err != nil {
|
||||
return coreField{}, coreField{}, fmt.Errorf("fields: %w", err)
|
||||
}
|
||||
|
||||
var localMaybeFlex, targetMaybeFlex bool
|
||||
for _, acc := range localAcc[1:] {
|
||||
switch localType := local.(type) {
|
||||
case composite:
|
||||
// For composite types acc is used to find the field in the local type,
|
||||
// and then we try to find a field in target with the same name.
|
||||
localMembers := localType.members()
|
||||
if acc >= len(localMembers) {
|
||||
return coreField{}, coreField{}, fmt.Errorf("invalid accessor %d for %s", acc, local)
|
||||
}
|
||||
|
||||
localMember := localMembers[acc]
|
||||
if localMember.Name == "" {
|
||||
_, ok := localMember.Type.(composite)
|
||||
if !ok {
|
||||
return coreField{}, coreField{}, fmt.Errorf("unnamed field with type %s: %s", localMember.Type, ErrNotSupported)
|
||||
}
|
||||
|
||||
// This is an anonymous struct or union, ignore it.
|
||||
local = localMember.Type
|
||||
localOffset += localMember.Offset
|
||||
localMaybeFlex = false
|
||||
continue
|
||||
}
|
||||
|
||||
targetType, ok := target.(composite)
|
||||
if !ok {
|
||||
return coreField{}, coreField{}, fmt.Errorf("target not composite: %w", errImpossibleRelocation)
|
||||
}
|
||||
|
||||
targetMember, last, err := coreFindMember(targetType, localMember.Name)
|
||||
if err != nil {
|
||||
return coreField{}, coreField{}, err
|
||||
}
|
||||
|
||||
if targetMember.BitfieldSize > 0 {
|
||||
return coreField{}, coreField{}, fmt.Errorf("field %q is a bitfield: %w", targetMember.Name, ErrNotSupported)
|
||||
}
|
||||
|
||||
local = localMember.Type
|
||||
localMaybeFlex = acc == len(localMembers)-1
|
||||
localOffset += localMember.Offset
|
||||
target = targetMember.Type
|
||||
targetMaybeFlex = last
|
||||
targetOffset += targetMember.Offset
|
||||
|
||||
case *Array:
|
||||
// For arrays, acc is the index in the target.
|
||||
targetType, ok := target.(*Array)
|
||||
if !ok {
|
||||
return coreField{}, coreField{}, fmt.Errorf("target not array: %w", errImpossibleRelocation)
|
||||
}
|
||||
|
||||
if localType.Nelems == 0 && !localMaybeFlex {
|
||||
return coreField{}, coreField{}, fmt.Errorf("local type has invalid flexible array")
|
||||
}
|
||||
if targetType.Nelems == 0 && !targetMaybeFlex {
|
||||
return coreField{}, coreField{}, fmt.Errorf("target type has invalid flexible array")
|
||||
}
|
||||
|
||||
if localType.Nelems > 0 && acc >= int(localType.Nelems) {
|
||||
return coreField{}, coreField{}, fmt.Errorf("invalid access of %s at index %d", localType, acc)
|
||||
}
|
||||
if targetType.Nelems > 0 && acc >= int(targetType.Nelems) {
|
||||
return coreField{}, coreField{}, fmt.Errorf("out of bounds access of target: %w", errImpossibleRelocation)
|
||||
}
|
||||
|
||||
local = localType.Type
|
||||
localMaybeFlex = false
|
||||
localOffset, err = adjustOffset(localOffset, local, acc)
|
||||
if err != nil {
|
||||
return coreField{}, coreField{}, err
|
||||
}
|
||||
|
||||
target = targetType.Type
|
||||
targetMaybeFlex = false
|
||||
targetOffset, err = adjustOffset(targetOffset, target, acc)
|
||||
if err != nil {
|
||||
return coreField{}, coreField{}, err
|
||||
}
|
||||
|
||||
default:
|
||||
return coreField{}, coreField{}, fmt.Errorf("relocate field of %T: %w", localType, ErrNotSupported)
|
||||
}
|
||||
|
||||
if err := coreAreMembersCompatible(local, target); err != nil {
|
||||
return coreField{}, coreField{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return coreField{local, localOffset}, coreField{target, targetOffset}, nil
|
||||
}
|
||||
|
||||
// coreFindMember finds a member in a composite type while handling anonymous
|
||||
// structs and unions.
|
||||
func coreFindMember(typ composite, name Name) (Member, bool, error) {
|
||||
if name == "" {
|
||||
return Member{}, false, errors.New("can't search for anonymous member")
|
||||
}
|
||||
|
||||
type offsetTarget struct {
|
||||
composite
|
||||
offset uint32
|
||||
}
|
||||
|
||||
targets := []offsetTarget{{typ, 0}}
|
||||
visited := make(map[composite]bool)
|
||||
|
||||
for i := 0; i < len(targets); i++ {
|
||||
target := targets[i]
|
||||
|
||||
// Only visit targets once to prevent infinite recursion.
|
||||
if visited[target] {
|
||||
continue
|
||||
}
|
||||
if len(visited) >= maxTypeDepth {
|
||||
// This check is different than libbpf, which restricts the entire
|
||||
// path to BPF_CORE_SPEC_MAX_LEN items.
|
||||
return Member{}, false, fmt.Errorf("type is nested too deep")
|
||||
}
|
||||
visited[target] = true
|
||||
|
||||
members := target.members()
|
||||
for j, member := range members {
|
||||
if member.Name == name {
|
||||
// NB: This is safe because member is a copy.
|
||||
member.Offset += target.offset
|
||||
return member, j == len(members)-1, nil
|
||||
}
|
||||
|
||||
// The names don't match, but this member could be an anonymous struct
|
||||
// or union.
|
||||
if member.Name != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
comp, ok := member.Type.(composite)
|
||||
if !ok {
|
||||
return Member{}, false, fmt.Errorf("anonymous non-composite type %T not allowed", member.Type)
|
||||
}
|
||||
|
||||
targets = append(targets, offsetTarget{comp, target.offset + member.Offset})
|
||||
}
|
||||
}
|
||||
|
||||
return Member{}, false, fmt.Errorf("no matching member: %w", errImpossibleRelocation)
|
||||
}
|
||||
|
||||
// coreFindEnumValue follows localAcc to find the equivalent enum value in target.
|
||||
func coreFindEnumValue(local Type, localAcc coreAccessor, target Type) (localValue, targetValue *EnumValue, _ error) {
|
||||
localValue, err := localAcc.enumValue(local)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
targetEnum, ok := target.(*Enum)
|
||||
if !ok {
|
||||
return nil, nil, errImpossibleRelocation
|
||||
}
|
||||
|
||||
localName := localValue.Name.essentialName()
|
||||
for i, targetValue := range targetEnum.Values {
|
||||
if targetValue.Name.essentialName() != localName {
|
||||
continue
|
||||
}
|
||||
|
||||
return localValue, &targetEnum.Values[i], nil
|
||||
}
|
||||
|
||||
return nil, nil, errImpossibleRelocation
|
||||
}
|
||||
|
||||
/* The comment below is from bpf_core_types_are_compat in libbpf.c:
|
||||
*
|
||||
* Check local and target types for compatibility. This check is used for
|
||||
@ -736,10 +239,8 @@ func coreFindEnumValue(local Type, localAcc coreAccessor, target Type) (localVal
|
||||
* number of input args and compatible return and argument types.
|
||||
* These rules are not set in stone and probably will be adjusted as we get
|
||||
* more experience with using BPF CO-RE relocations.
|
||||
*
|
||||
* Returns errImpossibleRelocation if types are not compatible.
|
||||
*/
|
||||
func coreAreTypesCompatible(localType Type, targetType Type) error {
|
||||
func coreAreTypesCompatible(localType Type, targetType Type) (bool, error) {
|
||||
var (
|
||||
localTs, targetTs typeDeque
|
||||
l, t = &localType, &targetType
|
||||
@ -748,14 +249,14 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
||||
|
||||
for ; l != nil && t != nil; l, t = localTs.shift(), targetTs.shift() {
|
||||
if depth >= maxTypeDepth {
|
||||
return errors.New("types are nested too deep")
|
||||
return false, errors.New("types are nested too deep")
|
||||
}
|
||||
|
||||
localType = *l
|
||||
targetType = *t
|
||||
localType = skipQualifierAndTypedef(*l)
|
||||
targetType = skipQualifierAndTypedef(*t)
|
||||
|
||||
if reflect.TypeOf(localType) != reflect.TypeOf(targetType) {
|
||||
return fmt.Errorf("type mismatch: %w", errImpossibleRelocation)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch lv := (localType).(type) {
|
||||
@ -765,7 +266,7 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
||||
case *Int:
|
||||
tv := targetType.(*Int)
|
||||
if lv.isBitfield() || tv.isBitfield() {
|
||||
return fmt.Errorf("bitfield: %w", errImpossibleRelocation)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
case *Pointer, *Array:
|
||||
@ -776,7 +277,7 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
||||
case *FuncProto:
|
||||
tv := targetType.(*FuncProto)
|
||||
if len(lv.Params) != len(tv.Params) {
|
||||
return fmt.Errorf("function param mismatch: %w", errImpossibleRelocation)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
depth++
|
||||
@ -784,24 +285,22 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
||||
targetType.walk(&targetTs)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported type %T", localType)
|
||||
return false, fmt.Errorf("unsupported type %T", localType)
|
||||
}
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
return fmt.Errorf("dangling local type %T", *l)
|
||||
return false, fmt.Errorf("dangling local type %T", *l)
|
||||
}
|
||||
|
||||
if t != nil {
|
||||
return fmt.Errorf("dangling target type %T", *t)
|
||||
return false, fmt.Errorf("dangling target type %T", *t)
|
||||
}
|
||||
|
||||
return nil
|
||||
return true, nil
|
||||
}
|
||||
|
||||
/* coreAreMembersCompatible checks two types for field-based relocation compatibility.
|
||||
*
|
||||
* The comment below is from bpf_core_fields_are_compat in libbpf.c:
|
||||
/* The comment below is from bpf_core_fields_are_compat in libbpf.c:
|
||||
*
|
||||
* Check two types for compatibility for the purpose of field access
|
||||
* relocation. const/volatile/restrict and typedefs are skipped to ensure we
|
||||
@ -815,63 +314,65 @@ func coreAreTypesCompatible(localType Type, targetType Type) error {
|
||||
* - for INT, size and signedness are ignored;
|
||||
* - for ARRAY, dimensionality is ignored, element types are checked for
|
||||
* compatibility recursively;
|
||||
* [ NB: coreAreMembersCompatible doesn't recurse, this check is done
|
||||
* by coreFindField. ]
|
||||
* - everything else shouldn't be ever a target of relocation.
|
||||
* These rules are not set in stone and probably will be adjusted as we get
|
||||
* more experience with using BPF CO-RE relocations.
|
||||
*
|
||||
* Returns errImpossibleRelocation if the members are not compatible.
|
||||
*/
|
||||
func coreAreMembersCompatible(localType Type, targetType Type) error {
|
||||
doNamesMatch := func(a, b string) error {
|
||||
func coreAreMembersCompatible(localType Type, targetType Type) (bool, error) {
|
||||
doNamesMatch := func(a, b string) bool {
|
||||
if a == "" || b == "" {
|
||||
// allow anonymous and named type to match
|
||||
return nil
|
||||
return true
|
||||
}
|
||||
|
||||
if essentialName(a) == essentialName(b) {
|
||||
return nil
|
||||
return essentialName(a) == essentialName(b)
|
||||
}
|
||||
|
||||
for depth := 0; depth <= maxTypeDepth; depth++ {
|
||||
localType = skipQualifierAndTypedef(localType)
|
||||
targetType = skipQualifierAndTypedef(targetType)
|
||||
|
||||
_, lok := localType.(composite)
|
||||
_, tok := targetType.(composite)
|
||||
if lok && tok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("names don't match: %w", errImpossibleRelocation)
|
||||
}
|
||||
|
||||
_, lok := localType.(composite)
|
||||
_, tok := targetType.(composite)
|
||||
if lok && tok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if reflect.TypeOf(localType) != reflect.TypeOf(targetType) {
|
||||
return fmt.Errorf("type mismatch: %w", errImpossibleRelocation)
|
||||
}
|
||||
|
||||
switch lv := localType.(type) {
|
||||
case *Array, *Pointer:
|
||||
return nil
|
||||
|
||||
case *Enum:
|
||||
tv := targetType.(*Enum)
|
||||
return doNamesMatch(lv.name(), tv.name())
|
||||
|
||||
case *Fwd:
|
||||
tv := targetType.(*Fwd)
|
||||
return doNamesMatch(lv.name(), tv.name())
|
||||
|
||||
case *Int:
|
||||
tv := targetType.(*Int)
|
||||
if lv.isBitfield() || tv.isBitfield() {
|
||||
return fmt.Errorf("bitfield: %w", errImpossibleRelocation)
|
||||
if reflect.TypeOf(localType) != reflect.TypeOf(targetType) {
|
||||
return false, nil
|
||||
}
|
||||
return nil
|
||||
|
||||
default:
|
||||
return fmt.Errorf("type %s: %w", localType, ErrNotSupported)
|
||||
switch lv := localType.(type) {
|
||||
case *Pointer:
|
||||
return true, nil
|
||||
|
||||
case *Enum:
|
||||
tv := targetType.(*Enum)
|
||||
return doNamesMatch(lv.name(), tv.name()), nil
|
||||
|
||||
case *Fwd:
|
||||
tv := targetType.(*Fwd)
|
||||
return doNamesMatch(lv.name(), tv.name()), nil
|
||||
|
||||
case *Int:
|
||||
tv := targetType.(*Int)
|
||||
return !lv.isBitfield() && !tv.isBitfield(), nil
|
||||
|
||||
case *Array:
|
||||
tv := targetType.(*Array)
|
||||
|
||||
localType = lv.Type
|
||||
targetType = tv.Type
|
||||
|
||||
default:
|
||||
return false, fmt.Errorf("unsupported type %T", localType)
|
||||
}
|
||||
}
|
||||
|
||||
return false, errors.New("types are nested too deep")
|
||||
}
|
||||
|
||||
func skipQualifierAndTypedef(typ Type) (Type, error) {
|
||||
func skipQualifierAndTypedef(typ Type) Type {
|
||||
result := typ
|
||||
for depth := 0; depth <= maxTypeDepth; depth++ {
|
||||
switch v := (result).(type) {
|
||||
@ -880,8 +381,8 @@ func skipQualifierAndTypedef(typ Type) (Type, error) {
|
||||
case *Typedef:
|
||||
result = v.Type
|
||||
default:
|
||||
return result, nil
|
||||
return result
|
||||
}
|
||||
}
|
||||
return nil, errors.New("exceeded type depth")
|
||||
return typ
|
||||
}
|
||||
|
46
vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
46
vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
@ -30,7 +30,7 @@ type btfExtCoreHeader struct {
|
||||
CoreReloLen uint32
|
||||
}
|
||||
|
||||
func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, relos map[string]coreRelos, err error) {
|
||||
func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, coreRelos map[string]bpfCoreRelos, err error) {
|
||||
var header btfExtHeader
|
||||
var coreHeader btfExtCoreHeader
|
||||
if err := binary.Read(r, bo, &header); err != nil {
|
||||
@ -94,13 +94,13 @@ func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (f
|
||||
return nil, nil, nil, fmt.Errorf("can't seek to CO-RE relocation section: %v", err)
|
||||
}
|
||||
|
||||
relos, err = parseExtInfoRelos(io.LimitReader(r, int64(coreHeader.CoreReloLen)), bo, strings)
|
||||
coreRelos, err = parseExtInfoRelos(io.LimitReader(r, int64(coreHeader.CoreReloLen)), bo, strings)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("CO-RE relocation info: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return funcInfo, lineInfo, relos, nil
|
||||
return funcInfo, lineInfo, coreRelos, nil
|
||||
}
|
||||
|
||||
type btfExtInfoSec struct {
|
||||
@ -208,25 +208,18 @@ type bpfCoreRelo struct {
|
||||
InsnOff uint32
|
||||
TypeID TypeID
|
||||
AccessStrOff uint32
|
||||
Kind COREKind
|
||||
ReloKind coreReloKind
|
||||
}
|
||||
|
||||
type coreRelo struct {
|
||||
insnOff uint32
|
||||
typeID TypeID
|
||||
accessor coreAccessor
|
||||
kind COREKind
|
||||
}
|
||||
|
||||
type coreRelos []coreRelo
|
||||
type bpfCoreRelos []bpfCoreRelo
|
||||
|
||||
// append two slices of extInfoRelo to each other. The InsnOff of b are adjusted
|
||||
// by offset.
|
||||
func (r coreRelos) append(other coreRelos, offset uint64) coreRelos {
|
||||
result := make([]coreRelo, 0, len(r)+len(other))
|
||||
func (r bpfCoreRelos) append(other bpfCoreRelos, offset uint64) bpfCoreRelos {
|
||||
result := make([]bpfCoreRelo, 0, len(r)+len(other))
|
||||
result = append(result, r...)
|
||||
for _, relo := range other {
|
||||
relo.insnOff += uint32(offset)
|
||||
relo.InsnOff += uint32(offset)
|
||||
result = append(result, relo)
|
||||
}
|
||||
return result
|
||||
@ -234,7 +227,7 @@ func (r coreRelos) append(other coreRelos, offset uint64) coreRelos {
|
||||
|
||||
var extInfoReloSize = binary.Size(bpfCoreRelo{})
|
||||
|
||||
func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]coreRelos, error) {
|
||||
func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]bpfCoreRelos, error) {
|
||||
var recordSize uint32
|
||||
if err := binary.Read(r, bo, &recordSize); err != nil {
|
||||
return nil, fmt.Errorf("read record size: %v", err)
|
||||
@ -244,14 +237,14 @@ func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (m
|
||||
return nil, fmt.Errorf("expected record size %d, got %d", extInfoReloSize, recordSize)
|
||||
}
|
||||
|
||||
result := make(map[string]coreRelos)
|
||||
result := make(map[string]bpfCoreRelos)
|
||||
for {
|
||||
secName, infoHeader, err := parseExtInfoHeader(r, bo, strings)
|
||||
if errors.Is(err, io.EOF) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
var relos coreRelos
|
||||
var relos []bpfCoreRelo
|
||||
for i := uint32(0); i < infoHeader.NumInfo; i++ {
|
||||
var relo bpfCoreRelo
|
||||
if err := binary.Read(r, bo, &relo); err != nil {
|
||||
@ -262,22 +255,7 @@ func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (m
|
||||
return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, relo.InsnOff)
|
||||
}
|
||||
|
||||
accessorStr, err := strings.Lookup(relo.AccessStrOff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessor, err := parseCoreAccessor(accessorStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("accessor %q: %s", accessorStr, err)
|
||||
}
|
||||
|
||||
relos = append(relos, coreRelo{
|
||||
relo.InsnOff,
|
||||
relo.TypeID,
|
||||
accessor,
|
||||
relo.Kind,
|
||||
})
|
||||
relos = append(relos, relo)
|
||||
}
|
||||
|
||||
result[secName] = relos
|
||||
|
46
vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
46
vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
@ -1,6 +1,7 @@
|
||||
package btf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
@ -36,7 +37,6 @@ type Type interface {
|
||||
type namedType interface {
|
||||
Type
|
||||
name() string
|
||||
essentialName() string
|
||||
}
|
||||
|
||||
// Name identifies a type.
|
||||
@ -48,10 +48,6 @@ func (n Name) name() string {
|
||||
return string(n)
|
||||
}
|
||||
|
||||
func (n Name) essentialName() string {
|
||||
return essentialName(string(n))
|
||||
}
|
||||
|
||||
// Void is the unit type of BTF.
|
||||
type Void struct{}
|
||||
|
||||
@ -178,7 +174,8 @@ func (s *Struct) walk(tdq *typeDeque) {
|
||||
|
||||
func (s *Struct) copy() Type {
|
||||
cpy := *s
|
||||
cpy.Members = copyMembers(s.Members)
|
||||
cpy.Members = make([]Member, len(s.Members))
|
||||
copy(cpy.Members, s.Members)
|
||||
return &cpy
|
||||
}
|
||||
|
||||
@ -209,7 +206,8 @@ func (u *Union) walk(tdq *typeDeque) {
|
||||
|
||||
func (u *Union) copy() Type {
|
||||
cpy := *u
|
||||
cpy.Members = copyMembers(u.Members)
|
||||
cpy.Members = make([]Member, len(u.Members))
|
||||
copy(cpy.Members, u.Members)
|
||||
return &cpy
|
||||
}
|
||||
|
||||
@ -217,12 +215,6 @@ func (u *Union) members() []Member {
|
||||
return u.Members
|
||||
}
|
||||
|
||||
func copyMembers(orig []Member) []Member {
|
||||
cpy := make([]Member, len(orig))
|
||||
copy(cpy, orig)
|
||||
return cpy
|
||||
}
|
||||
|
||||
type composite interface {
|
||||
members() []Member
|
||||
}
|
||||
@ -519,7 +511,7 @@ func Sizeof(typ Type) (int, error) {
|
||||
switch v := typ.(type) {
|
||||
case *Array:
|
||||
if n > 0 && int64(v.Nelems) > math.MaxInt64/n {
|
||||
return 0, fmt.Errorf("type %s: overflow", typ)
|
||||
return 0, errors.New("overflow")
|
||||
}
|
||||
|
||||
// Arrays may be of zero length, which allows
|
||||
@ -540,30 +532,28 @@ func Sizeof(typ Type) (int, error) {
|
||||
continue
|
||||
|
||||
default:
|
||||
return 0, fmt.Errorf("unsized type %T", typ)
|
||||
return 0, fmt.Errorf("unrecognized type %T", typ)
|
||||
}
|
||||
|
||||
if n > 0 && elem > math.MaxInt64/n {
|
||||
return 0, fmt.Errorf("type %s: overflow", typ)
|
||||
return 0, errors.New("overflow")
|
||||
}
|
||||
|
||||
size := n * elem
|
||||
if int64(int(size)) != size {
|
||||
return 0, fmt.Errorf("type %s: overflow", typ)
|
||||
return 0, errors.New("overflow")
|
||||
}
|
||||
|
||||
return int(size), nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("type %s: exceeded type depth", typ)
|
||||
return 0, errors.New("exceeded type depth")
|
||||
}
|
||||
|
||||
// copy a Type recursively.
|
||||
//
|
||||
// typ may form a cycle.
|
||||
//
|
||||
// Returns any errors from transform verbatim.
|
||||
func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) {
|
||||
func copyType(typ Type) Type {
|
||||
var (
|
||||
copies = make(map[Type]Type)
|
||||
work typeDeque
|
||||
@ -576,17 +566,7 @@ func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
var cpy Type
|
||||
if transform != nil {
|
||||
tf, err := transform(*t)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copy %s: %w", typ, err)
|
||||
}
|
||||
cpy = tf.copy()
|
||||
} else {
|
||||
cpy = (*t).copy()
|
||||
}
|
||||
|
||||
cpy := (*t).copy()
|
||||
copies[*t] = cpy
|
||||
*t = cpy
|
||||
|
||||
@ -594,7 +574,7 @@ func copyType(typ Type, transform func(Type) (Type, error)) (Type, error) {
|
||||
cpy.walk(&work)
|
||||
}
|
||||
|
||||
return typ, nil
|
||||
return typ
|
||||
}
|
||||
|
||||
// typeDeque keeps track of pointers to types which still
|
||||
|
16
vendor/github.com/cilium/ebpf/internal/elf.go
generated
vendored
16
vendor/github.com/cilium/ebpf/internal/elf.go
generated
vendored
@ -50,19 +50,3 @@ func (se *SafeELFFile) Symbols() (syms []elf.Symbol, err error) {
|
||||
syms, err = se.File.Symbols()
|
||||
return
|
||||
}
|
||||
|
||||
// DynamicSymbols is the safe version of elf.File.DynamicSymbols.
|
||||
func (se *SafeELFFile) DynamicSymbols() (syms []elf.Symbol, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
syms = nil
|
||||
err = fmt.Errorf("reading ELF dynamic symbols panicked: %s", r)
|
||||
}()
|
||||
|
||||
syms, err = se.File.DynamicSymbols()
|
||||
return
|
||||
}
|
||||
|
5
vendor/github.com/cilium/ebpf/internal/endian.go
generated
vendored
5
vendor/github.com/cilium/ebpf/internal/endian.go
generated
vendored
@ -9,16 +9,11 @@ import (
|
||||
// depending on the host's endianness.
|
||||
var NativeEndian binary.ByteOrder
|
||||
|
||||
// Clang is set to either "el" or "eb" depending on the host's endianness.
|
||||
var ClangEndian string
|
||||
|
||||
func init() {
|
||||
if isBigEndian() {
|
||||
NativeEndian = binary.BigEndian
|
||||
ClangEndian = "eb"
|
||||
} else {
|
||||
NativeEndian = binary.LittleEndian
|
||||
ClangEndian = "el"
|
||||
}
|
||||
}
|
||||
|
||||
|
4
vendor/github.com/cilium/ebpf/internal/errors.go
generated
vendored
4
vendor/github.com/cilium/ebpf/internal/errors.go
generated
vendored
@ -29,10 +29,6 @@ type VerifierError struct {
|
||||
log string
|
||||
}
|
||||
|
||||
func (le *VerifierError) Unwrap() error {
|
||||
return le.cause
|
||||
}
|
||||
|
||||
func (le *VerifierError) Error() string {
|
||||
if le.log == "" {
|
||||
return le.cause.Error()
|
||||
|
4
vendor/github.com/cilium/ebpf/internal/ptr.go
generated
vendored
4
vendor/github.com/cilium/ebpf/internal/ptr.go
generated
vendored
@ -22,6 +22,10 @@ func NewSlicePointer(buf []byte) Pointer {
|
||||
|
||||
// NewStringPointer creates a 64-bit pointer from a string.
|
||||
func NewStringPointer(str string) Pointer {
|
||||
if str == "" {
|
||||
return Pointer{}
|
||||
}
|
||||
|
||||
p, err := unix.BytePtrFromString(str)
|
||||
if err != nil {
|
||||
return Pointer{}
|
||||
|
1
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
1
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
@ -42,7 +42,6 @@ const (
|
||||
PROT_READ = linux.PROT_READ
|
||||
PROT_WRITE = linux.PROT_WRITE
|
||||
MAP_SHARED = linux.MAP_SHARED
|
||||
PERF_ATTR_SIZE_VER1 = linux.PERF_ATTR_SIZE_VER1
|
||||
PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE
|
||||
PERF_TYPE_TRACEPOINT = linux.PERF_TYPE_TRACEPOINT
|
||||
PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT
|
||||
|
1
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
1
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
@ -43,7 +43,6 @@ const (
|
||||
PROT_READ = 0x1
|
||||
PROT_WRITE = 0x2
|
||||
MAP_SHARED = 0x1
|
||||
PERF_ATTR_SIZE_VER1 = 0
|
||||
PERF_TYPE_SOFTWARE = 0x1
|
||||
PERF_TYPE_TRACEPOINT = 0
|
||||
PERF_COUNT_SW_BPF_OUTPUT = 0xa
|
||||
|
286
vendor/github.com/cilium/ebpf/link/kprobe.go
generated
vendored
286
vendor/github.com/cilium/ebpf/link/kprobe.go
generated
vendored
@ -1,16 +1,12 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
@ -19,60 +15,13 @@ import (
|
||||
|
||||
var (
|
||||
kprobeEventsPath = filepath.Join(tracefsPath, "kprobe_events")
|
||||
|
||||
kprobeRetprobeBit = struct {
|
||||
once sync.Once
|
||||
value uint64
|
||||
err error
|
||||
}{}
|
||||
)
|
||||
|
||||
type probeType uint8
|
||||
|
||||
const (
|
||||
kprobeType probeType = iota
|
||||
uprobeType
|
||||
)
|
||||
|
||||
func (pt probeType) String() string {
|
||||
if pt == kprobeType {
|
||||
return "kprobe"
|
||||
}
|
||||
return "uprobe"
|
||||
}
|
||||
|
||||
func (pt probeType) EventsPath() string {
|
||||
if pt == kprobeType {
|
||||
return kprobeEventsPath
|
||||
}
|
||||
return uprobeEventsPath
|
||||
}
|
||||
|
||||
func (pt probeType) PerfEventType(ret bool) perfEventType {
|
||||
if pt == kprobeType {
|
||||
if ret {
|
||||
return kretprobeEvent
|
||||
}
|
||||
return kprobeEvent
|
||||
}
|
||||
if ret {
|
||||
return uretprobeEvent
|
||||
}
|
||||
return uprobeEvent
|
||||
}
|
||||
|
||||
func (pt probeType) RetprobeBit() (uint64, error) {
|
||||
if pt == kprobeType {
|
||||
return kretprobeBit()
|
||||
}
|
||||
return uretprobeBit()
|
||||
}
|
||||
|
||||
// Kprobe attaches the given eBPF program to a perf event that fires when the
|
||||
// given kernel symbol starts executing. See /proc/kallsyms for available
|
||||
// symbols. For example, printk():
|
||||
//
|
||||
// Kprobe("printk", prog)
|
||||
// Kprobe("printk")
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources.
|
||||
@ -95,7 +44,7 @@ func Kprobe(symbol string, prog *ebpf.Program) (Link, error) {
|
||||
// before the given kernel symbol exits, with the function stack left intact.
|
||||
// See /proc/kallsyms for available symbols. For example, printk():
|
||||
//
|
||||
// Kretprobe("printk", prog)
|
||||
// Kretprobe("printk")
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources.
|
||||
@ -131,10 +80,7 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
|
||||
}
|
||||
|
||||
// Use kprobe PMU if the kernel has it available.
|
||||
tp, err := pmuKprobe(platformPrefix(symbol), ret)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
tp, err = pmuKprobe(symbol, ret)
|
||||
}
|
||||
tp, err := pmuKprobe(symbol, ret)
|
||||
if err == nil {
|
||||
return tp, nil
|
||||
}
|
||||
@ -143,10 +89,7 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
|
||||
}
|
||||
|
||||
// Use tracefs if kprobe PMU is missing.
|
||||
tp, err = tracefsKprobe(platformPrefix(symbol), ret)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
tp, err = tracefsKprobe(symbol, ret)
|
||||
}
|
||||
tp, err = tracefsKprobe(symbol, ret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating trace event '%s' in tracefs: %w", symbol, err)
|
||||
}
|
||||
@ -154,70 +97,36 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
// pmuKprobe opens a perf event based on the kprobe PMU.
|
||||
// Returns os.ErrNotExist if the given symbol does not exist in the kernel.
|
||||
// pmuKprobe opens a perf event based on a Performance Monitoring Unit.
|
||||
// Requires at least 4.17 (e12f03d7031a "perf/core: Implement the
|
||||
// 'perf_kprobe' PMU").
|
||||
// Returns ErrNotSupported if the kernel doesn't support perf_kprobe PMU,
|
||||
// or os.ErrNotExist if the given symbol does not exist in the kernel.
|
||||
func pmuKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
return pmuProbe(kprobeType, symbol, "", 0, ret)
|
||||
}
|
||||
|
||||
// pmuProbe opens a perf event based on a Performance Monitoring Unit.
|
||||
//
|
||||
// Requires at least a 4.17 kernel.
|
||||
// e12f03d7031a "perf/core: Implement the 'perf_kprobe' PMU"
|
||||
// 33ea4b24277b "perf/core: Implement the 'perf_uprobe' PMU"
|
||||
//
|
||||
// Returns ErrNotSupported if the kernel doesn't support perf_[k,u]probe PMU
|
||||
func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
// Getting the PMU type will fail if the kernel doesn't support
|
||||
// the perf_[k,u]probe PMU.
|
||||
et, err := getPMUEventType(typ)
|
||||
// the perf_kprobe PMU.
|
||||
et, err := getPMUEventType("kprobe")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var config uint64
|
||||
if ret {
|
||||
bit, err := typ.RetprobeBit()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config |= 1 << bit
|
||||
// Create a pointer to a NUL-terminated string for the kernel.
|
||||
sp, err := unsafeStringPtr(symbol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
attr unix.PerfEventAttr
|
||||
sp unsafe.Pointer
|
||||
)
|
||||
switch typ {
|
||||
case kprobeType:
|
||||
// Create a pointer to a NUL-terminated string for the kernel.
|
||||
sp, err := unsafeStringPtr(symbol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: Parse the position of the bit from /sys/bus/event_source/devices/%s/format/retprobe.
|
||||
config := 0
|
||||
if ret {
|
||||
config = 1
|
||||
}
|
||||
|
||||
attr = unix.PerfEventAttr{
|
||||
Type: uint32(et), // PMU event type read from sysfs
|
||||
Ext1: uint64(uintptr(sp)), // Kernel symbol to trace
|
||||
Config: config, // Retprobe flag
|
||||
}
|
||||
case uprobeType:
|
||||
sp, err := unsafeStringPtr(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attr = unix.PerfEventAttr{
|
||||
// The minimum size required for PMU uprobes is PERF_ATTR_SIZE_VER1,
|
||||
// since it added the config2 (Ext2) field. The Size field controls the
|
||||
// size of the internal buffer the kernel allocates for reading the
|
||||
// perf_event_attr argument from userspace.
|
||||
Size: unix.PERF_ATTR_SIZE_VER1,
|
||||
Type: uint32(et), // PMU event type read from sysfs
|
||||
Ext1: uint64(uintptr(sp)), // Uprobe path
|
||||
Ext2: offset, // Uprobe offset
|
||||
Config: config, // Retprobe flag
|
||||
}
|
||||
attr := unix.PerfEventAttr{
|
||||
Type: uint32(et), // PMU event type read from sysfs
|
||||
Ext1: uint64(uintptr(sp)), // Kernel symbol to trace
|
||||
Config: uint64(config), // perf_kprobe PMU treats config as flags
|
||||
}
|
||||
|
||||
fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
|
||||
@ -235,27 +144,22 @@ func pmuProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*per
|
||||
// Ensure the string pointer is not collected before PerfEventOpen returns.
|
||||
runtime.KeepAlive(sp)
|
||||
|
||||
// Kernel has perf_[k,u]probe PMU available, initialize perf event.
|
||||
// Kernel has perf_kprobe PMU available, initialize perf event.
|
||||
return &perfEvent{
|
||||
fd: internal.NewFD(uint32(fd)),
|
||||
pmuID: et,
|
||||
name: symbol,
|
||||
typ: typ.PerfEventType(ret),
|
||||
fd: internal.NewFD(uint32(fd)),
|
||||
pmuID: et,
|
||||
name: symbol,
|
||||
ret: ret,
|
||||
progType: ebpf.Kprobe,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// tracefsKprobe creates a Kprobe tracefs entry.
|
||||
func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
return tracefsProbe(kprobeType, symbol, "", 0, ret)
|
||||
}
|
||||
|
||||
// tracefsProbe creates a trace event by writing an entry to <tracefs>/[k,u]probe_events.
|
||||
// tracefsKprobe creates a trace event by writing an entry to <tracefs>/kprobe_events.
|
||||
// A new trace event group name is generated on every call to support creating
|
||||
// multiple trace events for the same kernel or userspace symbol.
|
||||
// Path and offset are only set in the case of uprobe(s) and are used to set
|
||||
// the executable/library path on the filesystem and the offset where the probe is inserted.
|
||||
// A perf event is then opened on the newly-created trace event and returned to the caller.
|
||||
func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
// multiple trace events for the same kernel symbol. A perf event is then opened
|
||||
// on the newly-created trace event and returned to the caller.
|
||||
func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
|
||||
// Generate a random string for each trace event we attempt to create.
|
||||
// This value is used as the 'group' token in tracefs to allow creating
|
||||
// multiple kprobe trace events with the same name.
|
||||
@ -272,13 +176,14 @@ func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) (
|
||||
if err == nil {
|
||||
return nil, fmt.Errorf("trace event already exists: %s/%s", group, symbol)
|
||||
}
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
// The read is expected to fail with ErrNotSupported due to a non-existing event.
|
||||
if err != nil && !errors.Is(err, ErrNotSupported) {
|
||||
return nil, fmt.Errorf("checking trace event %s/%s: %w", group, symbol, err)
|
||||
}
|
||||
|
||||
// Create the [k,u]probe trace event using tracefs.
|
||||
if err := createTraceFSProbeEvent(typ, group, symbol, path, offset, ret); err != nil {
|
||||
return nil, fmt.Errorf("creating probe entry on tracefs: %w", err)
|
||||
// Create the kprobe trace event using tracefs.
|
||||
if err := createTraceFSKprobeEvent(group, symbol, ret); err != nil {
|
||||
return nil, fmt.Errorf("creating kprobe event on tracefs: %w", err)
|
||||
}
|
||||
|
||||
// Get the newly-created trace event's id.
|
||||
@ -297,83 +202,65 @@ func tracefsProbe(typ probeType, symbol, path string, offset uint64, ret bool) (
|
||||
fd: fd,
|
||||
group: group,
|
||||
name: symbol,
|
||||
ret: ret,
|
||||
tracefsID: tid,
|
||||
typ: typ.PerfEventType(ret),
|
||||
progType: ebpf.Kprobe, // kernel only allows attaching kprobe programs to kprobe events
|
||||
}, nil
|
||||
}
|
||||
|
||||
// createTraceFSProbeEvent creates a new ephemeral trace event by writing to
|
||||
// <tracefs>/[k,u]probe_events. Returns os.ErrNotExist if symbol is not a valid
|
||||
// kernel symbol, or if it is not traceable with kprobes. Returns os.ErrExist
|
||||
// if a probe with the same group and symbol already exists.
|
||||
func createTraceFSProbeEvent(typ probeType, group, symbol, path string, offset uint64, ret bool) error {
|
||||
// createTraceFSKprobeEvent creates a new ephemeral trace event by writing to
|
||||
// <tracefs>/kprobe_events. Returns ErrNotSupported if symbol is not a valid
|
||||
// kernel symbol, or if it is not traceable with kprobes.
|
||||
func createTraceFSKprobeEvent(group, symbol string, ret bool) error {
|
||||
// Open the kprobe_events file in tracefs.
|
||||
f, err := os.OpenFile(typ.EventsPath(), os.O_APPEND|os.O_WRONLY, 0666)
|
||||
f, err := os.OpenFile(kprobeEventsPath, os.O_APPEND|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening '%s': %w", typ.EventsPath(), err)
|
||||
return fmt.Errorf("error opening kprobe_events: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var pe string
|
||||
switch typ {
|
||||
case kprobeType:
|
||||
// The kprobe_events syntax is as follows (see Documentation/trace/kprobetrace.txt):
|
||||
// p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe
|
||||
// r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe
|
||||
// -:[GRP/]EVENT : Clear a probe
|
||||
//
|
||||
// Some examples:
|
||||
// r:ebpf_1234/r_my_kretprobe nf_conntrack_destroy
|
||||
// p:ebpf_5678/p_my_kprobe __x64_sys_execve
|
||||
//
|
||||
// Leaving the kretprobe's MAXACTIVE set to 0 (or absent) will make the
|
||||
// kernel default to NR_CPUS. This is desired in most eBPF cases since
|
||||
// subsampling or rate limiting logic can be more accurately implemented in
|
||||
// the eBPF program itself.
|
||||
// See Documentation/kprobes.txt for more details.
|
||||
pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(ret), group, symbol, symbol)
|
||||
case uprobeType:
|
||||
// The uprobe_events syntax is as follows:
|
||||
// p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a probe
|
||||
// r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a return probe
|
||||
// -:[GRP/]EVENT : Clear a probe
|
||||
//
|
||||
// Some examples:
|
||||
// r:ebpf_1234/readline /bin/bash:0x12345
|
||||
// p:ebpf_5678/main_mySymbol /bin/mybin:0x12345
|
||||
//
|
||||
// See Documentation/trace/uprobetracer.txt for more details.
|
||||
pathOffset := uprobePathOffset(path, offset)
|
||||
pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(ret), group, symbol, pathOffset)
|
||||
}
|
||||
// The kprobe_events syntax is as follows (see Documentation/trace/kprobetrace.txt):
|
||||
// p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe
|
||||
// r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe
|
||||
// -:[GRP/]EVENT : Clear a probe
|
||||
//
|
||||
// Some examples:
|
||||
// r:ebpf_1234/r_my_kretprobe nf_conntrack_destroy
|
||||
// p:ebpf_5678/p_my_kprobe __x64_sys_execve
|
||||
//
|
||||
// Leaving the kretprobe's MAXACTIVE set to 0 (or absent) will make the
|
||||
// kernel default to NR_CPUS. This is desired in most eBPF cases since
|
||||
// subsampling or rate limiting logic can be more accurately implemented in
|
||||
// the eBPF program itself. See Documentation/kprobes.txt for more details.
|
||||
pe := fmt.Sprintf("%s:%s/%s %s", kprobePrefix(ret), group, symbol, symbol)
|
||||
_, err = f.WriteString(pe)
|
||||
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
|
||||
// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
|
||||
// is returned to the caller.
|
||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
||||
return fmt.Errorf("symbol %s not found: %w", symbol, os.ErrNotExist)
|
||||
return fmt.Errorf("kernel symbol %s not found: %w", symbol, os.ErrNotExist)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err)
|
||||
return fmt.Errorf("writing '%s' to kprobe_events: %w", pe, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// closeTraceFSProbeEvent removes the [k,u]probe with the given type, group and symbol
|
||||
// from <tracefs>/[k,u]probe_events.
|
||||
func closeTraceFSProbeEvent(typ probeType, group, symbol string) error {
|
||||
f, err := os.OpenFile(typ.EventsPath(), os.O_APPEND|os.O_WRONLY, 0666)
|
||||
// closeTraceFSKprobeEvent removes the kprobe with the given group, symbol and kind
|
||||
// from <tracefs>/kprobe_events.
|
||||
func closeTraceFSKprobeEvent(group, symbol string) error {
|
||||
f, err := os.OpenFile(kprobeEventsPath, os.O_APPEND|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening %s: %w", typ.EventsPath(), err)
|
||||
return fmt.Errorf("error opening kprobe_events: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// See [k,u]probe_events syntax above. The probe type does not need to be specified
|
||||
// See kprobe_events syntax above. Kprobe type does not need to be specified
|
||||
// for removals.
|
||||
pe := fmt.Sprintf("-:%s/%s", group, symbol)
|
||||
if _, err = f.WriteString(pe); err != nil {
|
||||
return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err)
|
||||
return fmt.Errorf("writing '%s' to kprobe_events: %w", pe, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -401,38 +288,9 @@ func randomGroup(prefix string) (string, error) {
|
||||
return group, nil
|
||||
}
|
||||
|
||||
func probePrefix(ret bool) string {
|
||||
func kprobePrefix(ret bool) string {
|
||||
if ret {
|
||||
return "r"
|
||||
}
|
||||
return "p"
|
||||
}
|
||||
|
||||
// determineRetprobeBit reads a Performance Monitoring Unit's retprobe bit
|
||||
// from /sys/bus/event_source/devices/<pmu>/format/retprobe.
|
||||
func determineRetprobeBit(typ probeType) (uint64, error) {
|
||||
p := filepath.Join("/sys/bus/event_source/devices/", typ.String(), "/format/retprobe")
|
||||
|
||||
data, err := ioutil.ReadFile(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var rp uint64
|
||||
n, err := fmt.Sscanf(string(bytes.TrimSpace(data)), "config:%d", &rp)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("parse retprobe bit: %w", err)
|
||||
}
|
||||
if n != 1 {
|
||||
return 0, fmt.Errorf("parse retprobe bit: expected 1 item, got %d", n)
|
||||
}
|
||||
|
||||
return rp, nil
|
||||
}
|
||||
|
||||
func kretprobeBit() (uint64, error) {
|
||||
kprobeRetprobeBit.once.Do(func() {
|
||||
kprobeRetprobeBit.value, kprobeRetprobeBit.err = determineRetprobeBit(kprobeType)
|
||||
})
|
||||
return kprobeRetprobeBit.value, kprobeRetprobeBit.err
|
||||
}
|
||||
|
78
vendor/github.com/cilium/ebpf/link/perf_event.go
generated
vendored
78
vendor/github.com/cilium/ebpf/link/perf_event.go
generated
vendored
@ -31,10 +31,6 @@ import (
|
||||
// exported kernel symbols. kprobe-based (tracefs) trace events can be
|
||||
// created system-wide by writing to the <tracefs>/kprobe_events file, or
|
||||
// they can be scoped to the current process by creating PMU perf events.
|
||||
// - u(ret)probe: Ephemeral trace events based on user provides ELF binaries
|
||||
// and offsets. uprobe-based (tracefs) trace events can be
|
||||
// created system-wide by writing to the <tracefs>/uprobe_events file, or
|
||||
// they can be scoped to the current process by creating PMU perf events.
|
||||
// - perf event: An object instantiated based on an existing trace event or
|
||||
// kernel symbol. Referred to by fd in userspace.
|
||||
// Exactly one eBPF program can be attached to a perf event. Multiple perf
|
||||
@ -56,16 +52,6 @@ const (
|
||||
perfAllThreads = -1
|
||||
)
|
||||
|
||||
type perfEventType uint8
|
||||
|
||||
const (
|
||||
tracepointEvent perfEventType = iota
|
||||
kprobeEvent
|
||||
kretprobeEvent
|
||||
uprobeEvent
|
||||
uretprobeEvent
|
||||
)
|
||||
|
||||
// A perfEvent represents a perf event kernel object. Exactly one eBPF program
|
||||
// can be attached to it. It is created based on a tracefs trace event or a
|
||||
// Performance Monitoring Unit (PMU).
|
||||
@ -80,10 +66,11 @@ type perfEvent struct {
|
||||
// ID of the trace event read from tracefs. Valid IDs are non-zero.
|
||||
tracefsID uint64
|
||||
|
||||
// The event type determines the types of programs that can be attached.
|
||||
typ perfEventType
|
||||
// True for kretprobes/uretprobes.
|
||||
ret bool
|
||||
|
||||
fd *internal.FD
|
||||
fd *internal.FD
|
||||
progType ebpf.ProgramType
|
||||
}
|
||||
|
||||
func (pe *perfEvent) isLink() {}
|
||||
@ -130,18 +117,13 @@ func (pe *perfEvent) Close() error {
|
||||
return fmt.Errorf("closing perf event fd: %w", err)
|
||||
}
|
||||
|
||||
switch pe.typ {
|
||||
case kprobeEvent, kretprobeEvent:
|
||||
// Clean up kprobe tracefs entry.
|
||||
switch t := pe.progType; t {
|
||||
case ebpf.Kprobe:
|
||||
// For kprobes created using tracefs, clean up the <tracefs>/kprobe_events entry.
|
||||
if pe.tracefsID != 0 {
|
||||
return closeTraceFSProbeEvent(kprobeType, pe.group, pe.name)
|
||||
return closeTraceFSKprobeEvent(pe.group, pe.name)
|
||||
}
|
||||
case uprobeEvent, uretprobeEvent:
|
||||
// Clean up uprobe tracefs entry.
|
||||
if pe.tracefsID != 0 {
|
||||
return closeTraceFSProbeEvent(uprobeType, pe.group, pe.name)
|
||||
}
|
||||
case tracepointEvent:
|
||||
case ebpf.TracePoint:
|
||||
// Tracepoint trace events don't hold any extra resources.
|
||||
return nil
|
||||
}
|
||||
@ -159,21 +141,12 @@ func (pe *perfEvent) attach(prog *ebpf.Program) error {
|
||||
if pe.fd == nil {
|
||||
return errors.New("cannot attach to nil perf event")
|
||||
}
|
||||
if t := prog.Type(); t != pe.progType {
|
||||
return fmt.Errorf("invalid program type (expected %s): %s", pe.progType, t)
|
||||
}
|
||||
if prog.FD() < 0 {
|
||||
return fmt.Errorf("invalid program: %w", internal.ErrClosedFd)
|
||||
}
|
||||
switch pe.typ {
|
||||
case kprobeEvent, kretprobeEvent, uprobeEvent, uretprobeEvent:
|
||||
if t := prog.Type(); t != ebpf.Kprobe {
|
||||
return fmt.Errorf("invalid program type (expected %s): %s", ebpf.Kprobe, t)
|
||||
}
|
||||
case tracepointEvent:
|
||||
if t := prog.Type(); t != ebpf.TracePoint {
|
||||
return fmt.Errorf("invalid program type (expected %s): %s", ebpf.TracePoint, t)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown perf event type: %d", pe.typ)
|
||||
}
|
||||
|
||||
// The ioctl below will fail when the fd is invalid.
|
||||
kfd, _ := pe.fd.Value()
|
||||
@ -207,8 +180,8 @@ func unsafeStringPtr(str string) (unsafe.Pointer, error) {
|
||||
// group and name must be alphanumeric or underscore, as required by the kernel.
|
||||
func getTraceEventID(group, name string) (uint64, error) {
|
||||
tid, err := uint64FromFile(tracefsPath, "events", group, name, "id")
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return 0, fmt.Errorf("trace event %s/%s: %w", group, name, os.ErrNotExist)
|
||||
if errors.Is(err, ErrNotSupported) {
|
||||
return 0, fmt.Errorf("trace event %s/%s: %w", group, name, ErrNotSupported)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading trace event ID of %s/%s: %w", group, name, err)
|
||||
@ -219,22 +192,20 @@ func getTraceEventID(group, name string) (uint64, error) {
|
||||
|
||||
// getPMUEventType reads a Performance Monitoring Unit's type (numeric identifier)
|
||||
// from /sys/bus/event_source/devices/<pmu>/type.
|
||||
//
|
||||
// Returns ErrNotSupported if the pmu type is not supported.
|
||||
func getPMUEventType(typ probeType) (uint64, error) {
|
||||
et, err := uint64FromFile("/sys/bus/event_source/devices", typ.String(), "type")
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return 0, fmt.Errorf("pmu type %s: %w", typ, ErrNotSupported)
|
||||
func getPMUEventType(pmu string) (uint64, error) {
|
||||
et, err := uint64FromFile("/sys/bus/event_source/devices", pmu, "type")
|
||||
if errors.Is(err, ErrNotSupported) {
|
||||
return 0, fmt.Errorf("pmu type %s: %w", pmu, ErrNotSupported)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading pmu type %s: %w", typ, err)
|
||||
return 0, fmt.Errorf("reading pmu type %s: %w", pmu, err)
|
||||
}
|
||||
|
||||
return et, nil
|
||||
}
|
||||
|
||||
// openTracepointPerfEvent opens a tracepoint-type perf event. System-wide
|
||||
// [k,u]probes created by writing to <tracefs>/[k,u]probe_events are tracepoints
|
||||
// kprobes created by writing to <tracefs>/kprobe_events are tracepoints
|
||||
// behind the scenes, and can be attached to using these perf events.
|
||||
func openTracepointPerfEvent(tid uint64) (*internal.FD, error) {
|
||||
attr := unix.PerfEventAttr{
|
||||
@ -257,13 +228,22 @@ func openTracepointPerfEvent(tid uint64) (*internal.FD, error) {
|
||||
// and joined onto base. Returns error if base no longer prefixes the path after
|
||||
// joining all components.
|
||||
func uint64FromFile(base string, path ...string) (uint64, error) {
|
||||
|
||||
// Resolve leaf path separately for error feedback. Makes the join onto
|
||||
// base more readable (can't mix with variadic args).
|
||||
l := filepath.Join(path...)
|
||||
|
||||
p := filepath.Join(base, l)
|
||||
if !strings.HasPrefix(p, base) {
|
||||
return 0, fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(p)
|
||||
if os.IsNotExist(err) {
|
||||
// Only echo leaf path, the base path can be prepended at the call site
|
||||
// if more verbosity is required.
|
||||
return 0, fmt.Errorf("symbol %s: %w", l, ErrNotSupported)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading file %s: %w", p, err)
|
||||
}
|
||||
|
25
vendor/github.com/cilium/ebpf/link/platform.go
generated
vendored
25
vendor/github.com/cilium/ebpf/link/platform.go
generated
vendored
@ -1,25 +0,0 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func platformPrefix(symbol string) string {
|
||||
|
||||
prefix := runtime.GOARCH
|
||||
|
||||
// per https://github.com/golang/go/blob/master/src/go/build/syslist.go
|
||||
switch prefix {
|
||||
case "386":
|
||||
prefix = "ia32"
|
||||
case "amd64", "amd64p32":
|
||||
prefix = "x64"
|
||||
case "arm64", "arm64be":
|
||||
prefix = "arm64"
|
||||
default:
|
||||
return symbol
|
||||
}
|
||||
|
||||
return fmt.Sprintf("__%s_%s", prefix, symbol)
|
||||
}
|
4
vendor/github.com/cilium/ebpf/link/program.go
generated
vendored
4
vendor/github.com/cilium/ebpf/link/program.go
generated
vendored
@ -43,7 +43,7 @@ func RawAttachProgram(opts RawAttachProgramOptions) error {
|
||||
}
|
||||
|
||||
if err := internal.BPFProgAttach(&attr); err != nil {
|
||||
return fmt.Errorf("can't attach program: %w", err)
|
||||
return fmt.Errorf("can't attach program: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -69,7 +69,7 @@ func RawDetachProgram(opts RawDetachProgramOptions) error {
|
||||
AttachType: uint32(opts.Attach),
|
||||
}
|
||||
if err := internal.BPFProgDetach(&attr); err != nil {
|
||||
return fmt.Errorf("can't detach program: %w", err)
|
||||
return fmt.Errorf("can't detach program: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
4
vendor/github.com/cilium/ebpf/link/tracepoint.go
generated
vendored
4
vendor/github.com/cilium/ebpf/link/tracepoint.go
generated
vendored
@ -11,7 +11,7 @@ import (
|
||||
// tracepoints. The top-level directory is the group, the event's subdirectory
|
||||
// is the name. Example:
|
||||
//
|
||||
// Tracepoint("syscalls", "sys_enter_fork", prog)
|
||||
// Tracepoint("syscalls", "sys_enter_fork")
|
||||
//
|
||||
// Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is
|
||||
// only possible as of kernel 4.14 (commit cf5f5ce).
|
||||
@ -44,7 +44,7 @@ func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) {
|
||||
tracefsID: tid,
|
||||
group: group,
|
||||
name: name,
|
||||
typ: tracepointEvent,
|
||||
progType: ebpf.TracePoint,
|
||||
}
|
||||
|
||||
if err := pe.attach(prog); err != nil {
|
||||
|
207
vendor/github.com/cilium/ebpf/link/uprobe.go
generated
vendored
207
vendor/github.com/cilium/ebpf/link/uprobe.go
generated
vendored
@ -1,207 +0,0 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sync"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
uprobeEventsPath = filepath.Join(tracefsPath, "uprobe_events")
|
||||
|
||||
// rgxUprobeSymbol is used to strip invalid characters from the uprobe symbol
|
||||
// as they are not allowed to be used as the EVENT token in tracefs.
|
||||
rgxUprobeSymbol = regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||
|
||||
uprobeRetprobeBit = struct {
|
||||
once sync.Once
|
||||
value uint64
|
||||
err error
|
||||
}{}
|
||||
)
|
||||
|
||||
// Executable defines an executable program on the filesystem.
|
||||
type Executable struct {
|
||||
// Path of the executable on the filesystem.
|
||||
path string
|
||||
// Parsed ELF symbols and dynamic symbols.
|
||||
symbols map[string]elf.Symbol
|
||||
}
|
||||
|
||||
// To open a new Executable, use:
|
||||
//
|
||||
// OpenExecutable("/bin/bash")
|
||||
//
|
||||
// The returned value can then be used to open Uprobe(s).
|
||||
func OpenExecutable(path string) (*Executable, error) {
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("path cannot be empty")
|
||||
}
|
||||
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open file '%s': %w", path, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
se, err := internal.NewSafeELFFile(f)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse ELF file: %w", err)
|
||||
}
|
||||
|
||||
var ex = Executable{
|
||||
path: path,
|
||||
symbols: make(map[string]elf.Symbol),
|
||||
}
|
||||
if err := ex.addSymbols(se.Symbols); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ex.addSymbols(se.DynamicSymbols); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ex, nil
|
||||
}
|
||||
|
||||
func (ex *Executable) addSymbols(f func() ([]elf.Symbol, error)) error {
|
||||
// elf.Symbols and elf.DynamicSymbols return ErrNoSymbols if the section is not found.
|
||||
syms, err := f()
|
||||
if err != nil && !errors.Is(err, elf.ErrNoSymbols) {
|
||||
return err
|
||||
}
|
||||
for _, s := range syms {
|
||||
ex.symbols[s.Name] = s
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ex *Executable) symbol(symbol string) (*elf.Symbol, error) {
|
||||
if s, ok := ex.symbols[symbol]; ok {
|
||||
return &s, nil
|
||||
}
|
||||
return nil, fmt.Errorf("symbol %s not found", symbol)
|
||||
}
|
||||
|
||||
// Uprobe attaches the given eBPF program to a perf event that fires when the
|
||||
// given symbol starts executing in the given Executable.
|
||||
// For example, /bin/bash::main():
|
||||
//
|
||||
// ex, _ = OpenExecutable("/bin/bash")
|
||||
// ex.Uprobe("main", prog)
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources. Functions provided by shared libraries can currently not
|
||||
// be traced and will result in an ErrNotSupported.
|
||||
func (ex *Executable) Uprobe(symbol string, prog *ebpf.Program) (Link, error) {
|
||||
u, err := ex.uprobe(symbol, prog, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = u.attach(prog)
|
||||
if err != nil {
|
||||
u.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// Uretprobe attaches the given eBPF program to a perf event that fires right
|
||||
// before the given symbol exits. For example, /bin/bash::main():
|
||||
//
|
||||
// ex, _ = OpenExecutable("/bin/bash")
|
||||
// ex.Uretprobe("main", prog)
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources. Functions provided by shared libraries can currently not
|
||||
// be traced and will result in an ErrNotSupported.
|
||||
func (ex *Executable) Uretprobe(symbol string, prog *ebpf.Program) (Link, error) {
|
||||
u, err := ex.uprobe(symbol, prog, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = u.attach(prog)
|
||||
if err != nil {
|
||||
u.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// uprobe opens a perf event for the given binary/symbol and attaches prog to it.
|
||||
// If ret is true, create a uretprobe.
|
||||
func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
|
||||
if prog == nil {
|
||||
return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
|
||||
}
|
||||
if prog.Type() != ebpf.Kprobe {
|
||||
return nil, fmt.Errorf("eBPF program type %s is not Kprobe: %w", prog.Type(), errInvalidInput)
|
||||
}
|
||||
|
||||
sym, err := ex.symbol(symbol)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("symbol '%s' not found in '%s': %w", symbol, ex.path, err)
|
||||
}
|
||||
|
||||
// Symbols with location 0 from section undef are shared library calls and
|
||||
// are relocated before the binary is executed. Dynamic linking is not
|
||||
// implemented by the library, so mark this as unsupported for now.
|
||||
if sym.Section == elf.SHN_UNDEF && sym.Value == 0 {
|
||||
return nil, fmt.Errorf("cannot resolve %s library call '%s': %w", ex.path, symbol, ErrNotSupported)
|
||||
}
|
||||
|
||||
// Use uprobe PMU if the kernel has it available.
|
||||
tp, err := pmuUprobe(sym.Name, ex.path, sym.Value, ret)
|
||||
if err == nil {
|
||||
return tp, nil
|
||||
}
|
||||
if err != nil && !errors.Is(err, ErrNotSupported) {
|
||||
return nil, fmt.Errorf("creating perf_uprobe PMU: %w", err)
|
||||
}
|
||||
|
||||
// Use tracefs if uprobe PMU is missing.
|
||||
tp, err = tracefsUprobe(uprobeSanitizedSymbol(sym.Name), ex.path, sym.Value, ret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating trace event '%s:%s' in tracefs: %w", ex.path, symbol, err)
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
// pmuUprobe opens a perf event based on the uprobe PMU.
|
||||
func pmuUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
return pmuProbe(uprobeType, symbol, path, offset, ret)
|
||||
}
|
||||
|
||||
// tracefsUprobe creates a Uprobe tracefs entry.
|
||||
func tracefsUprobe(symbol, path string, offset uint64, ret bool) (*perfEvent, error) {
|
||||
return tracefsProbe(uprobeType, symbol, path, offset, ret)
|
||||
}
|
||||
|
||||
// uprobeSanitizedSymbol replaces every invalid characted for the tracefs api with an underscore.
|
||||
func uprobeSanitizedSymbol(symbol string) string {
|
||||
return rgxUprobeSymbol.ReplaceAllString(symbol, "_")
|
||||
}
|
||||
|
||||
// uprobePathOffset creates the PATH:OFFSET token for the tracefs api.
|
||||
func uprobePathOffset(path string, offset uint64) string {
|
||||
return fmt.Sprintf("%s:%#x", path, offset)
|
||||
}
|
||||
|
||||
func uretprobeBit() (uint64, error) {
|
||||
uprobeRetprobeBit.once.Do(func() {
|
||||
uprobeRetprobeBit.value, uprobeRetprobeBit.err = determineRetprobeBit(uprobeType)
|
||||
})
|
||||
return uprobeRetprobeBit.value, uprobeRetprobeBit.err
|
||||
}
|
11
vendor/github.com/cilium/ebpf/linker.go
generated
vendored
11
vendor/github.com/cilium/ebpf/linker.go
generated
vendored
@ -108,16 +108,12 @@ func fixupJumpsAndCalls(insns asm.Instructions) error {
|
||||
offset := iter.Offset
|
||||
ins := iter.Ins
|
||||
|
||||
if ins.Reference == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case ins.IsFunctionCall() && ins.Constant == -1:
|
||||
// Rewrite bpf to bpf call
|
||||
callOffset, ok := symbolOffsets[ins.Reference]
|
||||
if !ok {
|
||||
return fmt.Errorf("call at %d: reference to missing symbol %q", i, ins.Reference)
|
||||
return fmt.Errorf("instruction %d: reference to missing symbol %q", i, ins.Reference)
|
||||
}
|
||||
|
||||
ins.Constant = int64(callOffset - offset - 1)
|
||||
@ -126,13 +122,10 @@ func fixupJumpsAndCalls(insns asm.Instructions) error {
|
||||
// Rewrite jump to label
|
||||
jumpOffset, ok := symbolOffsets[ins.Reference]
|
||||
if !ok {
|
||||
return fmt.Errorf("jump at %d: reference to missing symbol %q", i, ins.Reference)
|
||||
return fmt.Errorf("instruction %d: reference to missing symbol %q", i, ins.Reference)
|
||||
}
|
||||
|
||||
ins.Offset = int16(jumpOffset - offset - 1)
|
||||
|
||||
case ins.IsLoadFromMap() && ins.MapPtr() == -1:
|
||||
return fmt.Errorf("map %s: %w", ins.Reference, errUnsatisfiedReference)
|
||||
}
|
||||
}
|
||||
|
||||
|
50
vendor/github.com/cilium/ebpf/map.go
generated
vendored
50
vendor/github.com/cilium/ebpf/map.go
generated
vendored
@ -18,7 +18,6 @@ var (
|
||||
ErrKeyNotExist = errors.New("key does not exist")
|
||||
ErrKeyExist = errors.New("key already exists")
|
||||
ErrIterationAborted = errors.New("iteration aborted")
|
||||
ErrMapIncompatible = errors.New("map's spec is incompatible with pinned map")
|
||||
)
|
||||
|
||||
// MapOptions control loading a map into the kernel.
|
||||
@ -88,23 +87,6 @@ func (ms *MapSpec) Copy() *MapSpec {
|
||||
return &cpy
|
||||
}
|
||||
|
||||
func (ms *MapSpec) clampPerfEventArraySize() error {
|
||||
if ms.Type != PerfEventArray {
|
||||
return nil
|
||||
}
|
||||
|
||||
n, err := internal.PossibleCPUs()
|
||||
if err != nil {
|
||||
return fmt.Errorf("perf event array: %w", err)
|
||||
}
|
||||
|
||||
if n := uint32(n); ms.MaxEntries > n {
|
||||
ms.MaxEntries = n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MapKV is used to initialize the contents of a Map.
|
||||
type MapKV struct {
|
||||
Key interface{}
|
||||
@ -114,19 +96,19 @@ type MapKV struct {
|
||||
func (ms *MapSpec) checkCompatibility(m *Map) error {
|
||||
switch {
|
||||
case m.typ != ms.Type:
|
||||
return fmt.Errorf("expected type %v, got %v: %w", ms.Type, m.typ, ErrMapIncompatible)
|
||||
return fmt.Errorf("expected type %v, got %v", ms.Type, m.typ)
|
||||
|
||||
case m.keySize != ms.KeySize:
|
||||
return fmt.Errorf("expected key size %v, got %v: %w", ms.KeySize, m.keySize, ErrMapIncompatible)
|
||||
return fmt.Errorf("expected key size %v, got %v", ms.KeySize, m.keySize)
|
||||
|
||||
case m.valueSize != ms.ValueSize:
|
||||
return fmt.Errorf("expected value size %v, got %v: %w", ms.ValueSize, m.valueSize, ErrMapIncompatible)
|
||||
return fmt.Errorf("expected value size %v, got %v", ms.ValueSize, m.valueSize)
|
||||
|
||||
case m.maxEntries != ms.MaxEntries:
|
||||
return fmt.Errorf("expected max entries %v, got %v: %w", ms.MaxEntries, m.maxEntries, ErrMapIncompatible)
|
||||
return fmt.Errorf("expected max entries %v, got %v", ms.MaxEntries, m.maxEntries)
|
||||
|
||||
case m.flags != ms.Flags:
|
||||
return fmt.Errorf("expected flags %v, got %v: %w", ms.Flags, m.flags, ErrMapIncompatible)
|
||||
return fmt.Errorf("expected flags %v, got %v", ms.Flags, m.flags)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -189,16 +171,14 @@ func NewMap(spec *MapSpec) (*Map, error) {
|
||||
// The caller is responsible for ensuring the process' rlimit is set
|
||||
// sufficiently high for locking memory during map creation. This can be done
|
||||
// by calling unix.Setrlimit with unix.RLIMIT_MEMLOCK prior to calling NewMapWithOptions.
|
||||
//
|
||||
// May return an error wrapping ErrMapIncompatible.
|
||||
func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) {
|
||||
handles := newHandleCache()
|
||||
defer handles.close()
|
||||
btfs := make(btfHandleCache)
|
||||
defer btfs.close()
|
||||
|
||||
return newMapWithOptions(spec, opts, handles)
|
||||
return newMapWithOptions(spec, opts, btfs)
|
||||
}
|
||||
|
||||
func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ *Map, err error) {
|
||||
func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (_ *Map, err error) {
|
||||
closeOnError := func(c io.Closer) {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
@ -222,7 +202,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_
|
||||
defer closeOnError(m)
|
||||
|
||||
if err := spec.checkCompatibility(m); err != nil {
|
||||
return nil, fmt.Errorf("use pinned map %s: %w", spec.Name, err)
|
||||
return nil, fmt.Errorf("use pinned map %s: %s", spec.Name, err)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
@ -231,7 +211,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_
|
||||
// Nothing to do here
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("pin type %d: %w", int(spec.Pinning), ErrNotSupported)
|
||||
return nil, fmt.Errorf("unsupported pin type %d", int(spec.Pinning))
|
||||
}
|
||||
|
||||
var innerFd *internal.FD
|
||||
@ -244,7 +224,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_
|
||||
return nil, errors.New("inner maps cannot be pinned")
|
||||
}
|
||||
|
||||
template, err := createMap(spec.InnerMap, nil, opts, handles)
|
||||
template, err := createMap(spec.InnerMap, nil, opts, btfs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -253,7 +233,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_
|
||||
innerFd = template.fd
|
||||
}
|
||||
|
||||
m, err := createMap(spec, innerFd, opts, handles)
|
||||
m, err := createMap(spec, innerFd, opts, btfs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -269,7 +249,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *handleCache) (_ *Map, err error) {
|
||||
func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, btfs btfHandleCache) (_ *Map, err error) {
|
||||
closeOnError := func(closer io.Closer) {
|
||||
if err != nil {
|
||||
closer.Close()
|
||||
@ -340,7 +320,7 @@ func createMap(spec *MapSpec, inner *internal.FD, opts MapOptions, handles *hand
|
||||
|
||||
var btfDisabled bool
|
||||
if spec.BTF != nil {
|
||||
handle, err := handles.btfHandle(btf.MapSpec(spec.BTF))
|
||||
handle, err := btfs.load(btf.MapSpec(spec.BTF))
|
||||
btfDisabled = errors.Is(err, btf.ErrNotSupported)
|
||||
if err != nil && !btfDisabled {
|
||||
return nil, fmt.Errorf("load BTF: %w", err)
|
||||
|
149
vendor/github.com/cilium/ebpf/prog.go
generated
vendored
149
vendor/github.com/cilium/ebpf/prog.go
generated
vendored
@ -5,7 +5,6 @@ import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -20,8 +19,6 @@ import (
|
||||
// ErrNotSupported is returned whenever the kernel doesn't support a feature.
|
||||
var ErrNotSupported = internal.ErrNotSupported
|
||||
|
||||
var errUnsatisfiedReference = errors.New("unsatisfied reference")
|
||||
|
||||
// ProgramID represents the unique ID of an eBPF program.
|
||||
type ProgramID uint32
|
||||
|
||||
@ -44,12 +41,6 @@ type ProgramOptions struct {
|
||||
// Controls the output buffer size for the verifier. Defaults to
|
||||
// DefaultVerifierLogSize.
|
||||
LogSize int
|
||||
// An ELF containing the target BTF for this program. It is used both to
|
||||
// find the correct function to trace and to apply CO-RE relocations.
|
||||
// This is useful in environments where the kernel BTF is not available
|
||||
// (containers) or where it is in a non-standard location. Defaults to
|
||||
// use the kernel BTF from a well-known location.
|
||||
TargetBTF io.ReaderAt
|
||||
}
|
||||
|
||||
// ProgramSpec defines a Program.
|
||||
@ -134,21 +125,21 @@ func NewProgram(spec *ProgramSpec) (*Program, error) {
|
||||
// Loading a program for the first time will perform
|
||||
// feature detection by loading small, temporary programs.
|
||||
func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) {
|
||||
handles := newHandleCache()
|
||||
defer handles.close()
|
||||
btfs := make(btfHandleCache)
|
||||
defer btfs.close()
|
||||
|
||||
prog, err := newProgramWithOptions(spec, opts, handles)
|
||||
if errors.Is(err, errUnsatisfiedReference) {
|
||||
return nil, fmt.Errorf("cannot load program without loading its whole collection: %w", err)
|
||||
}
|
||||
return prog, err
|
||||
return newProgramWithOptions(spec, opts, btfs)
|
||||
}
|
||||
|
||||
func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *handleCache) (*Program, error) {
|
||||
func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandleCache) (*Program, error) {
|
||||
if len(spec.Instructions) == 0 {
|
||||
return nil, errors.New("Instructions cannot be empty")
|
||||
}
|
||||
|
||||
if len(spec.License) == 0 {
|
||||
return nil, errors.New("License cannot be empty")
|
||||
}
|
||||
|
||||
if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian {
|
||||
return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
|
||||
}
|
||||
@ -166,10 +157,27 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
kv = v.Kernel()
|
||||
}
|
||||
|
||||
insns := make(asm.Instructions, len(spec.Instructions))
|
||||
copy(insns, spec.Instructions)
|
||||
|
||||
if err := fixupJumpsAndCalls(insns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize))
|
||||
err := insns.Marshal(buf, internal.NativeEndian)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bytecode := buf.Bytes()
|
||||
insCount := uint32(len(bytecode) / asm.InstructionSize)
|
||||
attr := &bpfProgLoadAttr{
|
||||
progType: spec.Type,
|
||||
progFlags: spec.Flags,
|
||||
expectedAttachType: spec.AttachType,
|
||||
insCount: insCount,
|
||||
instructions: internal.NewSlicePointer(bytecode),
|
||||
license: internal.NewStringPointer(spec.License),
|
||||
kernelVersion: kv,
|
||||
}
|
||||
@ -178,24 +186,15 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
attr.progName = newBPFObjName(spec.Name)
|
||||
}
|
||||
|
||||
var err error
|
||||
var targetBTF *btf.Spec
|
||||
if opts.TargetBTF != nil {
|
||||
targetBTF, err = handles.btfSpec(opts.TargetBTF)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load target BTF: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var btfDisabled bool
|
||||
var core btf.COREFixups
|
||||
if spec.BTF != nil {
|
||||
core, err = btf.ProgramFixups(spec.BTF, targetBTF)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CO-RE relocations: %w", err)
|
||||
if relos, err := btf.ProgramRelocations(spec.BTF, nil); err != nil {
|
||||
return nil, fmt.Errorf("CO-RE relocations: %s", err)
|
||||
} else if len(relos) > 0 {
|
||||
return nil, fmt.Errorf("applying CO-RE relocations: %w", ErrNotSupported)
|
||||
}
|
||||
|
||||
handle, err := handles.btfHandle(btf.ProgramSpec(spec.BTF))
|
||||
handle, err := btfs.load(btf.ProgramSpec(spec.BTF))
|
||||
btfDisabled = errors.Is(err, btf.ErrNotSupported)
|
||||
if err != nil && !btfDisabled {
|
||||
return nil, fmt.Errorf("load BTF: %w", err)
|
||||
@ -222,27 +221,8 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
}
|
||||
}
|
||||
|
||||
insns, err := core.Apply(spec.Instructions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CO-RE fixup: %w", err)
|
||||
}
|
||||
|
||||
if err := fixupJumpsAndCalls(insns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize))
|
||||
err = insns.Marshal(buf, internal.NativeEndian)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bytecode := buf.Bytes()
|
||||
attr.instructions = internal.NewSlicePointer(bytecode)
|
||||
attr.insCount = uint32(len(bytecode) / asm.InstructionSize)
|
||||
|
||||
if spec.AttachTo != "" {
|
||||
target, err := resolveBTFType(targetBTF, spec.AttachTo, spec.Type, spec.AttachType)
|
||||
target, err := resolveBTFType(spec.AttachTo, spec.Type, spec.AttachType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -270,7 +250,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, handles *hand
|
||||
}
|
||||
|
||||
logErr := err
|
||||
if opts.LogLevel == 0 && opts.LogSize >= 0 {
|
||||
if opts.LogLevel == 0 {
|
||||
// Re-run with the verifier enabled to get better error messages.
|
||||
logBuf = make([]byte, logSize)
|
||||
attr.logLevel = 1
|
||||
@ -684,45 +664,52 @@ func (p *Program) ID() (ProgramID, error) {
|
||||
return ProgramID(info.id), nil
|
||||
}
|
||||
|
||||
func resolveBTFType(kernel *btf.Spec, name string, progType ProgramType, attachType AttachType) (btf.Type, error) {
|
||||
func findKernelType(name string, typ btf.Type) error {
|
||||
kernel, err := btf.LoadKernelSpec()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't load kernel spec: %w", err)
|
||||
}
|
||||
|
||||
return kernel.FindType(name, typ)
|
||||
}
|
||||
|
||||
func resolveBTFType(name string, progType ProgramType, attachType AttachType) (btf.Type, error) {
|
||||
type match struct {
|
||||
p ProgramType
|
||||
a AttachType
|
||||
}
|
||||
|
||||
var target btf.Type
|
||||
var typeName, featureName string
|
||||
switch (match{progType, attachType}) {
|
||||
target := match{progType, attachType}
|
||||
switch target {
|
||||
case match{LSM, AttachLSMMac}:
|
||||
target = new(btf.Func)
|
||||
typeName = "bpf_lsm_" + name
|
||||
featureName = name + " LSM hook"
|
||||
var target btf.Func
|
||||
err := findKernelType("bpf_lsm_"+name, &target)
|
||||
if errors.Is(err, btf.ErrNotFound) {
|
||||
return nil, &internal.UnsupportedFeatureError{
|
||||
Name: name + " LSM hook",
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolve BTF for LSM hook %s: %w", name, err)
|
||||
}
|
||||
|
||||
return &target, nil
|
||||
|
||||
case match{Tracing, AttachTraceIter}:
|
||||
target = new(btf.Func)
|
||||
typeName = "bpf_iter_" + name
|
||||
featureName = name + " iterator"
|
||||
var target btf.Func
|
||||
err := findKernelType("bpf_iter_"+name, &target)
|
||||
if errors.Is(err, btf.ErrNotFound) {
|
||||
return nil, &internal.UnsupportedFeatureError{
|
||||
Name: name + " iterator",
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolve BTF for iterator %s: %w", name, err)
|
||||
}
|
||||
|
||||
return &target, nil
|
||||
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if kernel == nil {
|
||||
var err error
|
||||
kernel, err = btf.LoadKernelSpec()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load kernel spec: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err := kernel.FindType(typeName, target)
|
||||
if errors.Is(err, btf.ErrNotFound) {
|
||||
return nil, &internal.UnsupportedFeatureError{
|
||||
Name: featureName,
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolve BTF for %s: %w", featureName, err)
|
||||
}
|
||||
return target, nil
|
||||
}
|
||||
|
125
vendor/github.com/cilium/ebpf/run-tests.sh
generated
vendored
125
vendor/github.com/cilium/ebpf/run-tests.sh
generated
vendored
@ -1,95 +1,56 @@
|
||||
#!/bin/bash
|
||||
# Test the current package under a different kernel.
|
||||
# Requires virtme and qemu to be installed.
|
||||
# Examples:
|
||||
# Run all tests on a 5.4 kernel
|
||||
# $ ./run-tests.sh 5.4
|
||||
# Run a subset of tests:
|
||||
# $ ./run-tests.sh 5.4 go test ./link
|
||||
|
||||
set -euo pipefail
|
||||
set -eu
|
||||
set -o pipefail
|
||||
|
||||
script="$(realpath "$0")"
|
||||
readonly script
|
||||
|
||||
# This script is a bit like a Matryoshka doll since it keeps re-executing itself
|
||||
# in various different contexts:
|
||||
#
|
||||
# 1. invoked by the user like run-tests.sh 5.4
|
||||
# 2. invoked by go test like run-tests.sh --exec-vm
|
||||
# 3. invoked by init in the vm like run-tests.sh --exec-test
|
||||
#
|
||||
# This allows us to use all available CPU on the host machine to compile our
|
||||
# code, and then only use the VM to execute the test. This is because the VM
|
||||
# is usually slower at compiling than the host.
|
||||
if [[ "${1:-}" = "--exec-vm" ]]; then
|
||||
shift
|
||||
|
||||
input="$1"
|
||||
shift
|
||||
|
||||
# Use sudo if /dev/kvm isn't accessible by the current user.
|
||||
sudo=""
|
||||
if [[ ! -r /dev/kvm || ! -w /dev/kvm ]]; then
|
||||
sudo="sudo"
|
||||
fi
|
||||
readonly sudo
|
||||
|
||||
testdir="$(dirname "$1")"
|
||||
output="$(mktemp -d)"
|
||||
printf -v cmd "%q " "$@"
|
||||
|
||||
if [[ "$(stat -c '%t:%T' -L /proc/$$/fd/0)" == "1:3" ]]; then
|
||||
# stdin is /dev/null, which doesn't play well with qemu. Use a fifo as a
|
||||
# blocking substitute.
|
||||
mkfifo "${output}/fake-stdin"
|
||||
# Open for reading and writing to avoid blocking.
|
||||
exec 0<> "${output}/fake-stdin"
|
||||
rm "${output}/fake-stdin"
|
||||
fi
|
||||
|
||||
$sudo virtme-run --kimg "${input}/bzImage" --memory 768M --pwd \
|
||||
--rwdir="${testdir}=${testdir}" \
|
||||
--rodir=/run/input="${input}" \
|
||||
--rwdir=/run/output="${output}" \
|
||||
--script-sh "PATH=\"$PATH\" \"$script\" --exec-test $cmd" \
|
||||
--qemu-opts -smp 2 # need at least two CPUs for some tests
|
||||
|
||||
if [[ ! -e "${output}/success" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$sudo rm -r "$output"
|
||||
exit 0
|
||||
elif [[ "${1:-}" = "--exec-test" ]]; then
|
||||
if [[ "${1:-}" = "--in-vm" ]]; then
|
||||
shift
|
||||
|
||||
mount -t bpf bpf /sys/fs/bpf
|
||||
mount -t tracefs tracefs /sys/kernel/debug/tracing
|
||||
export CGO_ENABLED=0
|
||||
export GOFLAGS=-mod=readonly
|
||||
export GOPATH=/run/go-path
|
||||
export GOPROXY=file:///run/go-path/pkg/mod/cache/download
|
||||
export GOSUMDB=off
|
||||
export GOCACHE=/run/go-cache
|
||||
|
||||
if [[ -d "/run/input/bpf" ]]; then
|
||||
export KERNEL_SELFTESTS="/run/input/bpf"
|
||||
fi
|
||||
|
||||
dmesg -C
|
||||
if ! "$@"; then
|
||||
dmesg
|
||||
exit 1
|
||||
fi
|
||||
touch "/run/output/success"
|
||||
readonly output="${1}"
|
||||
shift
|
||||
|
||||
echo Running tests...
|
||||
go test -v -coverpkg=./... -coverprofile="$output/coverage.txt" -count 1 ./...
|
||||
touch "$output/success"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Pull all dependencies, so that we can run tests without the
|
||||
# vm having network access.
|
||||
go mod download
|
||||
|
||||
# Use sudo if /dev/kvm isn't accessible by the current user.
|
||||
sudo=""
|
||||
if [[ ! -r /dev/kvm || ! -w /dev/kvm ]]; then
|
||||
sudo="sudo"
|
||||
fi
|
||||
readonly sudo
|
||||
|
||||
readonly kernel_version="${1:-}"
|
||||
if [[ -z "${kernel_version}" ]]; then
|
||||
echo "Expecting kernel version as first argument"
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
|
||||
readonly kernel="linux-${kernel_version}.bz"
|
||||
readonly selftests="linux-${kernel_version}-selftests-bpf.bz"
|
||||
readonly input="$(mktemp -d)"
|
||||
readonly output="$(mktemp -d)"
|
||||
readonly tmp_dir="${TMPDIR:-/tmp}"
|
||||
readonly branch="${BRANCH:-master}"
|
||||
|
||||
@ -99,7 +60,6 @@ fetch() {
|
||||
}
|
||||
|
||||
fetch "${kernel}"
|
||||
cp "${tmp_dir}/${kernel}" "${input}/bzImage"
|
||||
|
||||
if fetch "${selftests}"; then
|
||||
mkdir "${input}/bpf"
|
||||
@ -108,16 +68,25 @@ else
|
||||
echo "No selftests found, disabling"
|
||||
fi
|
||||
|
||||
args=(-v -short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...)
|
||||
if (( $# > 0 )); then
|
||||
args=("$@")
|
||||
echo Testing on "${kernel_version}"
|
||||
$sudo virtme-run --kimg "${tmp_dir}/${kernel}" --memory 512M --pwd \
|
||||
--rw \
|
||||
--rwdir=/run/input="${input}" \
|
||||
--rwdir=/run/output="${output}" \
|
||||
--rodir=/run/go-path="$(go env GOPATH)" \
|
||||
--rwdir=/run/go-cache="$(go env GOCACHE)" \
|
||||
--script-sh "PATH=\"$PATH\" $(realpath "$0") --in-vm /run/output" \
|
||||
--qemu-opts -smp 2 # need at least two CPUs for some tests
|
||||
|
||||
if [[ ! -e "${output}/success" ]]; then
|
||||
echo "Test failed on ${kernel_version}"
|
||||
exit 1
|
||||
else
|
||||
echo "Test successful on ${kernel_version}"
|
||||
if [[ -v COVERALLS_TOKEN ]]; then
|
||||
goveralls -coverprofile="${output}/coverage.txt" -service=semaphore -repotoken "$COVERALLS_TOKEN"
|
||||
fi
|
||||
fi
|
||||
|
||||
export GOFLAGS=-mod=readonly
|
||||
export CGO_ENABLED=0
|
||||
|
||||
echo Testing on "${kernel_version}"
|
||||
go test -exec "$script --exec-vm $input" "${args[@]}"
|
||||
echo "Test successful on ${kernel_version}"
|
||||
|
||||
rm -r "${input}"
|
||||
$sudo rm -r "${input}"
|
||||
$sudo rm -r "${output}"
|
||||
|
16
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go
generated
vendored
16
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go
generated
vendored
@ -1,16 +0,0 @@
|
||||
package apparmor
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// IsEnabled returns true if apparmor is enabled for the host.
|
||||
IsEnabled = isEnabled
|
||||
|
||||
// ApplyProfile will apply the profile with the specified name to the process after
|
||||
// the next exec. It is only supported on Linux and produces an ErrApparmorNotEnabled
|
||||
// on other platforms.
|
||||
ApplyProfile = applyProfile
|
||||
|
||||
// ErrApparmorNotEnabled indicates that AppArmor is not enabled or not supported.
|
||||
ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported")
|
||||
)
|
11
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go
generated
vendored
11
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go
generated
vendored
@ -15,8 +15,8 @@ var (
|
||||
checkAppArmor sync.Once
|
||||
)
|
||||
|
||||
// isEnabled returns true if apparmor is enabled for the host.
|
||||
func isEnabled() bool {
|
||||
// IsEnabled returns true if apparmor is enabled for the host.
|
||||
func IsEnabled() bool {
|
||||
checkAppArmor.Do(func() {
|
||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil {
|
||||
buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled")
|
||||
@ -57,10 +57,9 @@ func changeOnExec(name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyProfile will apply the profile with the specified name to the process after
|
||||
// the next exec. It is only supported on Linux and produces an error on other
|
||||
// platforms.
|
||||
func applyProfile(name string) error {
|
||||
// ApplyProfile will apply the profile with the specified name to the process after
|
||||
// the next exec.
|
||||
func ApplyProfile(name string) error {
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
|
10
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go
generated
vendored
10
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go
generated
vendored
@ -2,11 +2,17 @@
|
||||
|
||||
package apparmor
|
||||
|
||||
func isEnabled() bool {
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported")
|
||||
|
||||
func IsEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func applyProfile(name string) error {
|
||||
func ApplyProfile(name string) error {
|
||||
if name != "" {
|
||||
return ErrApparmorNotEnabled
|
||||
}
|
||||
|
13
vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go
generated
vendored
13
vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go
generated
vendored
@ -258,9 +258,9 @@ func (e *Emulator) Apply(rule devices.Rule) error {
|
||||
|
||||
if rule.Allow {
|
||||
return e.allow(innerRule)
|
||||
} else {
|
||||
return e.deny(innerRule)
|
||||
}
|
||||
|
||||
return e.deny(innerRule)
|
||||
}
|
||||
|
||||
// EmulatorFromList takes a reader to a "devices.list"-like source, and returns
|
||||
@ -371,12 +371,3 @@ func (source *Emulator) Transition(target *Emulator) ([]*devices.Rule, error) {
|
||||
}
|
||||
return transitionRules, nil
|
||||
}
|
||||
|
||||
// Rules returns the minimum set of rules necessary to convert a *deny-all*
|
||||
// cgroup to the emulated filter state (note that this is not the same as a
|
||||
// default cgroupv1 cgroup -- which is allow-all). This is effectively just a
|
||||
// wrapper around Transition() with the source emulator being an empty cgroup.
|
||||
func (e *Emulator) Rules() ([]*devices.Rule, error) {
|
||||
defaultCgroup := &Emulator{defaultAllow: false}
|
||||
return defaultCgroup.Transition(e)
|
||||
}
|
||||
|
119
vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
generated
vendored
119
vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
generated
vendored
@ -11,7 +11,6 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/cilium/ebpf/asm"
|
||||
devicesemulator "github.com/opencontainers/runc/libcontainer/cgroups/devices"
|
||||
"github.com/opencontainers/runc/libcontainer/devices"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
@ -23,44 +22,11 @@ const (
|
||||
)
|
||||
|
||||
// DeviceFilter returns eBPF device filter program and its license string
|
||||
func DeviceFilter(rules []*devices.Rule) (asm.Instructions, string, error) {
|
||||
// Generate the minimum ruleset for the device rules we are given. While we
|
||||
// don't care about minimum transitions in cgroupv2, using the emulator
|
||||
// gives us a guarantee that the behaviour of devices filtering is the same
|
||||
// as cgroupv1, including security hardenings to avoid misconfiguration
|
||||
// (such as punching holes in wildcard rules).
|
||||
emu := new(devicesemulator.Emulator)
|
||||
for _, rule := range rules {
|
||||
if err := emu.Apply(*rule); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
cleanRules, err := emu.Rules()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
p := &program{
|
||||
defaultAllow: emu.IsBlacklist(),
|
||||
}
|
||||
func DeviceFilter(devices []*devices.Rule) (asm.Instructions, string, error) {
|
||||
p := &program{}
|
||||
p.init()
|
||||
|
||||
for idx, rule := range cleanRules {
|
||||
if rule.Type == devices.WildcardDevice {
|
||||
// We can safely skip over wildcard entries because there should
|
||||
// only be one (at most) at the very start to instruct cgroupv1 to
|
||||
// go into allow-list mode. However we do double-check this here.
|
||||
if idx != 0 || rule.Allow != emu.IsBlacklist() {
|
||||
return nil, "", errors.Errorf("[internal error] emulated cgroupv2 devices ruleset had bad wildcard at idx %v (%s)", idx, rule.CgroupString())
|
||||
}
|
||||
continue
|
||||
}
|
||||
if rule.Allow == p.defaultAllow {
|
||||
// There should be no rules which have an action equal to the
|
||||
// default action, the emulator removes those.
|
||||
return nil, "", errors.Errorf("[internal error] emulated cgroupv2 devices ruleset had no-op rule at idx %v (%s)", idx, rule.CgroupString())
|
||||
}
|
||||
if err := p.appendRule(rule); err != nil {
|
||||
for i := len(devices) - 1; i >= 0; i-- {
|
||||
if err := p.appendDevice(devices[i]); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
@ -69,9 +35,9 @@ func DeviceFilter(rules []*devices.Rule) (asm.Instructions, string, error) {
|
||||
}
|
||||
|
||||
type program struct {
|
||||
insts asm.Instructions
|
||||
defaultAllow bool
|
||||
blockID int
|
||||
insts asm.Instructions
|
||||
hasWildCard bool
|
||||
blockID int
|
||||
}
|
||||
|
||||
func (p *program) init() {
|
||||
@ -101,35 +67,39 @@ func (p *program) init() {
|
||||
asm.LoadMem(asm.R5, asm.R1, 8, asm.Word))
|
||||
}
|
||||
|
||||
// appendRule rule converts an OCI rule to the relevant eBPF block and adds it
|
||||
// to the in-progress filter program. In order to operate properly, it must be
|
||||
// called with a "clean" rule list (generated by devices.Emulator.Rules() --
|
||||
// with any "a" rules removed).
|
||||
func (p *program) appendRule(rule *devices.Rule) error {
|
||||
// appendDevice needs to be called from the last element of OCI linux.resources.devices to the head element.
|
||||
func (p *program) appendDevice(dev *devices.Rule) error {
|
||||
if p.blockID < 0 {
|
||||
return errors.New("the program is finalized")
|
||||
}
|
||||
if p.hasWildCard {
|
||||
// All entries after wildcard entry are ignored
|
||||
return nil
|
||||
}
|
||||
|
||||
var bpfType int32
|
||||
switch rule.Type {
|
||||
case devices.CharDevice:
|
||||
bpfType := int32(-1)
|
||||
hasType := true
|
||||
switch dev.Type {
|
||||
case 'c':
|
||||
bpfType = int32(unix.BPF_DEVCG_DEV_CHAR)
|
||||
case devices.BlockDevice:
|
||||
case 'b':
|
||||
bpfType = int32(unix.BPF_DEVCG_DEV_BLOCK)
|
||||
case 'a':
|
||||
hasType = false
|
||||
default:
|
||||
// We do not permit 'a', nor any other types we don't know about.
|
||||
return errors.Errorf("invalid type %q", string(rule.Type))
|
||||
// if not specified in OCI json, typ is set to DeviceTypeAll
|
||||
return errors.Errorf("invalid Type %q", string(dev.Type))
|
||||
}
|
||||
if rule.Major > math.MaxUint32 {
|
||||
return errors.Errorf("invalid major %d", rule.Major)
|
||||
if dev.Major > math.MaxUint32 {
|
||||
return errors.Errorf("invalid major %d", dev.Major)
|
||||
}
|
||||
if rule.Minor > math.MaxUint32 {
|
||||
return errors.Errorf("invalid minor %d", rule.Major)
|
||||
if dev.Minor > math.MaxUint32 {
|
||||
return errors.Errorf("invalid minor %d", dev.Major)
|
||||
}
|
||||
hasMajor := rule.Major >= 0 // if not specified in OCI json, major is set to -1
|
||||
hasMinor := rule.Minor >= 0
|
||||
hasMajor := dev.Major >= 0 // if not specified in OCI json, major is set to -1
|
||||
hasMinor := dev.Minor >= 0
|
||||
bpfAccess := int32(0)
|
||||
for _, r := range rule.Permissions {
|
||||
for _, r := range dev.Permissions {
|
||||
switch r {
|
||||
case 'r':
|
||||
bpfAccess |= unix.BPF_DEVCG_ACC_READ
|
||||
@ -149,10 +119,12 @@ func (p *program) appendRule(rule *devices.Rule) error {
|
||||
nextBlockSym = "block-" + strconv.Itoa(p.blockID+1)
|
||||
prevBlockLastIdx = len(p.insts) - 1
|
||||
)
|
||||
p.insts = append(p.insts,
|
||||
// if (R2 != bpfType) goto next
|
||||
asm.JNE.Imm(asm.R2, bpfType, nextBlockSym),
|
||||
)
|
||||
if hasType {
|
||||
p.insts = append(p.insts,
|
||||
// if (R2 != bpfType) goto next
|
||||
asm.JNE.Imm(asm.R2, bpfType, nextBlockSym),
|
||||
)
|
||||
}
|
||||
if hasAccess {
|
||||
p.insts = append(p.insts,
|
||||
// if (R3 & bpfAccess != R3 /* use R1 as a temp var */) goto next
|
||||
@ -164,16 +136,19 @@ func (p *program) appendRule(rule *devices.Rule) error {
|
||||
if hasMajor {
|
||||
p.insts = append(p.insts,
|
||||
// if (R4 != major) goto next
|
||||
asm.JNE.Imm(asm.R4, int32(rule.Major), nextBlockSym),
|
||||
asm.JNE.Imm(asm.R4, int32(dev.Major), nextBlockSym),
|
||||
)
|
||||
}
|
||||
if hasMinor {
|
||||
p.insts = append(p.insts,
|
||||
// if (R5 != minor) goto next
|
||||
asm.JNE.Imm(asm.R5, int32(rule.Minor), nextBlockSym),
|
||||
asm.JNE.Imm(asm.R5, int32(dev.Minor), nextBlockSym),
|
||||
)
|
||||
}
|
||||
p.insts = append(p.insts, acceptBlock(rule.Allow)...)
|
||||
if !hasType && !hasAccess && !hasMajor && !hasMinor {
|
||||
p.hasWildCard = true
|
||||
}
|
||||
p.insts = append(p.insts, acceptBlock(dev.Allow)...)
|
||||
// set blockSym to the first instruction we added in this iteration
|
||||
p.insts[prevBlockLastIdx+1] = p.insts[prevBlockLastIdx+1].Sym(blockSym)
|
||||
p.blockID++
|
||||
@ -181,14 +156,14 @@ func (p *program) appendRule(rule *devices.Rule) error {
|
||||
}
|
||||
|
||||
func (p *program) finalize() (asm.Instructions, error) {
|
||||
var v int32
|
||||
if p.defaultAllow {
|
||||
v = 1
|
||||
if p.hasWildCard {
|
||||
// acceptBlock with asm.Return() is already inserted
|
||||
return p.insts, nil
|
||||
}
|
||||
blockSym := "block-" + strconv.Itoa(p.blockID)
|
||||
p.insts = append(p.insts,
|
||||
// R0 <- v
|
||||
asm.Mov.Imm32(asm.R0, v).Sym(blockSym),
|
||||
// R0 <- 0
|
||||
asm.Mov.Imm32(asm.R0, 0).Sym(blockSym),
|
||||
asm.Return(),
|
||||
)
|
||||
p.blockID = -1
|
||||
@ -196,7 +171,7 @@ func (p *program) finalize() (asm.Instructions, error) {
|
||||
}
|
||||
|
||||
func acceptBlock(accept bool) asm.Instructions {
|
||||
var v int32
|
||||
v := int32(0)
|
||||
if accept {
|
||||
v = 1
|
||||
}
|
||||
|
57
vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/ebpf.go
generated
vendored
Normal file
57
vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/ebpf.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
package ebpf
|
||||
|
||||
import (
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/asm"
|
||||
"github.com/cilium/ebpf/link"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// LoadAttachCgroupDeviceFilter installs eBPF device filter program to /sys/fs/cgroup/<foo> directory.
|
||||
//
|
||||
// Requires the system to be running in cgroup2 unified-mode with kernel >= 4.15 .
|
||||
//
|
||||
// https://github.com/torvalds/linux/commit/ebc614f687369f9df99828572b1d85a7c2de3d92
|
||||
func LoadAttachCgroupDeviceFilter(insts asm.Instructions, license string, dirFD int) (func() error, error) {
|
||||
nilCloser := func() error {
|
||||
return nil
|
||||
}
|
||||
// Increase `ulimit -l` limit to avoid BPF_PROG_LOAD error (#2167).
|
||||
// This limit is not inherited into the container.
|
||||
memlockLimit := &unix.Rlimit{
|
||||
Cur: unix.RLIM_INFINITY,
|
||||
Max: unix.RLIM_INFINITY,
|
||||
}
|
||||
_ = unix.Setrlimit(unix.RLIMIT_MEMLOCK, memlockLimit)
|
||||
spec := &ebpf.ProgramSpec{
|
||||
Type: ebpf.CGroupDevice,
|
||||
Instructions: insts,
|
||||
License: license,
|
||||
}
|
||||
prog, err := ebpf.NewProgram(spec)
|
||||
if err != nil {
|
||||
return nilCloser, err
|
||||
}
|
||||
err = link.RawAttachProgram(link.RawAttachProgramOptions{
|
||||
Target: dirFD,
|
||||
Program: prog,
|
||||
Attach: ebpf.AttachCGroupDevice,
|
||||
Flags: unix.BPF_F_ALLOW_MULTI,
|
||||
})
|
||||
if err != nil {
|
||||
return nilCloser, errors.Wrap(err, "failed to call BPF_PROG_ATTACH (BPF_CGROUP_DEVICE, BPF_F_ALLOW_MULTI)")
|
||||
}
|
||||
closer := func() error {
|
||||
err = link.RawDetachProgram(link.RawDetachProgramOptions{
|
||||
Target: dirFD,
|
||||
Program: prog,
|
||||
Attach: ebpf.AttachCGroupDevice,
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to call BPF_PROG_DETACH (BPF_CGROUP_DEVICE)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return closer, nil
|
||||
}
|
240
vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/ebpf_linux.go
generated
vendored
240
vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/ebpf_linux.go
generated
vendored
@ -1,240 +0,0 @@
|
||||
package ebpf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/asm"
|
||||
"github.com/cilium/ebpf/link"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func nilCloser() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findAttachedCgroupDeviceFilters(dirFd int) ([]*ebpf.Program, error) {
|
||||
type bpfAttrQuery struct {
|
||||
TargetFd uint32
|
||||
AttachType uint32
|
||||
QueryType uint32
|
||||
AttachFlags uint32
|
||||
ProgIds uint64 // __aligned_u64
|
||||
ProgCnt uint32
|
||||
}
|
||||
|
||||
// Currently you can only have 64 eBPF programs attached to a cgroup.
|
||||
size := 64
|
||||
retries := 0
|
||||
for retries < 10 {
|
||||
progIds := make([]uint32, size)
|
||||
query := bpfAttrQuery{
|
||||
TargetFd: uint32(dirFd),
|
||||
AttachType: uint32(unix.BPF_CGROUP_DEVICE),
|
||||
ProgIds: uint64(uintptr(unsafe.Pointer(&progIds[0]))),
|
||||
ProgCnt: uint32(len(progIds)),
|
||||
}
|
||||
|
||||
// Fetch the list of program ids.
|
||||
_, _, errno := unix.Syscall(unix.SYS_BPF,
|
||||
uintptr(unix.BPF_PROG_QUERY),
|
||||
uintptr(unsafe.Pointer(&query)),
|
||||
unsafe.Sizeof(query))
|
||||
size = int(query.ProgCnt)
|
||||
runtime.KeepAlive(query)
|
||||
if errno != 0 {
|
||||
// On ENOSPC we get the correct number of programs.
|
||||
if errno == unix.ENOSPC {
|
||||
retries++
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("bpf_prog_query(BPF_CGROUP_DEVICE) failed: %w", errno)
|
||||
}
|
||||
|
||||
// Convert the ids to program handles.
|
||||
progIds = progIds[:size]
|
||||
programs := make([]*ebpf.Program, len(progIds))
|
||||
for idx, progId := range progIds {
|
||||
program, err := ebpf.NewProgramFromID(ebpf.ProgramID(progId))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot fetch program from id: %w", err)
|
||||
}
|
||||
programs[idx] = program
|
||||
}
|
||||
runtime.KeepAlive(progIds)
|
||||
return programs, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("could not get complete list of CGROUP_DEVICE programs")
|
||||
}
|
||||
|
||||
var (
|
||||
haveBpfProgReplaceBool bool
|
||||
haveBpfProgReplaceOnce sync.Once
|
||||
)
|
||||
|
||||
// Loosely based on the BPF_F_REPLACE support check in
|
||||
// <https://github.com/cilium/ebpf/blob/v0.6.0/link/syscalls.go>.
|
||||
//
|
||||
// TODO: move this logic to cilium/ebpf
|
||||
func haveBpfProgReplace() bool {
|
||||
haveBpfProgReplaceOnce.Do(func() {
|
||||
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
||||
Type: ebpf.CGroupDevice,
|
||||
License: "MIT",
|
||||
Instructions: asm.Instructions{
|
||||
asm.Mov.Imm(asm.R0, 0),
|
||||
asm.Return(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Debugf("checking for BPF_F_REPLACE support: ebpf.NewProgram failed: %v", err)
|
||||
return
|
||||
}
|
||||
defer prog.Close()
|
||||
|
||||
devnull, err := os.Open("/dev/null")
|
||||
if err != nil {
|
||||
logrus.Debugf("checking for BPF_F_REPLACE support: open dummy target fd: %v", err)
|
||||
return
|
||||
}
|
||||
defer devnull.Close()
|
||||
|
||||
// We know that we have BPF_PROG_ATTACH since we can load
|
||||
// BPF_CGROUP_DEVICE programs. If passing BPF_F_REPLACE gives us EINVAL
|
||||
// we know that the feature isn't present.
|
||||
err = link.RawAttachProgram(link.RawAttachProgramOptions{
|
||||
// We rely on this fd being checked after attachFlags.
|
||||
Target: int(devnull.Fd()),
|
||||
// Attempt to "replace" bad fds with this program.
|
||||
Program: prog,
|
||||
Attach: ebpf.AttachCGroupDevice,
|
||||
Flags: unix.BPF_F_ALLOW_MULTI | unix.BPF_F_REPLACE,
|
||||
})
|
||||
if errors.Is(err, unix.EINVAL) {
|
||||
// not supported
|
||||
return
|
||||
}
|
||||
// attach_flags test succeded.
|
||||
if !errors.Is(err, unix.EBADF) {
|
||||
logrus.Debugf("checking for BPF_F_REPLACE: got unexpected (not EBADF or EINVAL) error: %v", err)
|
||||
}
|
||||
haveBpfProgReplaceBool = true
|
||||
})
|
||||
return haveBpfProgReplaceBool
|
||||
}
|
||||
|
||||
// LoadAttachCgroupDeviceFilter installs eBPF device filter program to /sys/fs/cgroup/<foo> directory.
|
||||
//
|
||||
// Requires the system to be running in cgroup2 unified-mode with kernel >= 4.15 .
|
||||
//
|
||||
// https://github.com/torvalds/linux/commit/ebc614f687369f9df99828572b1d85a7c2de3d92
|
||||
func LoadAttachCgroupDeviceFilter(insts asm.Instructions, license string, dirFd int) (func() error, error) {
|
||||
// Increase `ulimit -l` limit to avoid BPF_PROG_LOAD error (#2167).
|
||||
// This limit is not inherited into the container.
|
||||
memlockLimit := &unix.Rlimit{
|
||||
Cur: unix.RLIM_INFINITY,
|
||||
Max: unix.RLIM_INFINITY,
|
||||
}
|
||||
_ = unix.Setrlimit(unix.RLIMIT_MEMLOCK, memlockLimit)
|
||||
|
||||
// Get the list of existing programs.
|
||||
oldProgs, err := findAttachedCgroupDeviceFilters(dirFd)
|
||||
if err != nil {
|
||||
return nilCloser, err
|
||||
}
|
||||
useReplaceProg := haveBpfProgReplace() && len(oldProgs) == 1
|
||||
|
||||
// Generate new program.
|
||||
spec := &ebpf.ProgramSpec{
|
||||
Type: ebpf.CGroupDevice,
|
||||
Instructions: insts,
|
||||
License: license,
|
||||
}
|
||||
prog, err := ebpf.NewProgram(spec)
|
||||
if err != nil {
|
||||
return nilCloser, err
|
||||
}
|
||||
|
||||
// If there is only one old program, we can just replace it directly.
|
||||
var (
|
||||
replaceProg *ebpf.Program
|
||||
attachFlags uint32 = unix.BPF_F_ALLOW_MULTI
|
||||
)
|
||||
if useReplaceProg {
|
||||
replaceProg = oldProgs[0]
|
||||
attachFlags |= unix.BPF_F_REPLACE
|
||||
}
|
||||
err = link.RawAttachProgram(link.RawAttachProgramOptions{
|
||||
Target: dirFd,
|
||||
Program: prog,
|
||||
Replace: replaceProg,
|
||||
Attach: ebpf.AttachCGroupDevice,
|
||||
Flags: attachFlags,
|
||||
})
|
||||
if err != nil {
|
||||
return nilCloser, fmt.Errorf("failed to call BPF_PROG_ATTACH (BPF_CGROUP_DEVICE, BPF_F_ALLOW_MULTI): %w", err)
|
||||
}
|
||||
closer := func() error {
|
||||
err = link.RawDetachProgram(link.RawDetachProgramOptions{
|
||||
Target: dirFd,
|
||||
Program: prog,
|
||||
Attach: ebpf.AttachCGroupDevice,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to call BPF_PROG_DETACH (BPF_CGROUP_DEVICE): %w", err)
|
||||
}
|
||||
// TODO: Should we attach the old filters back in this case? Otherwise
|
||||
// we fail-open on a security feature, which is a bit scary.
|
||||
return nil
|
||||
}
|
||||
if !useReplaceProg {
|
||||
logLevel := logrus.DebugLevel
|
||||
// If there was more than one old program, give a warning (since this
|
||||
// really shouldn't happen with runc-managed cgroups) and then detach
|
||||
// all the old programs.
|
||||
if len(oldProgs) > 1 {
|
||||
// NOTE: Ideally this should be a warning but it turns out that
|
||||
// systemd-managed cgroups trigger this warning (apparently
|
||||
// systemd doesn't delete old non-systemd programs when
|
||||
// setting properties).
|
||||
logrus.Infof("found more than one filter (%d) attached to a cgroup -- removing extra filters!", len(oldProgs))
|
||||
logLevel = logrus.InfoLevel
|
||||
}
|
||||
for idx, oldProg := range oldProgs {
|
||||
// Output some extra debug info.
|
||||
if info, err := oldProg.Info(); err == nil {
|
||||
fields := logrus.Fields{
|
||||
"type": info.Type.String(),
|
||||
"tag": info.Tag,
|
||||
"name": info.Name,
|
||||
}
|
||||
if id, ok := info.ID(); ok {
|
||||
fields["id"] = id
|
||||
}
|
||||
if runCount, ok := info.RunCount(); ok {
|
||||
fields["run_count"] = runCount
|
||||
}
|
||||
if runtime, ok := info.Runtime(); ok {
|
||||
fields["runtime"] = runtime.String()
|
||||
}
|
||||
logrus.WithFields(fields).Logf(logLevel, "removing old filter %d from cgroup", idx)
|
||||
}
|
||||
err = link.RawDetachProgram(link.RawDetachProgramOptions{
|
||||
Target: dirFd,
|
||||
Program: oldProg,
|
||||
Attach: ebpf.AttachCGroupDevice,
|
||||
})
|
||||
if err != nil {
|
||||
return closer, fmt.Errorf("failed to call BPF_PROG_DETACH (BPF_CGROUP_DEVICE) on old filter program: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return closer, nil
|
||||
}
|
59
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go
generated
vendored
59
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go
generated
vendored
@ -6,17 +6,15 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
type BlkioGroup struct {
|
||||
weightFilename string
|
||||
weightDeviceFilename string
|
||||
}
|
||||
|
||||
func (s *BlkioGroup) Name() string {
|
||||
@ -28,47 +26,42 @@ func (s *BlkioGroup) Apply(path string, d *cgroupData) error {
|
||||
}
|
||||
|
||||
func (s *BlkioGroup) Set(path string, r *configs.Resources) error {
|
||||
s.detectWeightFilenames(path)
|
||||
if r.BlkioWeight != 0 {
|
||||
if err := cgroups.WriteFile(path, s.weightFilename, strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "blkio.weight", strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if r.BlkioLeafWeight != 0 {
|
||||
if err := cgroups.WriteFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(r.BlkioLeafWeight), 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(r.BlkioLeafWeight), 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, wd := range r.BlkioWeightDevice {
|
||||
if wd.Weight != 0 {
|
||||
if err := cgroups.WriteFile(path, s.weightDeviceFilename, wd.WeightString()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fscommon.WriteFile(path, "blkio.weight_device", wd.WeightString()); err != nil {
|
||||
return err
|
||||
}
|
||||
if wd.LeafWeight != 0 {
|
||||
if err := cgroups.WriteFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fscommon.WriteFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, td := range r.BlkioThrottleReadBpsDevice {
|
||||
if err := cgroups.WriteFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil {
|
||||
if err := fscommon.WriteFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, td := range r.BlkioThrottleWriteBpsDevice {
|
||||
if err := cgroups.WriteFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil {
|
||||
if err := fscommon.WriteFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, td := range r.BlkioThrottleReadIOPSDevice {
|
||||
if err := cgroups.WriteFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil {
|
||||
if err := fscommon.WriteFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, td := range r.BlkioThrottleWriteIOPSDevice {
|
||||
if err := cgroups.WriteFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil {
|
||||
if err := fscommon.WriteFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -113,7 +106,7 @@ func splitBlkioStatLine(r rune) bool {
|
||||
|
||||
func getBlkioStat(dir, file string) ([]cgroups.BlkioStatEntry, error) {
|
||||
var blkioStats []cgroups.BlkioStatEntry
|
||||
f, err := cgroups.OpenFile(dir, file, os.O_RDONLY)
|
||||
f, err := fscommon.OpenFile(dir, file, os.O_RDONLY)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return blkioStats, nil
|
||||
@ -168,7 +161,7 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
filename string
|
||||
blkioStatEntriesPtr *[]cgroups.BlkioStatEntry
|
||||
}
|
||||
bfqDebugStats := []blkioStatInfo{
|
||||
var bfqDebugStats = []blkioStatInfo{
|
||||
{
|
||||
filename: "blkio.bfq.sectors_recursive",
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.SectorsRecursive,
|
||||
@ -202,7 +195,7 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
|
||||
},
|
||||
}
|
||||
bfqStats := []blkioStatInfo{
|
||||
var bfqStats = []blkioStatInfo{
|
||||
{
|
||||
filename: "blkio.bfq.io_serviced_recursive",
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.IoServicedRecursive,
|
||||
@ -212,7 +205,7 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
|
||||
},
|
||||
}
|
||||
cfqStats := []blkioStatInfo{
|
||||
var cfqStats = []blkioStatInfo{
|
||||
{
|
||||
filename: "blkio.sectors_recursive",
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.SectorsRecursive,
|
||||
@ -246,7 +239,7 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
|
||||
},
|
||||
}
|
||||
throttleRecursiveStats := []blkioStatInfo{
|
||||
var throttleRecursiveStats = []blkioStatInfo{
|
||||
{
|
||||
filename: "blkio.throttle.io_serviced_recursive",
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.IoServicedRecursive,
|
||||
@ -256,7 +249,7 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
|
||||
},
|
||||
}
|
||||
baseStats := []blkioStatInfo{
|
||||
var baseStats = []blkioStatInfo{
|
||||
{
|
||||
filename: "blkio.throttle.io_serviced",
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.IoServicedRecursive,
|
||||
@ -266,7 +259,7 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
|
||||
},
|
||||
}
|
||||
orderedStats := [][]blkioStatInfo{
|
||||
var orderedStats = [][]blkioStatInfo{
|
||||
bfqDebugStats,
|
||||
bfqStats,
|
||||
cfqStats,
|
||||
@ -287,7 +280,7 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
return err
|
||||
}
|
||||
*statInfo.blkioStatEntriesPtr = blkioStats
|
||||
// finish if all stats are gathered
|
||||
//finish if all stats are gathered
|
||||
if i == len(statGroup)-1 {
|
||||
return nil
|
||||
}
|
||||
@ -295,17 +288,3 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *BlkioGroup) detectWeightFilenames(path string) {
|
||||
if s.weightFilename != "" {
|
||||
// Already detected.
|
||||
return
|
||||
}
|
||||
if cgroups.PathExists(filepath.Join(path, "blkio.weight")) {
|
||||
s.weightFilename = "blkio.weight"
|
||||
s.weightDeviceFilename = "blkio.weight_device"
|
||||
} else {
|
||||
s.weightFilename = "blkio.bfq.weight"
|
||||
s.weightDeviceFilename = "blkio.bfq.weight_device"
|
||||
}
|
||||
}
|
||||
|
17
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go
generated
vendored
17
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go
generated
vendored
@ -13,7 +13,8 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
type CpuGroup struct{}
|
||||
type CpuGroup struct {
|
||||
}
|
||||
|
||||
func (s *CpuGroup) Name() string {
|
||||
return "cpu"
|
||||
@ -25,7 +26,7 @@ func (s *CpuGroup) Apply(path string, d *cgroupData) error {
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
if err := os.MkdirAll(path, 0o755); err != nil {
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
// We should set the real-Time group scheduling settings before moving
|
||||
@ -41,12 +42,12 @@ func (s *CpuGroup) Apply(path string, d *cgroupData) error {
|
||||
|
||||
func (s *CpuGroup) SetRtSched(path string, r *configs.Resources) error {
|
||||
if r.CpuRtPeriod != 0 {
|
||||
if err := cgroups.WriteFile(path, "cpu.rt_period_us", strconv.FormatUint(r.CpuRtPeriod, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "cpu.rt_period_us", strconv.FormatUint(r.CpuRtPeriod, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if r.CpuRtRuntime != 0 {
|
||||
if err := cgroups.WriteFile(path, "cpu.rt_runtime_us", strconv.FormatInt(r.CpuRtRuntime, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "cpu.rt_runtime_us", strconv.FormatInt(r.CpuRtRuntime, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -56,7 +57,7 @@ func (s *CpuGroup) SetRtSched(path string, r *configs.Resources) error {
|
||||
func (s *CpuGroup) Set(path string, r *configs.Resources) error {
|
||||
if r.CpuShares != 0 {
|
||||
shares := r.CpuShares
|
||||
if err := cgroups.WriteFile(path, "cpu.shares", strconv.FormatUint(shares, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "cpu.shares", strconv.FormatUint(shares, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
// read it back
|
||||
@ -72,12 +73,12 @@ func (s *CpuGroup) Set(path string, r *configs.Resources) error {
|
||||
}
|
||||
}
|
||||
if r.CpuPeriod != 0 {
|
||||
if err := cgroups.WriteFile(path, "cpu.cfs_period_us", strconv.FormatUint(r.CpuPeriod, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "cpu.cfs_period_us", strconv.FormatUint(r.CpuPeriod, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if r.CpuQuota != 0 {
|
||||
if err := cgroups.WriteFile(path, "cpu.cfs_quota_us", strconv.FormatInt(r.CpuQuota, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "cpu.cfs_quota_us", strconv.FormatInt(r.CpuQuota, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -85,7 +86,7 @@ func (s *CpuGroup) Set(path string, r *configs.Resources) error {
|
||||
}
|
||||
|
||||
func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
f, err := cgroups.OpenFile(path, "cpu.stat", os.O_RDONLY)
|
||||
f, err := fscommon.OpenFile(path, "cpu.stat", os.O_RDONLY)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
|
11
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go
generated
vendored
11
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go
generated
vendored
@ -32,7 +32,8 @@ const (
|
||||
clockTicks uint64 = 100
|
||||
)
|
||||
|
||||
type CpuacctGroup struct{}
|
||||
type CpuacctGroup struct {
|
||||
}
|
||||
|
||||
func (s *CpuacctGroup) Name() string {
|
||||
return "cpuacct"
|
||||
@ -90,7 +91,7 @@ func getCpuUsageBreakdown(path string) (uint64, uint64, error) {
|
||||
// Expected format:
|
||||
// user <usage in ticks>
|
||||
// system <usage in ticks>
|
||||
data, err := cgroups.ReadFile(path, cgroupCpuacctStat)
|
||||
data, err := fscommon.ReadFile(path, cgroupCpuacctStat)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
@ -116,7 +117,7 @@ func getCpuUsageBreakdown(path string) (uint64, uint64, error) {
|
||||
|
||||
func getPercpuUsage(path string) ([]uint64, error) {
|
||||
percpuUsage := []uint64{}
|
||||
data, err := cgroups.ReadFile(path, "cpuacct.usage_percpu")
|
||||
data, err := fscommon.ReadFile(path, "cpuacct.usage_percpu")
|
||||
if err != nil {
|
||||
return percpuUsage, err
|
||||
}
|
||||
@ -134,7 +135,7 @@ func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) {
|
||||
usageKernelMode := []uint64{}
|
||||
usageUserMode := []uint64{}
|
||||
|
||||
file, err := cgroups.OpenFile(path, cgroupCpuacctUsageAll, os.O_RDONLY)
|
||||
file, err := fscommon.OpenFile(path, cgroupCpuacctUsageAll, os.O_RDONLY)
|
||||
if os.IsNotExist(err) {
|
||||
return usageKernelMode, usageUserMode, nil
|
||||
} else if err != nil {
|
||||
@ -143,7 +144,7 @@ func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) {
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Scan() // skipping header line
|
||||
scanner.Scan() //skipping header line
|
||||
|
||||
for scanner.Scan() {
|
||||
lineFields := strings.SplitN(scanner.Text(), " ", cuacctUsageAllColumnsNumber+1)
|
||||
|
19
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go
generated
vendored
19
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go
generated
vendored
@ -16,7 +16,8 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type CpusetGroup struct{}
|
||||
type CpusetGroup struct {
|
||||
}
|
||||
|
||||
func (s *CpusetGroup) Name() string {
|
||||
return "cpuset"
|
||||
@ -28,12 +29,12 @@ func (s *CpusetGroup) Apply(path string, d *cgroupData) error {
|
||||
|
||||
func (s *CpusetGroup) Set(path string, r *configs.Resources) error {
|
||||
if r.CpusetCpus != "" {
|
||||
if err := cgroups.WriteFile(path, "cpuset.cpus", r.CpusetCpus); err != nil {
|
||||
if err := fscommon.WriteFile(path, "cpuset.cpus", r.CpusetCpus); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if r.CpusetMems != "" {
|
||||
if err := cgroups.WriteFile(path, "cpuset.mems", r.CpusetMems); err != nil {
|
||||
if err := fscommon.WriteFile(path, "cpuset.mems", r.CpusetMems); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -155,7 +156,7 @@ func (s *CpusetGroup) ApplyDir(dir string, r *configs.Resources, pid int) error
|
||||
if err := cpusetEnsureParent(filepath.Dir(dir)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Mkdir(dir, 0o755); err != nil && !os.IsExist(err) {
|
||||
if err := os.Mkdir(dir, 0755); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
// We didn't inherit cpuset configs from parent, but we have
|
||||
@ -175,10 +176,10 @@ func (s *CpusetGroup) ApplyDir(dir string, r *configs.Resources, pid int) error
|
||||
}
|
||||
|
||||
func getCpusetSubsystemSettings(parent string) (cpus, mems string, err error) {
|
||||
if cpus, err = cgroups.ReadFile(parent, "cpuset.cpus"); err != nil {
|
||||
if cpus, err = fscommon.ReadFile(parent, "cpuset.cpus"); err != nil {
|
||||
return
|
||||
}
|
||||
if mems, err = cgroups.ReadFile(parent, "cpuset.mems"); err != nil {
|
||||
if mems, err = fscommon.ReadFile(parent, "cpuset.mems"); err != nil {
|
||||
return
|
||||
}
|
||||
return cpus, mems, nil
|
||||
@ -205,7 +206,7 @@ func cpusetEnsureParent(current string) error {
|
||||
if err := cpusetEnsureParent(parent); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.Mkdir(current, 0o755); err != nil && !os.IsExist(err) {
|
||||
if err := os.Mkdir(current, 0755); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
return cpusetCopyIfNeeded(current, parent)
|
||||
@ -224,12 +225,12 @@ func cpusetCopyIfNeeded(current, parent string) error {
|
||||
}
|
||||
|
||||
if isEmptyCpuset(currentCpus) {
|
||||
if err := cgroups.WriteFile(current, "cpuset.cpus", string(parentCpus)); err != nil {
|
||||
if err := fscommon.WriteFile(current, "cpuset.cpus", string(parentCpus)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if isEmptyCpuset(currentMems) {
|
||||
if err := cgroups.WriteFile(current, "cpuset.mems", string(parentMems)); err != nil {
|
||||
if err := fscommon.WriteFile(current, "cpuset.mems", string(parentMems)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
5
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go
generated
vendored
5
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go
generated
vendored
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
cgroupdevices "github.com/opencontainers/runc/libcontainer/cgroups/devices"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/devices"
|
||||
"github.com/opencontainers/runc/libcontainer/userns"
|
||||
@ -35,7 +36,7 @@ func (s *DevicesGroup) Apply(path string, d *cgroupData) error {
|
||||
}
|
||||
|
||||
func loadEmulator(path string) (*cgroupdevices.Emulator, error) {
|
||||
list, err := cgroups.ReadFile(path, "devices.list")
|
||||
list, err := fscommon.ReadFile(path, "devices.list")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -80,7 +81,7 @@ func (s *DevicesGroup) Set(path string, r *configs.Resources) error {
|
||||
if rule.Allow {
|
||||
file = "devices.allow"
|
||||
}
|
||||
if err := cgroups.WriteFile(path, file, rule.CgroupString()); err != nil {
|
||||
if err := fscommon.WriteFile(path, file, rule.CgroupString()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
16
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go
generated
vendored
16
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go
generated
vendored
@ -10,12 +10,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type FreezerGroup struct{}
|
||||
type FreezerGroup struct {
|
||||
}
|
||||
|
||||
func (s *FreezerGroup) Name() string {
|
||||
return "freezer"
|
||||
@ -33,7 +35,7 @@ func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) {
|
||||
// Freezing failed, and it is bad and dangerous
|
||||
// to leave the cgroup in FROZEN or FREEZING
|
||||
// state, so (try to) thaw it back.
|
||||
_ = cgroups.WriteFile(path, "freezer.state", string(configs.Thawed))
|
||||
_ = fscommon.WriteFile(path, "freezer.state", string(configs.Thawed))
|
||||
}
|
||||
}()
|
||||
|
||||
@ -66,11 +68,11 @@ func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) {
|
||||
// the chances to succeed in freezing
|
||||
// in case new processes keep appearing
|
||||
// in the cgroup.
|
||||
_ = cgroups.WriteFile(path, "freezer.state", string(configs.Thawed))
|
||||
_ = fscommon.WriteFile(path, "freezer.state", string(configs.Thawed))
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
if err := cgroups.WriteFile(path, "freezer.state", string(configs.Frozen)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "freezer.state", string(configs.Frozen)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -81,7 +83,7 @@ func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) {
|
||||
// system.
|
||||
time.Sleep(10 * time.Microsecond)
|
||||
}
|
||||
state, err := cgroups.ReadFile(path, "freezer.state")
|
||||
state, err := fscommon.ReadFile(path, "freezer.state")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -102,7 +104,7 @@ func (s *FreezerGroup) Set(path string, r *configs.Resources) (Err error) {
|
||||
// Despite our best efforts, it got stuck in FREEZING.
|
||||
return errors.New("unable to freeze")
|
||||
case configs.Thawed:
|
||||
return cgroups.WriteFile(path, "freezer.state", string(configs.Thawed))
|
||||
return fscommon.WriteFile(path, "freezer.state", string(configs.Thawed))
|
||||
case configs.Undefined:
|
||||
return nil
|
||||
default:
|
||||
@ -116,7 +118,7 @@ func (s *FreezerGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
|
||||
func (s *FreezerGroup) GetState(path string) (configs.FreezerState, error) {
|
||||
for {
|
||||
state, err := cgroups.ReadFile(path, "freezer.state")
|
||||
state, err := fscommon.ReadFile(path, "freezer.state")
|
||||
if err != nil {
|
||||
// If the kernel is too old, then we just treat the freezer as
|
||||
// being in an "undefined" state.
|
||||
|
8
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go
generated
vendored
8
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go
generated
vendored
@ -64,10 +64,8 @@ func NewManager(cg *configs.Cgroup, paths map[string]string, rootless bool) cgro
|
||||
}
|
||||
|
||||
// The absolute path to the root of the cgroup hierarchies.
|
||||
var (
|
||||
cgroupRootLock sync.Mutex
|
||||
cgroupRoot string
|
||||
)
|
||||
var cgroupRootLock sync.Mutex
|
||||
var cgroupRoot string
|
||||
|
||||
const defaultCgroupRoot = "/sys/fs/cgroup"
|
||||
|
||||
@ -395,7 +393,7 @@ func join(path string, pid int) error {
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
if err := os.MkdirAll(path, 0o755); err != nil {
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return cgroups.WriteCgroupProc(path, pid)
|
||||
|
5
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go
generated
vendored
5
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go
generated
vendored
@ -11,7 +11,8 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
type HugetlbGroup struct{}
|
||||
type HugetlbGroup struct {
|
||||
}
|
||||
|
||||
func (s *HugetlbGroup) Name() string {
|
||||
return "hugetlb"
|
||||
@ -23,7 +24,7 @@ func (s *HugetlbGroup) Apply(path string, d *cgroupData) error {
|
||||
|
||||
func (s *HugetlbGroup) Set(path string, r *configs.Resources) error {
|
||||
for _, hugetlb := range r.HugetlbLimit {
|
||||
if err := cgroups.WriteFile(path, "hugetlb."+hugetlb.Pagesize+".limit_in_bytes", strconv.FormatUint(hugetlb.Limit, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "hugetlb."+hugetlb.Pagesize+".limit_in_bytes", strconv.FormatUint(hugetlb.Limit, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
26
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go
generated
vendored
26
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go
generated
vendored
@ -25,7 +25,8 @@ const (
|
||||
cgroupMemoryMaxUsage = "memory.max_usage_in_bytes"
|
||||
)
|
||||
|
||||
type MemoryGroup struct{}
|
||||
type MemoryGroup struct {
|
||||
}
|
||||
|
||||
func (s *MemoryGroup) Name() string {
|
||||
return "memory"
|
||||
@ -40,7 +41,7 @@ func setMemory(path string, val int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := cgroups.WriteFile(path, cgroupMemoryLimit, strconv.FormatInt(val, 10))
|
||||
err := fscommon.WriteFile(path, cgroupMemoryLimit, strconv.FormatInt(val, 10))
|
||||
if !errors.Is(err, unix.EBUSY) {
|
||||
return err
|
||||
}
|
||||
@ -64,7 +65,7 @@ func setSwap(path string, val int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return cgroups.WriteFile(path, cgroupMemorySwapLimit, strconv.FormatInt(val, 10))
|
||||
return fscommon.WriteFile(path, cgroupMemorySwapLimit, strconv.FormatInt(val, 10))
|
||||
}
|
||||
|
||||
func setMemoryAndSwap(path string, r *configs.Resources) error {
|
||||
@ -117,20 +118,20 @@ func (s *MemoryGroup) Set(path string, r *configs.Resources) error {
|
||||
// ignore KernelMemory and KernelMemoryTCP
|
||||
|
||||
if r.MemoryReservation != 0 {
|
||||
if err := cgroups.WriteFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(r.MemoryReservation, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(r.MemoryReservation, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if r.OomKillDisable {
|
||||
if err := cgroups.WriteFile(path, "memory.oom_control", "1"); err != nil {
|
||||
if err := fscommon.WriteFile(path, "memory.oom_control", "1"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if r.MemorySwappiness == nil || int64(*r.MemorySwappiness) == -1 {
|
||||
return nil
|
||||
} else if *r.MemorySwappiness <= 100 {
|
||||
if err := cgroups.WriteFile(path, "memory.swappiness", strconv.FormatUint(*r.MemorySwappiness, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "memory.swappiness", strconv.FormatUint(*r.MemorySwappiness, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
@ -142,7 +143,7 @@ func (s *MemoryGroup) Set(path string, r *configs.Resources) error {
|
||||
|
||||
func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
// Set stats from memory.stat.
|
||||
statsFile, err := cgroups.OpenFile(path, "memory.stat", os.O_RDONLY)
|
||||
statsFile, err := fscommon.OpenFile(path, "memory.stat", os.O_RDONLY)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
@ -199,6 +200,14 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func memoryAssigned(cgroup *configs.Cgroup) bool {
|
||||
return cgroup.Resources.Memory != 0 ||
|
||||
cgroup.Resources.MemoryReservation != 0 ||
|
||||
cgroup.Resources.MemorySwap > 0 ||
|
||||
cgroup.Resources.OomKillDisable ||
|
||||
(cgroup.Resources.MemorySwappiness != nil && int64(*cgroup.Resources.MemorySwappiness) != -1)
|
||||
}
|
||||
|
||||
func getMemoryData(path, name string) (cgroups.MemoryData, error) {
|
||||
memoryData := cgroups.MemoryData{}
|
||||
|
||||
@ -249,13 +258,12 @@ func getPageUsageByNUMA(cgroupPath string) (cgroups.PageUsageByNUMA, error) {
|
||||
)
|
||||
stats := cgroups.PageUsageByNUMA{}
|
||||
|
||||
file, err := cgroups.OpenFile(cgroupPath, filename, os.O_RDONLY)
|
||||
file, err := fscommon.OpenFile(cgroupPath, filename, os.O_RDONLY)
|
||||
if os.IsNotExist(err) {
|
||||
return stats, nil
|
||||
} else if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// File format is documented in linux/Documentation/cgroup-v1/memory.txt
|
||||
// and it looks like this:
|
||||
|
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go
generated
vendored
@ -6,10 +6,12 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
type NetClsGroup struct{}
|
||||
type NetClsGroup struct {
|
||||
}
|
||||
|
||||
func (s *NetClsGroup) Name() string {
|
||||
return "net_cls"
|
||||
@ -21,7 +23,7 @@ func (s *NetClsGroup) Apply(path string, d *cgroupData) error {
|
||||
|
||||
func (s *NetClsGroup) Set(path string, r *configs.Resources) error {
|
||||
if r.NetClsClassid != 0 {
|
||||
if err := cgroups.WriteFile(path, "net_cls.classid", strconv.FormatUint(uint64(r.NetClsClassid), 10)); err != nil {
|
||||
if err := fscommon.WriteFile(path, "net_cls.classid", strconv.FormatUint(uint64(r.NetClsClassid), 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go
generated
vendored
@ -4,10 +4,12 @@ package fs
|
||||
|
||||
import (
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
type NetPrioGroup struct{}
|
||||
type NetPrioGroup struct {
|
||||
}
|
||||
|
||||
func (s *NetPrioGroup) Name() string {
|
||||
return "net_prio"
|
||||
@ -19,7 +21,7 @@ func (s *NetPrioGroup) Apply(path string, d *cgroupData) error {
|
||||
|
||||
func (s *NetPrioGroup) Set(path string, r *configs.Resources) error {
|
||||
for _, prioMap := range r.NetPrioIfpriomap {
|
||||
if err := cgroups.WriteFile(path, "net_prio.ifpriomap", prioMap.CgroupString()); err != nil {
|
||||
if err := fscommon.WriteFile(path, "net_prio.ifpriomap", prioMap.CgroupString()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
3
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go
generated
vendored
3
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go
generated
vendored
@ -7,7 +7,8 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
type PerfEventGroup struct{}
|
||||
type PerfEventGroup struct {
|
||||
}
|
||||
|
||||
func (s *PerfEventGroup) Name() string {
|
||||
return "perf_event"
|
||||
|
5
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go
generated
vendored
5
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go
generated
vendored
@ -12,7 +12,8 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
type PidsGroup struct{}
|
||||
type PidsGroup struct {
|
||||
}
|
||||
|
||||
func (s *PidsGroup) Name() string {
|
||||
return "pids"
|
||||
@ -31,7 +32,7 @@ func (s *PidsGroup) Set(path string, r *configs.Resources) error {
|
||||
limit = strconv.FormatInt(r.PidsLimit, 10)
|
||||
}
|
||||
|
||||
if err := cgroups.WriteFile(path, "pids.max", limit); err != nil {
|
||||
if err := fscommon.WriteFile(path, "pids.max", limit); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
7
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go
generated
vendored
7
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go
generated
vendored
@ -23,7 +23,7 @@ func setCpu(dirPath string, r *configs.Resources) error {
|
||||
|
||||
// NOTE: .CpuShares is not used here. Conversion is the caller's responsibility.
|
||||
if r.CpuWeight != 0 {
|
||||
if err := cgroups.WriteFile(dirPath, "cpu.weight", strconv.FormatUint(r.CpuWeight, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "cpu.weight", strconv.FormatUint(r.CpuWeight, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -40,16 +40,15 @@ func setCpu(dirPath string, r *configs.Resources) error {
|
||||
period = 100000
|
||||
}
|
||||
str += " " + strconv.FormatUint(period, 10)
|
||||
if err := cgroups.WriteFile(dirPath, "cpu.max", str); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "cpu.max", str); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func statCpu(dirPath string, stats *cgroups.Stats) error {
|
||||
f, err := cgroups.OpenFile(dirPath, "cpu.stat", os.O_RDONLY)
|
||||
f, err := fscommon.OpenFile(dirPath, "cpu.stat", os.O_RDONLY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go
generated
vendored
@ -3,7 +3,7 @@
|
||||
package fs2
|
||||
|
||||
import (
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
@ -17,12 +17,12 @@ func setCpuset(dirPath string, r *configs.Resources) error {
|
||||
}
|
||||
|
||||
if r.CpusetCpus != "" {
|
||||
if err := cgroups.WriteFile(dirPath, "cpuset.cpus", r.CpusetCpus); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "cpuset.cpus", r.CpusetCpus); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if r.CpusetMems != "" {
|
||||
if err := cgroups.WriteFile(dirPath, "cpuset.mems", r.CpusetMems); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "cpuset.mems", r.CpusetMems); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
14
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/create.go
generated
vendored
14
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/create.go
generated
vendored
@ -6,12 +6,12 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
func supportedControllers() (string, error) {
|
||||
return cgroups.ReadFile(UnifiedMountpoint, "/cgroup.controllers")
|
||||
return fscommon.ReadFile(UnifiedMountpoint, "/cgroup.controllers")
|
||||
}
|
||||
|
||||
// needAnyControllers returns whether we enable some supported controllers or not,
|
||||
@ -92,7 +92,7 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
|
||||
for i, e := range elements {
|
||||
current = filepath.Join(current, e)
|
||||
if i > 0 {
|
||||
if err := os.Mkdir(current, 0o755); err != nil {
|
||||
if err := os.Mkdir(current, 0755); err != nil {
|
||||
if !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
@ -105,7 +105,7 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
|
||||
}
|
||||
}()
|
||||
}
|
||||
cgType, _ := cgroups.ReadFile(current, cgTypeFile)
|
||||
cgType, _ := fscommon.ReadFile(current, cgTypeFile)
|
||||
cgType = strings.TrimSpace(cgType)
|
||||
switch cgType {
|
||||
// If the cgroup is in an invalid mode (usually this means there's an internal
|
||||
@ -122,7 +122,7 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
|
||||
// since that means we're a properly delegated cgroup subtree) but in
|
||||
// this case there's not much we can do and it's better than giving an
|
||||
// error.
|
||||
_ = cgroups.WriteFile(current, cgTypeFile, "threaded")
|
||||
_ = fscommon.WriteFile(current, cgTypeFile, "threaded")
|
||||
}
|
||||
// If the cgroup is in (threaded) or (domain threaded) mode, we can only use thread-aware controllers
|
||||
// (and you cannot usually take a cgroup out of threaded mode).
|
||||
@ -136,11 +136,11 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
|
||||
}
|
||||
// enable all supported controllers
|
||||
if i < len(elements)-1 {
|
||||
if err := cgroups.WriteFile(current, cgStCtlFile, res); err != nil {
|
||||
if err := fscommon.WriteFile(current, cgStCtlFile, res); err != nil {
|
||||
// try write one by one
|
||||
allCtrs := strings.Split(res, " ")
|
||||
for _, ctr := range allCtrs {
|
||||
_ = cgroups.WriteFile(current, cgStCtlFile, ctr)
|
||||
_ = fscommon.WriteFile(current, cgStCtlFile, ctr)
|
||||
}
|
||||
}
|
||||
// Some controllers might not be enabled when rootless or containerized,
|
||||
|
4
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go
generated
vendored
4
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go
generated
vendored
@ -82,7 +82,9 @@ func parseCgroupFile(path string) (string, error) {
|
||||
}
|
||||
|
||||
func parseCgroupFromReader(r io.Reader) (string, error) {
|
||||
s := bufio.NewScanner(r)
|
||||
var (
|
||||
s = bufio.NewScanner(r)
|
||||
)
|
||||
for s.Scan() {
|
||||
var (
|
||||
text = s.Text()
|
||||
|
16
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go
generated
vendored
16
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go
generated
vendored
@ -58,15 +58,29 @@ func setDevices(dirPath string, r *configs.Resources) error {
|
||||
if r.SkipDevices {
|
||||
return nil
|
||||
}
|
||||
// XXX: This is currently a white-list (but all callers pass a blacklist of
|
||||
// devices). This is bad for a whole variety of reasons, but will need
|
||||
// to be fixed with co-ordinated effort with downstreams.
|
||||
insts, license, err := devicefilter.DeviceFilter(r.Devices)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dirFD, err := unix.Open(dirPath, unix.O_DIRECTORY|unix.O_RDONLY, 0o600)
|
||||
dirFD, err := unix.Open(dirPath, unix.O_DIRECTORY|unix.O_RDONLY, 0600)
|
||||
if err != nil {
|
||||
return errors.Errorf("cannot get dir FD for %s", dirPath)
|
||||
}
|
||||
defer unix.Close(dirFD)
|
||||
// XXX: This code is currently incorrect when it comes to updating an
|
||||
// existing cgroup with new rules (new rulesets are just appended to
|
||||
// the program list because this uses BPF_F_ALLOW_MULTI). If we didn't
|
||||
// use BPF_F_ALLOW_MULTI we could actually atomically swap the
|
||||
// programs.
|
||||
//
|
||||
// The real issue is that BPF_F_ALLOW_MULTI makes it hard to have a
|
||||
// race-free blacklist because it acts as a whitelist by default, and
|
||||
// having a deny-everything program cannot be overridden by other
|
||||
// programs. You could temporarily insert a deny-everything program
|
||||
// but that would result in spurrious failures during updates.
|
||||
if _, err := ebpf.LoadAttachCgroupDeviceFilter(insts, license, dirFD); err != nil {
|
||||
if !canSkipEBPFError(r) {
|
||||
return err
|
||||
|
101
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go
generated
vendored
101
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go
generated
vendored
@ -3,20 +3,27 @@
|
||||
package fs2
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
stdErrors "errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func setFreezer(dirPath string, state configs.FreezerState) error {
|
||||
if err := supportsFreezer(dirPath); err != nil {
|
||||
// We can ignore this request as long as the user didn't ask us to
|
||||
// freeze the container (since without the freezer cgroup, that's a
|
||||
// no-op).
|
||||
if state == configs.Undefined || state == configs.Thawed {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrap(err, "freezer not supported")
|
||||
}
|
||||
|
||||
var stateStr string
|
||||
switch state {
|
||||
case configs.Undefined:
|
||||
@ -29,23 +36,11 @@ func setFreezer(dirPath string, state configs.FreezerState) error {
|
||||
return errors.Errorf("invalid freezer state %q requested", state)
|
||||
}
|
||||
|
||||
fd, err := cgroups.OpenFile(dirPath, "cgroup.freeze", unix.O_RDWR)
|
||||
if err != nil {
|
||||
// We can ignore this request as long as the user didn't ask us to
|
||||
// freeze the container (since without the freezer cgroup, that's a
|
||||
// no-op).
|
||||
if state != configs.Frozen {
|
||||
return nil
|
||||
}
|
||||
return errors.Wrap(err, "freezer not supported")
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
if _, err := fd.WriteString(stateStr); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "cgroup.freeze", stateStr); err != nil {
|
||||
return err
|
||||
}
|
||||
// Confirm that the cgroup did actually change states.
|
||||
if actualState, err := readFreezer(dirPath, fd); err != nil {
|
||||
if actualState, err := getFreezer(dirPath); err != nil {
|
||||
return err
|
||||
} else if actualState != state {
|
||||
return errors.Errorf(`expected "cgroup.freeze" to be in state %q but was in %q`, state, actualState)
|
||||
@ -53,8 +48,13 @@ func setFreezer(dirPath string, state configs.FreezerState) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func supportsFreezer(dirPath string) error {
|
||||
_, err := fscommon.ReadFile(dirPath, "cgroup.freeze")
|
||||
return err
|
||||
}
|
||||
|
||||
func getFreezer(dirPath string) (configs.FreezerState, error) {
|
||||
fd, err := cgroups.OpenFile(dirPath, "cgroup.freeze", unix.O_RDONLY)
|
||||
state, err := fscommon.ReadFile(dirPath, "cgroup.freeze")
|
||||
if err != nil {
|
||||
// If the kernel is too old, then we just treat the freezer as being in
|
||||
// an "undefined" state.
|
||||
@ -63,67 +63,12 @@ func getFreezer(dirPath string) (configs.FreezerState, error) {
|
||||
}
|
||||
return configs.Undefined, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
return readFreezer(dirPath, fd)
|
||||
}
|
||||
|
||||
func readFreezer(dirPath string, fd *os.File) (configs.FreezerState, error) {
|
||||
if _, err := fd.Seek(0, 0); err != nil {
|
||||
return configs.Undefined, err
|
||||
}
|
||||
state := make([]byte, 2)
|
||||
if _, err := fd.Read(state); err != nil {
|
||||
return configs.Undefined, err
|
||||
}
|
||||
switch string(state) {
|
||||
case "0\n":
|
||||
switch strings.TrimSpace(state) {
|
||||
case "0":
|
||||
return configs.Thawed, nil
|
||||
case "1\n":
|
||||
return waitFrozen(dirPath)
|
||||
case "1":
|
||||
return configs.Frozen, nil
|
||||
default:
|
||||
return configs.Undefined, errors.Errorf(`unknown "cgroup.freeze" state: %q`, state)
|
||||
}
|
||||
}
|
||||
|
||||
// waitFrozen polls cgroup.events until it sees "frozen 1" in it.
|
||||
func waitFrozen(dirPath string) (configs.FreezerState, error) {
|
||||
fd, err := cgroups.OpenFile(dirPath, "cgroup.events", unix.O_RDONLY)
|
||||
if err != nil {
|
||||
return configs.Undefined, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
// XXX: Simple wait/read/retry is used here. An implementation
|
||||
// based on poll(2) or inotify(7) is possible, but it makes the code
|
||||
// much more complicated. Maybe address this later.
|
||||
const (
|
||||
// Perform maxIter with waitTime in between iterations.
|
||||
waitTime = 10 * time.Millisecond
|
||||
maxIter = 1000
|
||||
)
|
||||
scanner := bufio.NewScanner(fd)
|
||||
for i := 0; scanner.Scan(); {
|
||||
if i == maxIter {
|
||||
return configs.Undefined, fmt.Errorf("timeout of %s reached waiting for the cgroup to freeze", waitTime*maxIter)
|
||||
}
|
||||
line := scanner.Text()
|
||||
val := strings.TrimPrefix(line, "frozen ")
|
||||
if val != line { // got prefix
|
||||
if val[0] == '1' {
|
||||
return configs.Frozen, nil
|
||||
}
|
||||
|
||||
i++
|
||||
// wait, then re-read
|
||||
time.Sleep(waitTime)
|
||||
_, err := fd.Seek(0, 0)
|
||||
if err != nil {
|
||||
return configs.Undefined, err
|
||||
}
|
||||
}
|
||||
}
|
||||
// Should only reach here either on read error,
|
||||
// or if the file does not contain "frozen " line.
|
||||
return configs.Undefined, scanner.Err()
|
||||
}
|
||||
|
8
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go
generated
vendored
8
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go
generated
vendored
@ -51,7 +51,7 @@ func (m *manager) getControllers() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := cgroups.ReadFile(m.dirPath, "cgroup.controllers")
|
||||
data, err := fscommon.ReadFile(m.dirPath, "cgroup.controllers")
|
||||
if err != nil {
|
||||
if m.rootless && m.config.Path == "" {
|
||||
return nil
|
||||
@ -98,7 +98,9 @@ func (m *manager) GetAllPids() ([]int, error) {
|
||||
}
|
||||
|
||||
func (m *manager) GetStats() (*cgroups.Stats, error) {
|
||||
var errs []error
|
||||
var (
|
||||
errs []error
|
||||
)
|
||||
|
||||
st := cgroups.NewStats()
|
||||
|
||||
@ -197,7 +199,7 @@ func (m *manager) setUnified(res map[string]string) error {
|
||||
if strings.Contains(k, "/") {
|
||||
return fmt.Errorf("unified resource %q must be a file name (no slashes)", k)
|
||||
}
|
||||
if err := cgroups.WriteFile(m.dirPath, k, v); err != nil {
|
||||
if err := fscommon.WriteFile(m.dirPath, k, v); err != nil {
|
||||
errC := errors.Cause(err)
|
||||
// Check for both EPERM and ENOENT since O_CREAT is used by WriteFile.
|
||||
if errors.Is(errC, os.ErrPermission) || errors.Is(errC, os.ErrNotExist) {
|
||||
|
2
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go
generated
vendored
@ -21,7 +21,7 @@ func setHugeTlb(dirPath string, r *configs.Resources) error {
|
||||
return nil
|
||||
}
|
||||
for _, hugetlb := range r.HugetlbLimit {
|
||||
if err := cgroups.WriteFile(dirPath, "hugetlb."+hugetlb.Pagesize+".max", strconv.FormatUint(hugetlb.Limit, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "hugetlb."+hugetlb.Pagesize+".max", strconv.FormatUint(hugetlb.Limit, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
98
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go
generated
vendored
98
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go
generated
vendored
@ -4,95 +4,60 @@ package fs2
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
func isIoSet(r *configs.Resources) bool {
|
||||
return r.BlkioWeight != 0 ||
|
||||
len(r.BlkioWeightDevice) > 0 ||
|
||||
len(r.BlkioThrottleReadBpsDevice) > 0 ||
|
||||
len(r.BlkioThrottleWriteBpsDevice) > 0 ||
|
||||
len(r.BlkioThrottleReadIOPSDevice) > 0 ||
|
||||
len(r.BlkioThrottleWriteIOPSDevice) > 0
|
||||
}
|
||||
|
||||
// bfqDeviceWeightSupported checks for per-device BFQ weight support (added
|
||||
// in kernel v5.4, commit 795fe54c2a8) by reading from "io.bfq.weight".
|
||||
func bfqDeviceWeightSupported(bfq *os.File) bool {
|
||||
if bfq == nil {
|
||||
return false
|
||||
}
|
||||
_, _ = bfq.Seek(0, 0)
|
||||
buf := make([]byte, 32)
|
||||
_, _ = bfq.Read(buf)
|
||||
// If only a single number (default weight) if read back, we have older kernel.
|
||||
_, err := strconv.ParseInt(string(bytes.TrimSpace(buf)), 10, 64)
|
||||
return err != nil
|
||||
}
|
||||
|
||||
func setIo(dirPath string, r *configs.Resources) error {
|
||||
if !isIoSet(r) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If BFQ IO scheduler is available, use it.
|
||||
var bfq *os.File
|
||||
if r.BlkioWeight != 0 || len(r.BlkioWeightDevice) > 0 {
|
||||
var err error
|
||||
bfq, err = cgroups.OpenFile(dirPath, "io.bfq.weight", os.O_RDWR)
|
||||
if err == nil {
|
||||
defer bfq.Close()
|
||||
} else if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if r.BlkioWeight != 0 {
|
||||
if bfq != nil { // Use BFQ.
|
||||
if _, err := bfq.WriteString(strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil {
|
||||
filename := "io.bfq.weight"
|
||||
if err := fscommon.WriteFile(dirPath, filename,
|
||||
strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil {
|
||||
// if io.bfq.weight does not exist, then bfq module is not loaded.
|
||||
// Fallback to use io.weight with a conversion scheme
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Fallback to io.weight with a conversion scheme.
|
||||
v := cgroups.ConvertBlkIOToIOWeightValue(r.BlkioWeight)
|
||||
if err := cgroups.WriteFile(dirPath, "io.weight", strconv.FormatUint(v, 10)); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "io.weight", strconv.FormatUint(v, 10)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if bfqDeviceWeightSupported(bfq) {
|
||||
for _, wd := range r.BlkioWeightDevice {
|
||||
if _, err := bfq.WriteString(wd.WeightString() + "\n"); err != nil {
|
||||
return fmt.Errorf("setting device weight %q: %w", wd.WeightString(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, td := range r.BlkioThrottleReadBpsDevice {
|
||||
if err := cgroups.WriteFile(dirPath, "io.max", td.StringName("rbps")); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("rbps")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, td := range r.BlkioThrottleWriteBpsDevice {
|
||||
if err := cgroups.WriteFile(dirPath, "io.max", td.StringName("wbps")); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wbps")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, td := range r.BlkioThrottleReadIOPSDevice {
|
||||
if err := cgroups.WriteFile(dirPath, "io.max", td.StringName("riops")); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("riops")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, td := range r.BlkioThrottleWriteIOPSDevice {
|
||||
if err := cgroups.WriteFile(dirPath, "io.max", td.StringName("wiops")); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wiops")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -102,7 +67,7 @@ func setIo(dirPath string, r *configs.Resources) error {
|
||||
|
||||
func readCgroup2MapFile(dirPath string, name string) (map[string][]string, error) {
|
||||
ret := map[string][]string{}
|
||||
f, err := cgroups.OpenFile(dirPath, name, os.O_RDONLY)
|
||||
f, err := fscommon.OpenFile(dirPath, name, os.O_RDONLY)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -123,22 +88,22 @@ func readCgroup2MapFile(dirPath string, name string) (map[string][]string, error
|
||||
}
|
||||
|
||||
func statIo(dirPath string, stats *cgroups.Stats) error {
|
||||
// more details on the io.stat file format: https://www.kernel.org/doc/Documentation/cgroup-v2.txt
|
||||
var ioServiceBytesRecursive []cgroups.BlkioStatEntry
|
||||
values, err := readCgroup2MapFile(dirPath, "io.stat")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// more details on the io.stat file format: https://www.kernel.org/doc/Documentation/cgroup-v2.txt
|
||||
var parsedStats cgroups.BlkioStats
|
||||
for k, v := range values {
|
||||
d := strings.Split(k, ":")
|
||||
if len(d) != 2 {
|
||||
continue
|
||||
}
|
||||
major, err := strconv.ParseUint(d[0], 10, 64)
|
||||
major, err := strconv.ParseUint(d[0], 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
minor, err := strconv.ParseUint(d[1], 10, 64)
|
||||
minor, err := strconv.ParseUint(d[1], 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -150,32 +115,15 @@ func statIo(dirPath string, stats *cgroups.Stats) error {
|
||||
}
|
||||
op := d[0]
|
||||
|
||||
// Map to the cgroupv1 naming and layout (in separate tables).
|
||||
var targetTable *[]cgroups.BlkioStatEntry
|
||||
// Accommodate the cgroup v1 naming
|
||||
switch op {
|
||||
// Equivalent to cgroupv1's blkio.io_service_bytes.
|
||||
case "rbytes":
|
||||
op = "Read"
|
||||
targetTable = &parsedStats.IoServiceBytesRecursive
|
||||
op = "read"
|
||||
case "wbytes":
|
||||
op = "Write"
|
||||
targetTable = &parsedStats.IoServiceBytesRecursive
|
||||
// Equivalent to cgroupv1's blkio.io_serviced.
|
||||
case "rios":
|
||||
op = "Read"
|
||||
targetTable = &parsedStats.IoServicedRecursive
|
||||
case "wios":
|
||||
op = "Write"
|
||||
targetTable = &parsedStats.IoServicedRecursive
|
||||
default:
|
||||
// Skip over entries we cannot map to cgroupv1 stats for now.
|
||||
// In the future we should expand the stats struct to include
|
||||
// them.
|
||||
logrus.Debugf("cgroupv2 io stats: skipping over unmappable %s entry", item)
|
||||
continue
|
||||
op = "write"
|
||||
}
|
||||
|
||||
value, err := strconv.ParseUint(d[1], 10, 64)
|
||||
value, err := strconv.ParseUint(d[1], 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -186,9 +134,9 @@ func statIo(dirPath string, stats *cgroups.Stats) error {
|
||||
Minor: minor,
|
||||
Value: value,
|
||||
}
|
||||
*targetTable = append(*targetTable, entry)
|
||||
ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry)
|
||||
}
|
||||
}
|
||||
stats.BlkioStats = parsedStats
|
||||
stats.BlkioStats = cgroups.BlkioStats{IoServiceBytesRecursive: ioServiceBytesRecursive}
|
||||
return nil
|
||||
}
|
||||
|
8
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go
generated
vendored
8
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go
generated
vendored
@ -52,13 +52,13 @@ func setMemory(dirPath string, r *configs.Resources) error {
|
||||
}
|
||||
// never write empty string to `memory.swap.max`, it means set to 0.
|
||||
if swapStr != "" {
|
||||
if err := cgroups.WriteFile(dirPath, "memory.swap.max", swapStr); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "memory.swap.max", swapStr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if val := numToStr(r.Memory); val != "" {
|
||||
if err := cgroups.WriteFile(dirPath, "memory.max", val); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "memory.max", val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -66,7 +66,7 @@ func setMemory(dirPath string, r *configs.Resources) error {
|
||||
// cgroup.Resources.KernelMemory is ignored
|
||||
|
||||
if val := numToStr(r.MemoryReservation); val != "" {
|
||||
if err := cgroups.WriteFile(dirPath, "memory.low", val); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "memory.low", val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -76,7 +76,7 @@ func setMemory(dirPath string, r *configs.Resources) error {
|
||||
|
||||
func statMemory(dirPath string, stats *cgroups.Stats) error {
|
||||
// Set stats from memory.stat.
|
||||
statsFile, err := cgroups.OpenFile(dirPath, "memory.stat", os.O_RDONLY)
|
||||
statsFile, err := fscommon.OpenFile(dirPath, "memory.stat", os.O_RDONLY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go
generated
vendored
@ -23,7 +23,7 @@ func setPids(dirPath string, r *configs.Resources) error {
|
||||
return nil
|
||||
}
|
||||
if val := numToStr(r.PidsLimit); val != "" {
|
||||
if err := cgroups.WriteFile(dirPath, "pids.max", val); err != nil {
|
||||
if err := fscommon.WriteFile(dirPath, "pids.max", val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -34,9 +34,9 @@ func setPids(dirPath string, r *configs.Resources) error {
|
||||
func statPidsFromCgroupProcs(dirPath string, stats *cgroups.Stats) error {
|
||||
// if the controller is not enabled, let's read PIDS from cgroups.procs
|
||||
// (or threads if cgroup.threads is enabled)
|
||||
contents, err := cgroups.ReadFile(dirPath, "cgroup.procs")
|
||||
contents, err := fscommon.ReadFile(dirPath, "cgroup.procs")
|
||||
if errors.Is(err, unix.ENOTSUP) {
|
||||
contents, err = cgroups.ReadFile(dirPath, "cgroup.threads")
|
||||
contents, err = fscommon.ReadFile(dirPath, "cgroup.threads")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
51
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/fscommon.go
generated
vendored
Normal file
51
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/fscommon.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
// +build linux
|
||||
|
||||
package fscommon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// WriteFile writes data to a cgroup file in dir.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func WriteFile(dir, file, data string) error {
|
||||
fd, err := OpenFile(dir, file, unix.O_WRONLY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fd.Close()
|
||||
if err := retryingWriteFile(fd, data); err != nil {
|
||||
return errors.Wrapf(err, "failed to write %q", data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadFile reads data from a cgroup file in dir.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func ReadFile(dir, file string) (string, error) {
|
||||
fd, err := OpenFile(dir, file, unix.O_RDONLY)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer fd.Close()
|
||||
var buf bytes.Buffer
|
||||
|
||||
_, err = buf.ReadFrom(fd)
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
func retryingWriteFile(fd *os.File, data string) error {
|
||||
for {
|
||||
_, err := fd.Write([]byte(data))
|
||||
if errors.Is(err, unix.EINTR) {
|
||||
logrus.Infof("interrupted while writing %s to %s", data, fd.Name())
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package cgroups
|
||||
package fscommon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -11,54 +10,6 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// OpenFile opens a cgroup file in a given dir with given flags.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func OpenFile(dir, file string, flags int) (*os.File, error) {
|
||||
if dir == "" {
|
||||
return nil, errors.Errorf("no directory specified for %s", file)
|
||||
}
|
||||
return openFile(dir, file, flags)
|
||||
}
|
||||
|
||||
// ReadFile reads data from a cgroup file in dir.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func ReadFile(dir, file string) (string, error) {
|
||||
fd, err := OpenFile(dir, file, unix.O_RDONLY)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer fd.Close()
|
||||
var buf bytes.Buffer
|
||||
|
||||
_, err = buf.ReadFrom(fd)
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
// WriteFile writes data to a cgroup file in dir.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func WriteFile(dir, file, data string) error {
|
||||
fd, err := OpenFile(dir, file, unix.O_WRONLY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fd.Close()
|
||||
if err := retryingWriteFile(fd, data); err != nil {
|
||||
return errors.Wrapf(err, "failed to write %q", data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func retryingWriteFile(fd *os.File, data string) error {
|
||||
for {
|
||||
_, err := fd.Write([]byte(data))
|
||||
if errors.Is(err, unix.EINTR) {
|
||||
logrus.Infof("interrupted while writing %s to %s", data, fd.Name())
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
cgroupfsDir = "/sys/fs/cgroup"
|
||||
cgroupfsPrefix = cgroupfsDir + "/"
|
||||
@ -77,8 +28,7 @@ var (
|
||||
func prepareOpenat2() error {
|
||||
prepOnce.Do(func() {
|
||||
fd, err := unix.Openat2(-1, cgroupfsDir, &unix.OpenHow{
|
||||
Flags: unix.O_DIRECTORY | unix.O_PATH,
|
||||
})
|
||||
Flags: unix.O_DIRECTORY | unix.O_PATH})
|
||||
if err != nil {
|
||||
prepErr = &os.PathError{Op: "openat2", Path: cgroupfsDir, Err: err}
|
||||
if err != unix.ENOSYS {
|
||||
@ -102,6 +52,7 @@ func prepareOpenat2() error {
|
||||
// cgroupv2 has a single mountpoint and no "cpu,cpuacct" symlinks
|
||||
resolveFlags |= unix.RESOLVE_NO_XDEV | unix.RESOLVE_NO_SYMLINKS
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return prepErr
|
||||
@ -109,7 +60,10 @@ func prepareOpenat2() error {
|
||||
|
||||
// OpenFile opens a cgroup file in a given dir with given flags.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func openFile(dir, file string, flags int) (*os.File, error) {
|
||||
func OpenFile(dir, file string, flags int) (*os.File, error) {
|
||||
if dir == "" {
|
||||
return nil, errors.Errorf("no directory specified for %s", file)
|
||||
}
|
||||
mode := os.FileMode(0)
|
||||
if TestMode && flags&os.O_WRONLY != 0 {
|
||||
// "emulate" cgroup fs for unit tests
|
15
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/utils.go
generated
vendored
15
vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/utils.go
generated
vendored
@ -8,19 +8,10 @@ import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotValidFormat = errors.New("line is not a valid key value format")
|
||||
|
||||
// Deprecated: use cgroups.OpenFile instead.
|
||||
OpenFile = cgroups.OpenFile
|
||||
// Deprecated: use cgroups.ReadFile instead.
|
||||
ReadFile = cgroups.ReadFile
|
||||
// Deprecated: use cgroups.WriteFile instead.
|
||||
WriteFile = cgroups.WriteFile
|
||||
)
|
||||
|
||||
// ParseUint converts a string to an uint64 integer.
|
||||
@ -66,7 +57,7 @@ func ParseKeyValue(t string) (string, uint64, error) {
|
||||
// and returns a value of the specified key. ParseUint is used for value
|
||||
// conversion.
|
||||
func GetValueByKey(path, file, key string) (uint64, error) {
|
||||
content, err := cgroups.ReadFile(path, file)
|
||||
content, err := ReadFile(path, file)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -104,7 +95,7 @@ func GetCgroupParamUint(path, file string) (uint64, error) {
|
||||
// GetCgroupParamInt reads a single int64 value from specified cgroup file.
|
||||
// If the value read is "max", the math.MaxInt64 is returned.
|
||||
func GetCgroupParamInt(path, file string) (int64, error) {
|
||||
contents, err := cgroups.ReadFile(path, file)
|
||||
contents, err := ReadFile(path, file)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -122,7 +113,7 @@ func GetCgroupParamInt(path, file string) (int64, error) {
|
||||
|
||||
// GetCgroupParamString reads a string from the specified cgroup file.
|
||||
func GetCgroupParamString(path, file string) (string, error) {
|
||||
contents, err := cgroups.ReadFile(path, file)
|
||||
contents, err := ReadFile(path, file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
50
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go
generated
vendored
50
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go
generated
vendored
@ -158,27 +158,14 @@ func findDeviceGroup(ruleType devices.Type, ruleMajor int64) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// DeviceAllow is the dbus type "a(ss)" which means we need a struct
|
||||
// to represent it in Go.
|
||||
type deviceAllowEntry struct {
|
||||
Path string
|
||||
Perms string
|
||||
}
|
||||
|
||||
func allowAllDevices() []systemdDbus.Property {
|
||||
// Setting mode to auto and removing all DeviceAllow rules
|
||||
// results in allowing access to all devices.
|
||||
return []systemdDbus.Property{
|
||||
newProp("DevicePolicy", "auto"),
|
||||
newProp("DeviceAllow", []deviceAllowEntry{}),
|
||||
}
|
||||
}
|
||||
|
||||
// generateDeviceProperties takes the configured device rules and generates a
|
||||
// corresponding set of systemd properties to configure the devices correctly.
|
||||
func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, error) {
|
||||
if r.SkipDevices {
|
||||
return nil, nil
|
||||
func generateDeviceProperties(rules []*devices.Rule) ([]systemdDbus.Property, error) {
|
||||
// DeviceAllow is the type "a(ss)" which means we need a temporary struct
|
||||
// to represent it in Go.
|
||||
type deviceAllowEntry struct {
|
||||
Path string
|
||||
Perms string
|
||||
}
|
||||
|
||||
properties := []systemdDbus.Property{
|
||||
@ -190,7 +177,7 @@ func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, err
|
||||
|
||||
// Figure out the set of rules.
|
||||
configEmu := &cgroupdevices.Emulator{}
|
||||
for _, rule := range r.Devices {
|
||||
for _, rule := range rules {
|
||||
if err := configEmu.Apply(*rule); err != nil {
|
||||
return nil, errors.Wrap(err, "apply rule for systemd")
|
||||
}
|
||||
@ -202,7 +189,12 @@ func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, err
|
||||
if configEmu.IsBlacklist() {
|
||||
// However, if we're dealing with an allow-all rule then we can do it.
|
||||
if configEmu.IsAllowAll() {
|
||||
return allowAllDevices(), nil
|
||||
return []systemdDbus.Property{
|
||||
// Run in white-list mode by setting to "auto" and removing all
|
||||
// DeviceAllow rules.
|
||||
newProp("DevicePolicy", "auto"),
|
||||
newProp("DeviceAllow", []deviceAllowEntry{}),
|
||||
}, nil
|
||||
}
|
||||
logrus.Warn("systemd doesn't support blacklist device rules -- applying temporary deny-all rule")
|
||||
return properties, nil
|
||||
@ -211,7 +203,8 @@ func generateDeviceProperties(r *configs.Resources) ([]systemdDbus.Property, err
|
||||
// Now generate the set of rules we actually need to apply. Unlike the
|
||||
// normal devices cgroup, in "strict" mode systemd defaults to a deny-all
|
||||
// whitelist which is the default for devices.Emulator.
|
||||
finalRules, err := configEmu.Rules()
|
||||
baseEmu := &cgroupdevices.Emulator{}
|
||||
finalRules, err := baseEmu.Transition(configEmu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get simplified rules for systemd")
|
||||
}
|
||||
@ -313,7 +306,7 @@ func getUnitName(c *configs.Cgroup) string {
|
||||
// isDbusError returns true if the error is a specific dbus error.
|
||||
func isDbusError(err error, name string) bool {
|
||||
if err != nil {
|
||||
var derr dbus.Error
|
||||
var derr *dbus.Error
|
||||
if errors.As(err, &derr) {
|
||||
return strings.Contains(derr.Name, name)
|
||||
}
|
||||
@ -362,9 +355,6 @@ func stopUnit(cm *dbusConnManager, unitName string) error {
|
||||
return err
|
||||
})
|
||||
if err == nil {
|
||||
timeout := time.NewTimer(30 * time.Second)
|
||||
defer timeout.Stop()
|
||||
|
||||
select {
|
||||
case s := <-statusChan:
|
||||
close(statusChan)
|
||||
@ -372,8 +362,8 @@ func stopUnit(cm *dbusConnManager, unitName string) error {
|
||||
if s != "done" {
|
||||
logrus.Warnf("error removing unit `%s`: got `%s`. Continuing...", unitName, s)
|
||||
}
|
||||
case <-timeout.C:
|
||||
return errors.New("Timed out while waiting for systemd to remove " + unitName)
|
||||
case <-time.After(time.Second):
|
||||
logrus.Warnf("Timed out while waiting for StopUnit(%s) completion signal from dbus. Continuing...", unitName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -486,7 +476,7 @@ func addCpuset(cm *dbusConnManager, props *[]systemdDbus.Property, cpus, mems st
|
||||
}
|
||||
|
||||
if cpus != "" {
|
||||
bits, err := RangeToBits(cpus)
|
||||
bits, err := rangeToBits(cpus)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resources.CPU.Cpus=%q conversion error: %w",
|
||||
cpus, err)
|
||||
@ -495,7 +485,7 @@ func addCpuset(cm *dbusConnManager, props *[]systemdDbus.Property, cpus, mems st
|
||||
newProp("AllowedCPUs", bits))
|
||||
}
|
||||
if mems != "" {
|
||||
bits, err := RangeToBits(mems)
|
||||
bits, err := rangeToBits(mems)
|
||||
if err != nil {
|
||||
return fmt.Errorf("resources.CPU.Mems=%q conversion error: %w",
|
||||
mems, err)
|
||||
|
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/cpuset.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/cpuset.go
generated
vendored
@ -5,15 +5,15 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bits-and-blooms/bitset"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/willf/bitset"
|
||||
)
|
||||
|
||||
// RangeToBits converts a text representation of a CPU mask (as written to
|
||||
// rangeToBits converts a text representation of a CPU mask (as written to
|
||||
// or read from cgroups' cpuset.* files, e.g. "1,3-5") to a slice of bytes
|
||||
// with the corresponding bits set (as consumed by systemd over dbus as
|
||||
// AllowedCPUs/AllowedMemoryNodes unit property value).
|
||||
func RangeToBits(str string) ([]byte, error) {
|
||||
func rangeToBits(str string) ([]byte, error) {
|
||||
bits := &bitset.BitSet{}
|
||||
|
||||
for _, r := range strings.Split(str, ",") {
|
||||
|
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/dbus.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/dbus.go
generated
vendored
@ -17,16 +17,14 @@ var (
|
||||
dbusRootless bool
|
||||
)
|
||||
|
||||
type dbusConnManager struct{}
|
||||
type dbusConnManager struct {
|
||||
}
|
||||
|
||||
// newDbusConnManager initializes systemd dbus connection manager.
|
||||
func newDbusConnManager(rootless bool) *dbusConnManager {
|
||||
dbusMu.Lock()
|
||||
defer dbusMu.Unlock()
|
||||
if dbusInited && rootless != dbusRootless {
|
||||
panic("can't have both root and rootless dbus")
|
||||
}
|
||||
dbusInited = true
|
||||
dbusRootless = rootless
|
||||
return &dbusConnManager{}
|
||||
}
|
||||
|
38
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go
generated
vendored
38
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go
generated
vendored
@ -61,7 +61,7 @@ var legacySubsystems = []subsystem{
|
||||
func genV1ResourcesProperties(r *configs.Resources, cm *dbusConnManager) ([]systemdDbus.Property, error) {
|
||||
var properties []systemdDbus.Property
|
||||
|
||||
deviceProperties, err := generateDeviceProperties(r)
|
||||
deviceProperties, err := generateDeviceProperties(r.Devices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -207,10 +207,9 @@ func (m *legacyManager) Destroy() error {
|
||||
|
||||
stopErr := stopUnit(m.dbus, getUnitName(m.cgroups))
|
||||
|
||||
// Both on success and on error, cleanup all the cgroups
|
||||
// we are aware of, as some of them were created directly
|
||||
// by Apply() and are not managed by systemd.
|
||||
if err := cgroups.RemovePaths(m.paths); err != nil && stopErr == nil {
|
||||
// Both on success and on error, cleanup all the cgroups we are aware of.
|
||||
// Some of them were created directly by Apply() and are not managed by systemd.
|
||||
if err := cgroups.RemovePaths(m.paths); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -238,7 +237,7 @@ func (m *legacyManager) joinCgroups(pid int) error {
|
||||
}
|
||||
default:
|
||||
if path, ok := m.paths[name]; ok {
|
||||
if err := os.MkdirAll(path, 0o755); err != nil {
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cgroups.WriteCgroupProc(path, pid); err != nil {
|
||||
@ -339,24 +338,27 @@ func (m *legacyManager) Set(r *configs.Resources) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Figure out the current freezer state, so we can revert to it after we
|
||||
// temporarily freeze the container.
|
||||
targetFreezerState, err := m.GetFreezerState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if targetFreezerState == configs.Undefined {
|
||||
targetFreezerState = configs.Thawed
|
||||
}
|
||||
|
||||
// We have to freeze the container while systemd sets the cgroup settings.
|
||||
// The reason for this is that systemd's application of DeviceAllow rules
|
||||
// is done disruptively, resulting in spurrious errors to common devices
|
||||
// (unlike our fs driver, they will happily write deny-all rules to running
|
||||
// containers). So we freeze the container to avoid them hitting the cgroup
|
||||
// error. But if the freezer cgroup isn't supported, we just warn about it.
|
||||
if err := m.Freeze(configs.Frozen); err != nil {
|
||||
logrus.Infof("freeze container before SetUnitProperties failed: %v", err)
|
||||
targetFreezerState := configs.Undefined
|
||||
if !m.cgroups.SkipDevices {
|
||||
// Figure out the current freezer state, so we can revert to it after we
|
||||
// temporarily freeze the container.
|
||||
targetFreezerState, err = m.GetFreezerState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if targetFreezerState == configs.Undefined {
|
||||
targetFreezerState = configs.Thawed
|
||||
}
|
||||
|
||||
if err := m.Freeze(configs.Frozen); err != nil {
|
||||
logrus.Infof("freeze container before SetUnitProperties failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := setUnitProperties(m.dbus, getUnitName(m.cgroups), properties...); err != nil {
|
||||
|
31
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go
generated
vendored
31
vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go
generated
vendored
@ -96,7 +96,7 @@ func unifiedResToSystemdProps(cm *dbusConnManager, res map[string]string) (props
|
||||
newProp("CPUWeight", num))
|
||||
|
||||
case "cpuset.cpus", "cpuset.mems":
|
||||
bits, err := RangeToBits(v)
|
||||
bits, err := rangeToBits(v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unified resource %q=%q conversion error: %w", k, v, err)
|
||||
}
|
||||
@ -172,7 +172,7 @@ func genV2ResourcesProperties(r *configs.Resources, cm *dbusConnManager) ([]syst
|
||||
// aren't the end of the world, but it is a bit concerning. However
|
||||
// it's unclear if systemd removes all eBPF programs attached when
|
||||
// doing SetUnitProperties...
|
||||
deviceProperties, err := generateDeviceProperties(r)
|
||||
deviceProperties, err := generateDeviceProperties(r.Devices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -418,24 +418,27 @@ func (m *unifiedManager) Set(r *configs.Resources) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Figure out the current freezer state, so we can revert to it after we
|
||||
// temporarily freeze the container.
|
||||
targetFreezerState, err := m.GetFreezerState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if targetFreezerState == configs.Undefined {
|
||||
targetFreezerState = configs.Thawed
|
||||
}
|
||||
|
||||
// We have to freeze the container while systemd sets the cgroup settings.
|
||||
// The reason for this is that systemd's application of DeviceAllow rules
|
||||
// is done disruptively, resulting in spurrious errors to common devices
|
||||
// (unlike our fs driver, they will happily write deny-all rules to running
|
||||
// containers). So we freeze the container to avoid them hitting the cgroup
|
||||
// error. But if the freezer cgroup isn't supported, we just warn about it.
|
||||
if err := m.Freeze(configs.Frozen); err != nil {
|
||||
logrus.Infof("freeze container before SetUnitProperties failed: %v", err)
|
||||
targetFreezerState := configs.Undefined
|
||||
if !m.cgroups.SkipDevices {
|
||||
// Figure out the current freezer state, so we can revert to it after we
|
||||
// temporarily freeze the container.
|
||||
targetFreezerState, err = m.GetFreezerState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if targetFreezerState == configs.Undefined {
|
||||
targetFreezerState = configs.Thawed
|
||||
}
|
||||
|
||||
if err := m.Freeze(configs.Frozen); err != nil {
|
||||
logrus.Infof("freeze container before SetUnitProperties failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := setUnitProperties(m.dbus, getUnitName(m.cgroups), properties...); err != nil {
|
||||
|
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
generated
vendored
@ -15,6 +15,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/opencontainers/runc/libcontainer/userns"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
@ -87,7 +88,7 @@ func GetAllSubsystems() ([]string, error) {
|
||||
// - freezer: implemented in kernel 5.2
|
||||
// We assume these are always available, as it is hard to detect availability.
|
||||
pseudo := []string{"devices", "freezer"}
|
||||
data, err := ReadFile("/sys/fs/cgroup", "cgroup.controllers")
|
||||
data, err := fscommon.ReadFile("/sys/fs/cgroup", "cgroup.controllers")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -266,6 +267,7 @@ func RemovePaths(paths map[string]string) (err error) {
|
||||
case retries - 1:
|
||||
logrus.WithError(err).Error("Failed to remove cgroup")
|
||||
}
|
||||
|
||||
}
|
||||
_, err := os.Stat(p)
|
||||
// We need this strange way of checking cgroups existence because
|
||||
@ -374,7 +376,7 @@ func WriteCgroupProc(dir string, pid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
file, err := OpenFile(dir, CgroupProcesses, os.O_WRONLY)
|
||||
file, err := fscommon.OpenFile(dir, CgroupProcesses, os.O_WRONLY)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write %v to %v: %v", pid, CgroupProcesses, err)
|
||||
}
|
||||
|
10
vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go
generated
vendored
10
vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go
generated
vendored
@ -13,12 +13,12 @@ const (
|
||||
Thawed FreezerState = "THAWED"
|
||||
)
|
||||
|
||||
// Cgroup holds properties of a cgroup on Linux.
|
||||
type Cgroup struct {
|
||||
// Name specifies the name of the cgroup
|
||||
// Deprecated, use Path instead
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// Parent specifies the name of parent of cgroup or slice
|
||||
// name of parent of cgroup or slice
|
||||
// Deprecated, use Path instead
|
||||
Parent string `json:"parent,omitempty"`
|
||||
|
||||
// Path specifies the path to cgroups that are created and/or joined by the container.
|
||||
@ -127,8 +127,8 @@ type Resources struct {
|
||||
|
||||
// SkipDevices allows to skip configuring device permissions.
|
||||
// Used by e.g. kubelet while creating a parent cgroup (kubepods)
|
||||
// common for many containers, and by runc update.
|
||||
// common for many containers.
|
||||
//
|
||||
// NOTE it is impossible to start a container which has this flag set.
|
||||
SkipDevices bool `json:"-"`
|
||||
SkipDevices bool `json:"skip_devices"`
|
||||
}
|
||||
|
4
vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go
generated
vendored
4
vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_unsupported.go
generated
vendored
@ -2,7 +2,7 @@
|
||||
|
||||
package configs
|
||||
|
||||
// Cgroup holds properties of a cgroup on Linux
|
||||
// TODO Windows: This can ultimately be entirely factored out on Windows as
|
||||
// cgroups are a Unix-specific construct.
|
||||
type Cgroup struct{}
|
||||
type Cgroup struct {
|
||||
}
|
||||
|
10
vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
generated
vendored
10
vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
generated
vendored
@ -208,11 +208,9 @@ type Config struct {
|
||||
RootlessCgroups bool `json:"rootless_cgroups,omitempty"`
|
||||
}
|
||||
|
||||
type (
|
||||
HookName string
|
||||
HookList []Hook
|
||||
Hooks map[HookName]HookList
|
||||
)
|
||||
type HookName string
|
||||
type HookList []Hook
|
||||
type Hooks map[HookName]HookList
|
||||
|
||||
const (
|
||||
// Prestart commands are executed after the container namespaces are created,
|
||||
@ -389,7 +387,7 @@ func (c Command) Run(s *specs.State) error {
|
||||
case err := <-errC:
|
||||
return err
|
||||
case <-timerCh:
|
||||
_ = cmd.Process.Kill()
|
||||
cmd.Process.Kill()
|
||||
<-errC
|
||||
return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
|
||||
}
|
||||
|
17
vendor/github.com/opencontainers/runc/libcontainer/configs/devices.go
generated
vendored
Normal file
17
vendor/github.com/opencontainers/runc/libcontainer/configs/devices.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
package configs
|
||||
|
||||
import "github.com/opencontainers/runc/libcontainer/devices"
|
||||
|
||||
type (
|
||||
// Deprecated: use libcontainer/devices.Device
|
||||
Device = devices.Device
|
||||
|
||||
// Deprecated: use libcontainer/devices.Rule
|
||||
DeviceRule = devices.Rule
|
||||
|
||||
// Deprecated: use libcontainer/devices.Type
|
||||
DeviceType = devices.Type
|
||||
|
||||
// Deprecated: use libcontainer/devices.Permissions
|
||||
DevicePermissions = devices.Permissions
|
||||
)
|
2
vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/configs/mount.go
generated
vendored
@ -3,7 +3,7 @@ package configs
|
||||
const (
|
||||
// EXT_COPYUP is a directive to copy up the contents of a directory when
|
||||
// a tmpfs is mounted over it.
|
||||
EXT_COPYUP = 1 << iota //nolint:golint // ignore "don't use ALL_CAPS" warning
|
||||
EXT_COPYUP = 1 << iota
|
||||
)
|
||||
|
||||
type Mount struct {
|
||||
|
3
vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go
generated
vendored
3
vendor/github.com/opencontainers/runc/libcontainer/configs/namespaces_unsupported.go
generated
vendored
@ -4,4 +4,5 @@ package configs
|
||||
|
||||
// Namespace defines configuration for each namespace. It specifies an
|
||||
// alternate path that is able to be joined via setns.
|
||||
type Namespace struct{}
|
||||
type Namespace struct {
|
||||
}
|
||||
|
13
vendor/github.com/opencontainers/runc/libcontainer/configs/network.go
generated
vendored
13
vendor/github.com/opencontainers/runc/libcontainer/configs/network.go
generated
vendored
@ -50,10 +50,7 @@ type Network struct {
|
||||
HairpinMode bool `json:"hairpin_mode"`
|
||||
}
|
||||
|
||||
// Route defines a routing table entry.
|
||||
//
|
||||
// Routes can be specified to create entries in the routing table as the container
|
||||
// is started.
|
||||
// Routes can be specified to create entries in the route table as the container is started
|
||||
//
|
||||
// All of destination, source, and gateway should be either IPv4 or IPv6.
|
||||
// One of the three options must be present, and omitted entries will use their
|
||||
@ -61,15 +58,15 @@ type Network struct {
|
||||
// gateway to 1.2.3.4 and the interface to eth0 will set up a standard
|
||||
// destination of 0.0.0.0(or *) when viewed in the route table.
|
||||
type Route struct {
|
||||
// Destination specifies the destination IP address and mask in the CIDR form.
|
||||
// Sets the destination and mask, should be a CIDR. Accepts IPv4 and IPv6
|
||||
Destination string `json:"destination"`
|
||||
|
||||
// Source specifies the source IP address and mask in the CIDR form.
|
||||
// Sets the source and mask, should be a CIDR. Accepts IPv4 and IPv6
|
||||
Source string `json:"source"`
|
||||
|
||||
// Gateway specifies the gateway IP address.
|
||||
// Sets the gateway. Accepts IPv4 and IPv6
|
||||
Gateway string `json:"gateway"`
|
||||
|
||||
// InterfaceName specifies the device to set this route up for, for example eth0.
|
||||
// The device to set this route up for, for example: eth0
|
||||
InterfaceName string `json:"interface_name"`
|
||||
}
|
||||
|
17
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
generated
vendored
17
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
generated
vendored
@ -12,7 +12,6 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/intelrdt"
|
||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@ -24,13 +23,13 @@ func New() Validator {
|
||||
return &ConfigValidator{}
|
||||
}
|
||||
|
||||
type ConfigValidator struct{}
|
||||
type ConfigValidator struct {
|
||||
}
|
||||
|
||||
type check func(config *configs.Config) error
|
||||
|
||||
func (v *ConfigValidator) Validate(config *configs.Config) error {
|
||||
checks := []check{
|
||||
v.cgroups,
|
||||
v.rootfs,
|
||||
v.network,
|
||||
v.hostname,
|
||||
@ -40,21 +39,17 @@ func (v *ConfigValidator) Validate(config *configs.Config) error {
|
||||
v.sysctl,
|
||||
v.intelrdt,
|
||||
v.rootlessEUID,
|
||||
v.mounts,
|
||||
}
|
||||
for _, c := range checks {
|
||||
if err := c(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Relaxed validation rules for backward compatibility
|
||||
warns := []check{
|
||||
v.mounts, // TODO (runc v1.x.x): make this an error instead of a warning
|
||||
}
|
||||
for _, c := range warns {
|
||||
if err := c(config); err != nil {
|
||||
logrus.WithError(err).Warnf("invalid configuration")
|
||||
}
|
||||
if err := v.cgroups(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/opencontainers/runc/libcontainer/console_linux.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/console_linux.go
generated
vendored
@ -9,7 +9,7 @@ import (
|
||||
// mount initializes the console inside the rootfs mounting with the specified mount label
|
||||
// and applying the correct ownership of the console.
|
||||
func mountConsole(slavePath string) error {
|
||||
oldMask := unix.Umask(0o000)
|
||||
oldMask := unix.Umask(0000)
|
||||
defer unix.Umask(oldMask)
|
||||
f, err := os.Create("/dev/console")
|
||||
if err != nil && !os.IsExist(err) {
|
||||
|
33
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
33
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
@ -437,8 +437,8 @@ func (c *linuxContainer) createExecFifo() error {
|
||||
if _, err := os.Stat(fifoName); err == nil {
|
||||
return fmt.Errorf("exec fifo %s already exists", fifoName)
|
||||
}
|
||||
oldMask := unix.Umask(0o000)
|
||||
if err := unix.Mkfifo(fifoName, 0o622); err != nil {
|
||||
oldMask := unix.Umask(0000)
|
||||
if err := unix.Mkfifo(fifoName, 0622); err != nil {
|
||||
unix.Umask(oldMask)
|
||||
return err
|
||||
}
|
||||
@ -699,6 +699,7 @@ func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struc
|
||||
var criuFeatures *criurpc.CriuFeatures
|
||||
|
||||
func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.CriuOpts, criuFeat *criurpc.CriuFeatures) error {
|
||||
|
||||
t := criurpc.CriuReqType_FEATURE_CHECK
|
||||
|
||||
// make sure the features we are looking for are really not from
|
||||
@ -760,6 +761,7 @@ func compareCriuVersion(criuVersion int, minVersion int) error {
|
||||
|
||||
// checkCriuVersion checks Criu version greater than or equal to minVersion
|
||||
func (c *linuxContainer) checkCriuVersion(minVersion int) error {
|
||||
|
||||
// If the version of criu has already been determined there is no need
|
||||
// to ask criu for the version again. Use the value from c.criuVersion.
|
||||
if c.criuVersion != 0 {
|
||||
@ -968,7 +970,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||
|
||||
// Since a container can be C/R'ed multiple times,
|
||||
// the checkpoint directory may already exist.
|
||||
if err := os.Mkdir(criuOpts.ImagesDirectory, 0o700); err != nil && !os.IsExist(err) {
|
||||
if err := os.Mkdir(criuOpts.ImagesDirectory, 0700); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -976,7 +978,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||
criuOpts.WorkDirectory = filepath.Join(c.root, "criu.work")
|
||||
}
|
||||
|
||||
if err := os.Mkdir(criuOpts.WorkDirectory, 0o700); err != nil && !os.IsExist(err) {
|
||||
if err := os.Mkdir(criuOpts.WorkDirectory, 0700); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -1046,7 +1048,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||
}
|
||||
}
|
||||
|
||||
// pre-dump may need parentImage param to complete iterative migration
|
||||
//pre-dump may need parentImage param to complete iterative migration
|
||||
if criuOpts.ParentImage != "" {
|
||||
rpcOpts.ParentImg = proto.String(criuOpts.ParentImage)
|
||||
rpcOpts.TrackMem = proto.Bool(true)
|
||||
@ -1144,7 +1146,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename), fdsJSON, 0o600)
|
||||
err = ioutil.WriteFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename), fdsJSON, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1215,7 +1217,7 @@ func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error {
|
||||
if err := checkProcMount(c.config.Rootfs, dest, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(dest, 0o755); err != nil {
|
||||
if err := os.MkdirAll(dest, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -1316,7 +1318,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||
}
|
||||
// Since a container can be C/R'ed multiple times,
|
||||
// the work directory may already exist.
|
||||
if err := os.Mkdir(criuOpts.WorkDirectory, 0o700); err != nil && !os.IsExist(err) {
|
||||
if err := os.Mkdir(criuOpts.WorkDirectory, 0700); err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
workDir, err := os.Open(criuOpts.WorkDirectory)
|
||||
@ -1338,7 +1340,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||
// c.config.Rootfs is bind-mounted to a temporary directory
|
||||
// to satisfy these requirements.
|
||||
root := filepath.Join(c.root, "criu-root")
|
||||
if err := os.Mkdir(root, 0o755); err != nil {
|
||||
if err := os.Mkdir(root, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(root)
|
||||
@ -1350,7 +1352,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unix.Unmount(root, unix.MNT_DETACH) //nolint: errcheck
|
||||
defer unix.Unmount(root, unix.MNT_DETACH)
|
||||
t := criurpc.CriuReqType_RESTORE
|
||||
req := &criurpc.CriuReq{
|
||||
Type: &t,
|
||||
@ -1375,15 +1377,6 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
|
||||
},
|
||||
}
|
||||
|
||||
if criuOpts.LsmProfile != "" {
|
||||
// CRIU older than 3.16 has a bug which breaks the possibility
|
||||
// to set a different LSM profile.
|
||||
if err := c.checkCriuVersion(31600); err != nil {
|
||||
return errors.New("--lsm-profile requires at least CRIU 3.16")
|
||||
}
|
||||
req.Opts.LsmProfile = proto.String(criuOpts.LsmProfile)
|
||||
}
|
||||
|
||||
c.handleCriuConfigurationFile(req.Opts)
|
||||
|
||||
if err := c.handleRestoringNamespaces(req.Opts, &extraFiles); err != nil {
|
||||
@ -1672,7 +1665,7 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
|
||||
break
|
||||
}
|
||||
|
||||
_ = criuClientCon.CloseWrite()
|
||||
criuClientCon.CloseWrite()
|
||||
// cmd.Wait() waits cmd.goroutines which are used for proxying file descriptors.
|
||||
// Here we want to wait only the CRIU process.
|
||||
criuProcessState, err = criuProcess.Wait()
|
||||
|
1
vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go
generated
vendored
1
vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go
generated
vendored
@ -29,5 +29,4 @@ type CriuOpts struct {
|
||||
AutoDedup bool // auto deduplication for incremental dumps
|
||||
LazyPages bool // restore memory pages lazily using userfaultfd
|
||||
StatusFd int // fd for feedback when lazy server is ready
|
||||
LsmProfile string // LSM profile used to restore the container
|
||||
}
|
||||
|
11
vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go
generated
vendored
11
vendor/github.com/opencontainers/runc/libcontainer/devices/device_unix.go
generated
vendored
@ -11,8 +11,10 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// ErrNotADevice denotes that a file is not a valid linux device.
|
||||
var ErrNotADevice = errors.New("not a device node")
|
||||
var (
|
||||
// ErrNotADevice denotes that a file is not a valid linux device.
|
||||
ErrNotADevice = errors.New("not a device node")
|
||||
)
|
||||
|
||||
// Testing dependencies
|
||||
var (
|
||||
@ -27,9 +29,8 @@ func mkDev(d *Rule) (uint64, error) {
|
||||
return unix.Mkdev(uint32(d.Major), uint32(d.Minor)), nil
|
||||
}
|
||||
|
||||
// DeviceFromPath takes the path to a device and its cgroup_permissions (which
|
||||
// cannot be easily queried) to look up the information about a linux device
|
||||
// and returns that information as a Device struct.
|
||||
// Given the path to a device and its cgroup_permissions(which cannot be easily queried) look up the
|
||||
// information about a linux device and return that information as a Device struct.
|
||||
func DeviceFromPath(path, permissions string) (*Device, error) {
|
||||
var stat unix.Stat_t
|
||||
err := unixLstat(path, &stat)
|
||||
|
8
vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go
generated
vendored
8
vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go
generated
vendored
@ -196,11 +196,7 @@ func New(root string, options ...func(*LinuxFactory) error) (Factory, error) {
|
||||
Validator: validate.New(),
|
||||
CriuPath: "criu",
|
||||
}
|
||||
|
||||
if err := Cgroupfs(l); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Cgroupfs(l)
|
||||
for _, opt := range options {
|
||||
if opt == nil {
|
||||
continue
|
||||
@ -291,7 +287,7 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
|
||||
if l.Root == "" {
|
||||
return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid)
|
||||
}
|
||||
// when load, we need to check id is valid or not.
|
||||
//when load, we need to check id is valid or not.
|
||||
if err := l.validateID(id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
14
vendor/github.com/opencontainers/runc/libcontainer/init_linux.go
generated
vendored
14
vendor/github.com/opencontainers/runc/libcontainer/init_linux.go
generated
vendored
@ -112,19 +112,9 @@ func populateProcessEnvironment(env []string) error {
|
||||
for _, pair := range env {
|
||||
p := strings.SplitN(pair, "=", 2)
|
||||
if len(p) < 2 {
|
||||
return fmt.Errorf("invalid environment variable: %q", pair)
|
||||
return fmt.Errorf("invalid environment '%v'", pair)
|
||||
}
|
||||
name, val := p[0], p[1]
|
||||
if name == "" {
|
||||
return fmt.Errorf("environment variable name can't be empty: %q", pair)
|
||||
}
|
||||
if strings.IndexByte(name, 0) >= 0 {
|
||||
return fmt.Errorf("environment variable name can't contain null(\\x00): %q", pair)
|
||||
}
|
||||
if strings.IndexByte(val, 0) >= 0 {
|
||||
return fmt.Errorf("environment variable value can't contain null(\\x00): %q", pair)
|
||||
}
|
||||
if err := os.Setenv(name, val); err != nil {
|
||||
if err := os.Setenv(p[0], p[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
4
vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go
generated
vendored
4
vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go
generated
vendored
@ -1,6 +1,8 @@
|
||||
package intelrdt
|
||||
|
||||
var cmtEnabled bool
|
||||
var (
|
||||
cmtEnabled bool
|
||||
)
|
||||
|
||||
// Check if Intel RDT/CMT is enabled.
|
||||
func IsCMTEnabled() bool {
|
||||
|
6
vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go
generated
vendored
6
vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go
generated
vendored
@ -2,8 +2,10 @@
|
||||
|
||||
package intelrdt
|
||||
|
||||
// The flag to indicate if Intel RDT/MBM is enabled
|
||||
var mbmEnabled bool
|
||||
var (
|
||||
// The flag to indicate if Intel RDT/MBM is enabled
|
||||
mbmEnabled bool
|
||||
)
|
||||
|
||||
// Check if Intel RDT/MBM is enabled.
|
||||
func IsMBMEnabled() bool {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user