Commit Graph

109 Commits

Author SHA1 Message Date
Kir Kolyshkin dbb9fc03ae libct/*: remove linux build tag from some pkgs
Only some libcontainer packages can be built on non-linux platforms
(not that it make sense, but at least go build succeeds). Let's call
these "good" packages.

For all other packages (i.e. ones that fail to build with GOOS other
than linux), it does not make sense to have linux build tag (as they
are broken already, and thus are not and can not be used on anything
other than Linux).

Remove linux build tag for all non-"good" packages.

This was mostly done by the following script, with just a few manual
fixes on top.

function list_good_pkgs() {
	for pkg in $(find . -type d -print); do
		GOOS=freebsd go build $pkg 2>/dev/null \
		&& GOOS=solaris go build $pkg 2>/dev/null \
		&& echo $pkg
	done | sed -e 's|^./||' | tr '\n' '|' | sed -e 's/|$//'
}

function remove_tag() {
	sed -i -e '\|^// +build linux$|d' $1
	go fmt $1
}

SKIP="^("$(list_good_pkgs)")"
for f in $(git ls-files . | grep .go$); do
	if echo $f | grep -qE "$SKIP"; then
		echo skip $f
		continue
	fi
	echo proc $f
	remove_tag $f
done

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-30 20:52:07 -07:00
Kir Kolyshkin 3c7db3827c Merge pull request #2883 from flouthoc/master
Add support for rdma cgroup introduced in Linux Kernel 4.11
2021-08-30 20:02:04 -07:00
flouthoc b3d14488b5 Add support for rdma cgroup introduced in Linux Kernel 4.11
Signed-off-by: Aditya Rajan <flouthoc.git@gmail.com>
2021-08-23 12:25:33 +05:30
Kir Kolyshkin 1cbfe23464 libct/cg: rm dead code
This was initially added by commits 41d9d26513 and 4a8f0b4db4,
apparently to implement docker run --cgroup container:ID, which was
never merged. Therefore, this code is not and was never used.

It needs to be removed mainly because having it makes it much harder to
understand how cgroup manager works (because with this in place we have
not one or two but three sets of cgroup paths to think about).

Note if the paths are known and there is a need to add a PID to existing
cgroup, cgroup manager is not needed at all -- something like
cgroups.WriteCgroupProc or cgroups.EnterPid is sufficient (and the
latter is what runc exec uses in (*setnsProcess).start).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-08 13:03:51 -07:00
Kir Kolyshkin a91ce3062f libct/*_test.go: use t.TempDir
Replace ioutil.TempDir (mostly) with t.TempDir, which require no
explicit cleanup.

While at it, fix incorrect usage of os.ModePerm in libcontainer/intelrdt
test. This is supposed to be a mask, not mode bits.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 01:41:47 -07:00
Kir Kolyshkin b60e2edf75 libct/cg: stop using pkg/errors
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-22 16:09:47 -07:00
Kir Kolyshkin 825335b2b7 libct/cg/fs2: fix/unify parsing errors
This builds on top of recently introduced fscommon.ParseError.

Errors returned from parsers (mostly ones used by GetStats()) are all
different, and many are incomplete. For example, in many cases errors
from strconv.ParseUint are returned as is, meaning there is no context
telling which file we were reading. Similarly, errors from
fscommon.ParseKeyValue should be wrapped to add more context.
Same is true for scanner.Err().

OTOH, errors from fscommon.GetCgroup* do have enough context and there
is no need to wrap them.

Fix all the above.

While at it, add missing scanner.Err() checks.

[v2: use parseError, not ParseError]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-22 12:00:54 -07:00
Kir Kolyshkin adcd3b4451 libct/cg/fs[2]: simplify getting pid stats
1. Do not wrap errors returned from fscommon.GetCgroupParamUint -- those
   errors already have enough context.

2. Instead of parsing "max" ourselves, use GetCgroupParamUint which does
   it, and then convert MaxUint64 to 0 (we do it historically since
   commit 087b953dc5, and while using MaxUint64 as is seems fine,
   there may be some existing users who rely on the old behavior).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-22 11:44:31 -07:00
Kir Kolyshkin 1036f3f995 libct/cg/fs2: set per-device io weight if available
Per-device weight is supported since kernel v5.4 (kernel commit
795fe54c2a8), so let's set those if supplied.

[v2: implement a more relaxed check in bfqDeviceWeightSupported]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-16 04:51:19 -07:00
Kir Kolyshkin d7fc302860 libct/cg/fs*: mark {Open,Read,Write}File as deprecated
... and switch to using the ones from cgroups.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-13 17:17:48 -07:00
Kir Kolyshkin 8f1b4d4a6f libct/cg: mv fscommon.{Open,Read,Write}File to cgroups
This is a better place as cgroups itself is using these.
Should help with moving more stuff common in between fs and fs2 to
fscommon.

Looks big, but this is just moving the code around:

 fscommon/{fscommon,open}.go -> cgroups/file.go
 fscommon/fscommon_test.go   -> cgroups/file_test.go

and fixes for TestMode moved to a different package.

There's no functional change.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-13 12:38:21 -07:00
Kir Kolyshkin e6048715e4 Use gofumpt to format code
gofumpt (mvdan.cc/gofumpt) is a fork of gofmt with stricter rules.

Brought to you by

	git ls-files \*.go | grep -v ^vendor/ | xargs gofumpt -s -w

Looking at the diff, all these changes make sense.

Also, replace gofmt with gofumpt in golangci.yml.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-01 12:17:27 -07:00
Aleksa Sarai 1eea9253a1 cgroup2: io: add io.stats parsing test
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-06-01 10:47:39 +10:00
Aleksa Sarai 0fef122f87 cgroup2: io: handle 64-bit values correctly on 32-bit architectures
strconv.ParseUint(..., 0) is not really safe, because on 32-bit
architectures it will trigger runtime errors when trying to parse large
numbers (which in the case of the cgroupv2 io controller, is almost
certainly going to happen).

Fixes: 1932917b71 ("libcontainer: add initial support for cgroups v2")
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-06-01 10:35:09 +10:00
Aleksa Sarai efca32c799 cgroup2: io: map io.stats to v1 blkio.stats correctly
Kubelet and cAdvisor depend on the metrics having the same values as in
cgroupv1, but we didn't correctly map the number of read and write IOs
to the correct cgroupv1 stats table (blkio.io_serviced).

In addition, don't leak any extra stats in our output -- if users need
that information we can always add a new field for it.

Reported-by: Yashpal Choudhary <yashpal.c1995@gmail.com>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-06-01 10:35:03 +10:00
Yashpal Choudhary 49d293a56d cgroup2: capitalize io stats read and write Op values
Signed-off-by: Yashpal Choudhary <yashpal.c1995@gmail.com>
2021-05-27 03:32:01 +05:30
Aleksa Sarai d0f2c25f52 cgroup2: devices: replace all existing filters when attaching
In the normal cases (only one existing filter or no existing filters),
just make use of BPF_F_REPLACE if there is one existing filter. However
if there is more than one filter applied, we should probably remove all
other filters since the alternative is that we will never remove our old
filters.

The only two other viable ways of solving this problem would be to use
BPF pins to either pin the eBPF program using a predictable name (so we
can always only replace *our* programs) or to switch away from custom
programs and instead use eBPF maps (which are pinned) and thus we just
update the map conntents to update the ruleset. Unfortunately these both
would add a hard requirement of bpffs and would require at least a minor
rewrite of the eBPF filtering code -- which is better left for another
time.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-05-23 17:55:19 +10:00
Aleksa Sarai 98a3c0e4db cgroup2: devices: switch to emulator for cgroupv1 parity
There were several issues with the previous cgroupv2 devices filter
generator implementation, stemming from the previous implementation
using a few too many tricks to implement the correct cgroup behaviour
(rules were handled in reverse order, with wildcards having particularly
special interpretations). As a result, some slightly odd configurations
with rules in specific orders could result in incorrect filters being
generated.

By switching to the emulator which is already used by cgroupv1, we can
guarantee that the behaviour of filters in both cgroup versions will be
identical, as well as making use of the hardenings in the emulator (not
allowing users to add deny rules the kernel will ignore).

(Note that because the ordering of the devices emulator rules is
deterministic and based on the rule value, the existing test rules had
to be reordered slightly.)

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-05-23 17:55:15 +10:00
Kir Kolyshkin b93666ebc1 libct/cg/fs2: setFreezer: wait until frozen
According to cgroup v2 documentation [1]:

> Freezing of the cgroup may take some time; when this action is
> completed, the “frozen” value in the cgroup.events control file will
> be updated to “1” and the corresponding notification will be issued.

Implement polling of cgroup.events, waiting for "frozen 1" to appear.
In case something goes wrong, limit the maximum number of retries and
return "undefined" after some time (currently 10s).

[1] https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-05-19 12:15:24 -07:00
Kir Kolyshkin 1069e4e9da libct/cg/fs2: optimize setFreezer more
Before this patch, setFreezer does

- open/read/close (to check if the freezer is supported)
- open/write/close (to set the value)
- open/read/close (to check the value)

Three opens is a bit excessive. Refactor to only open the file once:

- open (to check if the freezer is supported)
- write (to set the value)
- seek/read (to check the value)
- close

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-05-19 12:10:56 -07:00
Kir Kolyshkin 5d193188db libct/cg/fs2: optimize setFreezer
In case configs.Undefined or any wrong value is passed, there is no need
to check whether the freezer is supported.

Move arguments check to the beginning to avoid an unnecessary call to
supportFreezer().

While at it, simplify the "whether to return an error if freezer is not
supported" check.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-05-19 12:10:56 -07:00
Kir Kolyshkin 3f65946756 libct/cg: make Set accept configs.Resources
A cgroup manager's Set method sets cgroup resources, but historically
it was accepting configs.Cgroups.

Refactor it to accept resources only. This is an improvement from the
API point of view, as the method can not change cgroup configuration
(such as path to the cgroup etc), it can only set (modify) its
resources/limits.

This also lays the foundation for complicated resource updates, as now
Set has two sets of resources -- the one that was previously specified
during cgroup manager creation (or the previous Set), and the one passed
in the argument, so it could deduce the difference between these. This
is a long term goal though.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-29 15:24:19 -07:00
Akihiro Suda ba257d2de8 Merge pull request #2873 from kolyshkin/mem-root-cgroup2
libct/cg/fs2.GetStats() improvements
2021-04-19 13:59:14 +09:00
Odin Ugedal ee3b563de7 Add cfs throttle stats to cgroup v2
Signed-off-by: Odin Ugedal <odin@uged.al>
2021-04-16 13:41:22 +02:00
Kir Kolyshkin ef9922c26c libct/cg: don't return OOMKillCount error when rootless
Commit 5d0ffbf9c8 added OOM kill count checking and better container
start/run/exec error reporting in case we hit OOM.

It also introduced warnings like these:

> level=warning msg="unable to get oom kill count" error="openat2
> /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/test_hello/memory.events:
> no such file or directory"

In case of rootless containers, unless cgroup is delegated or systemd is
used, runc can not create a cgroup and thus it fails to get OOM kill
count. This is expected, and the warning should not be shown in this
case.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-14 17:57:00 -07:00
Kir Kolyshkin 5cdd9022a9 libct/cg/fs[2]: fix comments about m.rootless
For fs, commit fc620fdf81 made rootless field private,
and for fs2, it was always private, and yet comments in both
mention it as m.Rootless.

Fix it.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-14 17:44:22 -07:00
Sebastiaan van Stijn 4316df8b53 libcontainer/system: move userns utilities to separate package
Moving these utilities to a separate package, so that consumers of this
package don't have to pull in the whole "system" package.

Looking at uses of these utilities (outside of runc itself);

`RunningInUserNS()` is used by [various external consumers][1],
so adding a "Deprecated" alias for this.

[1]: https://grep.app/search?current=2&q=.RunningInUserNS

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-04 22:42:03 +02:00
Kir Kolyshkin 0f8d2b6bed libct/cg/fs2.Stat: don't look for available controllers
Some controllers might still have stats available even if they are
disabled (this is definitely so for cpu.stat -- see earlier commit).

Some stat methods might implement sensible fallbacks (see previous
commit for statPids.

In the view of all that, it makes sense to not check if a particular
controller is available, but rather ignore ENOENT from it.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 12:16:14 -07:00
Kir Kolyshkin 85416b8742 libct/cg/fs2.statPids: fall back directly
When getting pids stats, instead of checking whether the pids controller
is available, let's use a fall back function in case pids.current does
not exist. This simplifies the logic in fs2.GetStats.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 12:03:12 -07:00
Kir Kolyshkin 10f9a982ac libct/cg/fs2/getPidsWithoutController: optimize
It is inefficient to create an associative map for the whole purpose of
counting the number of elements in it, especially if the elements are
all unique. It uses more CPU than necessary and creates some work for
the garbage collector.

The file we read contains PIDs and newlines, and the easiest/fastest way
to get the number of PIDs is just to count the newlines.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 11:55:07 -07:00
Kir Kolyshkin 6121f8b69f libct/cg/fs2.Stat: always call statCpu
Giuseppe found out that cpu.stat for a cgroup is available even if
the cpu controller is not enabled for it. So, let's call statCpu
regradress, and ignore ENOENT.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 11:40:28 -07:00
Kir Kolyshkin 9455395b06 libct/cg/fs2/memory.Stat: add usage for root cgroup
There is no memory.{current,max} for the root node in cgroup v2, and
thus stats for "/sys/fs/cgroup" return an error.

The same thing works with cgroup v1 (as there are
memory.{usage,limit}_in_bytes files in the root node).

Emulate stats for /sys/fs/cgroup by getting numbers from
/proc/self/meminfo.

NOTE that both memory.current (in cgroup v2) and memory.usage_in_bytes
(in cgroup v1) include page cache etc into the number, so we do the same
when calculating memory usage (as opposed to number reported by "free",
which excludes page cache and buffers).

[v2: check for cgroup files first, as future kernels might add it]
[v3: don't subtract cache from mem_used, simplifying the logic]

[Initially, I wanted to avoid parsing yet another /proc file and
instead mock some numbers using data from memory.stat but was
unable to come up with formulae that make sense.]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 11:14:49 -07:00
Kir Kolyshkin a9c47fe70f libct/cg/fs[2]/getMemoryData[V2]: optimize
Existing code ignores ENOENT error in case we're reading data from
controls that might not be enabled. While this is correct, the code
can be improved:

1. Check name != "" instead of moduleName != "memory", as these checks
   are equivalent but the new one is faster.

2. It does not make sense to ignore subsequent errors -- if the control
   is not available, we won't hit this codepath.

3. Add a comment explaining why we ignore the error.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 11:14:49 -07:00
Kir Kolyshkin b99ca25ad0 libct/cg/fs2/memory: fix swap reporting
cgroup v1 reports combined mem+swap in stats.MemoryStats.SwapUsage.
In cgroup v2, swap is separate.

For the sake of compatibility, make v2 report mem+swap as well.
This also includes Limit.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 11:14:49 -07:00
Akihiro Suda 5df79d5c3d Merge pull request #2820 from dqminh/io-cgroup2-fallback
fs2: fallback to setting io.weight if io.bfq.weight
2021-03-26 18:58:51 +09:00
Daniel Dao 8c7ece1e6d fs2: fallback to setting io.weight if io.bfq.weight
if bfq is not loaded, then io.bfq.weight is not available. io.weight
should always be available and is the next best equivalent thing.

Signed-off-by: Daniel Dao <dqminh89@gmail.com>
2021-03-05 13:55:36 +00:00
Akihiro Suda d56a9c67ac Merge pull request #2812 from kolyshkin/memory-tight 2021-02-26 10:52:17 +09:00
Aleksa Sarai c153261830 merge branch 'pr-2786'
Daniel Dao (1):
  Do not convert blkio weight value using blkio->io conversion scheme

LGTMs: @kolyshkin @AkihiroSuda @cyphar
Closes #2786
2021-02-24 18:29:27 +11:00
Daniel Dao c3ffd2ef81 Do not convert blkio weight value using blkio->io conversion scheme
bfq weight controller (i.e. io.bfq.weight if present) is still using the
same bfq weight scheme (i.e 1->1000, see [1].) Unfortunately the
documentation for this was wrong, and only fixed recently [2].

Therefore, if we map blkio weight to io.bfq.weight, there's no need to
do any conversion. Otherwise, we will try to write invalid value which
results in error such as:

```
time="2021-02-03T14:55:30Z" level=error msg="container_linux.go:367: starting container process caused: process_linux.go:495: container init caused: process_linux.go:458: setting cgroup config for procHooks process caused: failed to write \"7475\": write /sys/fs/cgroup/runc-cgroups-integration-test/test-cgroup/io.bfq.weight: numerical result out of range"
```

[1] https://github.com/torvalds/linux/blob/master/Documentation/block/bfq-iosched.rst
[2] https://github.com/torvalds/linux/commit/65752aef0a407e1ef17ec78a7fc31ba4e0b360f9

Signed-off-by: Daniel Dao <dqminh89@gmail.com>
2021-02-23 19:46:16 -08:00
Kir Kolyshkin 5d0ffbf9c8 runc start/run: report OOM
In some cases, container init fails to start because it is killed by
the kernel OOM killer. The errors returned by runc in such cases are
semi-random and rather cryptic. Below are a few examples.

On cgroup v1 + systemd cgroup driver:

> process_linux.go:348: copying bootstrap data to pipe caused: write init-p: broken pipe

> process_linux.go:352: getting the final child's pid from pipe caused: EOF

On cgroup v2:

> process_linux.go:495: container init caused: read init-p: connection reset by peer

> process_linux.go:484: writing syncT 'resume' caused: write init-p: broken pipe

This commits adds the OOM method to cgroup managers, which tells whether
the container was OOM-killed. In case that has happened, the original error
is discarded (unless --debug is set), and the new OOM error is reported
instead:

> ERRO[0000] container_linux.go:367: starting container process caused: container init was OOM-killed (memory limit too low?)

Also, fix the rootless test cases that are failing because they expect
an error in the first line, and we have an additional warning now:

> unable to get oom kill count" error="no directory specified for memory.oom_control

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:15:33 -08:00
Kir Kolyshkin 7e137b9044 libct/cg/fs2/hugetlb: use fscommon.GetValueByKey
This makes the code simpler and more future-proof, in case
any more values will appear in hugetlb.*.events.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Kir Kolyshkin 494f900e91 libct/cg/fscommon: rename/facelift GetCgroupParamKeyValue
1. This is the only function in the package with Get prefix
   that does not read a file (but parses a string). Rename
   accordingly, and convert the callers.

	GetCgroupParamKeyValue -> ParseKeyValue

2. Use strings.Split rather than strings.Fields. Split by a space
   is 2x faster, plus we can limit the splitting. The downside is
   we have to strip a newline in one of the callers.

3. Improve the doc and the code flow.

4. Fix a test case with invalid data (spaces at BOL).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Odin Ugedal 6c5ed0db3a Fix memory stats for cache in fs2
In cgroup v2, the "cache" value from cgroup v1 is called "file" in v2.
There are no values called "cache" in v2.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/memcontrol.c?id=31caf8b2a847214be856f843e251fc2ed2cd1075#n1521
Signed-off-by: Odin Ugedal <odin@uged.al>
2021-02-22 12:27:12 +01:00
Aleksa Sarai 2831fb5595 cgroup2: devices: handle eBPF skipping more correctly
In the past we incorrectly handled eBPF errors in two ways:

 1. We would only ignore errors if there was an allow rule in the list
    (this doesn't make sense because for security purposes we only care
    if a *deny* rule is being ignored). Arguably this is a security flaw
    but you would only get an error from bpf(2) in rare cases, and thus
    is not a big enough deal to go through security review.

 2. If we were in a rootless container we would still return an error
    even though bpf(2) is blocked for rootless containers.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-02-05 18:13:06 +11:00
Sebastiaan van Stijn 4fc2de77e9 libcontainer/devices: remove "Device" prefix from types
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-12-01 11:11:23 +01:00
Sebastiaan van Stijn 677baf22d2 libcontainer: isolate libcontainer/devices
Move the Device-related types to libcontainer/devices, so that
the package can be used in isolation. Aliases have been created
in libcontainer/configs for backward compatibility.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2020-12-01 11:11:21 +01:00
Mrunal Patel 10e5ab7966 Merge pull request #2635 from kolyshkin/fscommon-III
libct/cg: introduce and use fscommon.OpenFile
2020-10-22 20:59:56 -07:00
SataQiu abcc1aae05 fix some typos about libcontainer
Signed-off-by: SataQiu <1527062125@qq.com>
2020-10-17 13:14:55 +08:00
Kir Kolyshkin c95e69007c libct/cg/fs*: use fscommon.OpenFile
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2020-10-05 17:08:09 -07:00
Kir Kolyshkin 6bae53f589 libct/cg/fs2: use fscommon.ReadFile
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2020-10-05 14:07:15 -07:00