net_cls cgroup mounting
Hello,
this code is not working
package main
import (
"github.com/containerd/cgroups/v3/cgroup1"
"github.com/opencontainers/runtime-spec/specs-go"
)
func uint32Ptr(v uint32) *uint32 {
return &v
}
func main() {
netClsController := cgroup1.NewNetCls("/sys/fs/cgroup")
err := netClsController.Create("foobar", &specs.LinuxResources{
Network: &specs.LinuxNetwork{
ClassID: uint32Ptr(0x00100010), //10:10
},
})
if err != nil {
panic(err)
}
}
but I think is equivalent of this:
mkdir /sys/fs/cgroup/net_cls
#mount -t cgroup -onet_cls net_cls /sys/fs/cgroup/net_cls
mkdir /sys/fs/cgroup/net_cls/foobar
echo 0x100010 > /sys/fs/cgroup/net_cls/foobar/net_cls.classid
except mounting part. We need mounting to get net_cls cgroup and to put classid into net_cls.classid.
I could not figure out if the package supports mounting, but if so, then how to force it to do that? If not, then I think it's an issue because Create creates and writes to net_cls.classid file so there is no place to put own mounting code between NewNetCls and Create.
To make Create work, the code should look something like this:
func (n *netclsController) Create(path string, resources *specs.LinuxResources) error {
if err := os.MkdirAll(path, defaultDirPerm); err != nil {
return err
}
if err := syscall.Mount("cgroup", n.root, "cgroup", 0, NetCls); err != nil {
if !errors.Is(err, syscall.EBUSY) { //could be already mounted and it's ok
// some other error
return err
}
}
if resources.Network != nil && resources.Network.ClassID != nil && *resources.Network.ClassID > 0 {
return os.WriteFile(
filepath.Join(n.Path(path), "net_cls.classid"),
[]byte(strconv.FormatUint(uint64(*resources.Network.ClassID), 10)),
defaultFilePerm,
)
}
return nil
}
version: github.com/containerd/cgroups/v3 v3.0.2
Ok, I think I've made a mistake. The project has nothing to do with subsystem management. It's up to me to create a net_cls mounting point first and then create a subgroup`.
if err := os.MkdirAll("/sys/fs/cgroup/net_cls", 0o755); err != nil {
panic(err)
}
err := syscall.Mount("net_cls", "/sys/fs/cgroup/net_cls", "cgroup", 0, "net_cls")
if err != nil {
if !errors.Is(err, syscall.EBUSY) {
panic(err)
}
}
subsystems, err := cgroup1.Default()
if err != nil {
fmt.Println("Default error:", err)
panic(err)
}
for i := range subsystems {
fmt.Println("Subsystem:", subsystems[i].Name())
}
control, err := cgroup1.New(cgroup1.StaticPath("foobar4"),
&specs.LinuxResources{
Network: &specs.LinuxNetwork{
ClassID: uint32Ptr(0x00100010), //10:10
},
},
cgroup1.WithHiearchy(func() ([]cgroup1.Subsystem, error) {
return []cgroup1.Subsystem{cgroup1.NewNetCls("/sys/fs/cgroup")}, nil
}) /* [1] */)
if err := control.AddTask(cgroup1.Process{
Pid: os.Getpid(),
}); err != nil {
panic(err)
}
Having look at [1] and New internals I see that this option has no meaning while you do nothing with opts except checking it's validity inside New function. So, why does New use options? And the second thing. If you try to create sub group in all subsystems it means that my foobar4 will be spread in subsystems where I do not want it to.
Still, I do not catch how to make this simple thing correctly with your code:
mkdir /sys/fs/cgroup/net_cls
mount -t cgroup -onet_cls net_cls /sys/fs/cgroup/net_cls
mkdir /sys/fs/cgroup/net_cls/foobar