Apply net-related sysctls when configuring host network.

This is needed to support things like ipv6, which are configured by sysctls
passed to Docker.

PiperOrigin-RevId: 523138695
This commit is contained in:
Nicolas Lacasse
2023-04-10 09:49:09 -07:00
committed by gVisor bot
parent dadab01167
commit ef03c57c55
4 changed files with 50 additions and 11 deletions
+4
View File
@@ -105,6 +105,9 @@ type RunOpts struct {
// Links is the list of containers to be connected to the container.
Links []string
// Sysctls is the list of Namespaced sysctls used for the container.
Sysctls map[string]string
}
func makeContainer(ctx context.Context, logger testutil.Logger, runtime string) *Container {
@@ -275,6 +278,7 @@ func (c *Container) hostConfig(r RunOpts) *container.HostConfig {
Privileged: r.Privileged,
ReadonlyRootfs: r.ReadOnly,
NetworkMode: container.NetworkMode(r.NetworkMode),
Sysctls: r.Sysctls,
Resources: container.Resources{
Memory: int64(r.Memory), // In bytes.
CpusetCpus: r.CpusetCpus,
+5
View File
@@ -647,6 +647,11 @@ func (l *Loader) run() error {
// Delay host network configuration to this point because network namespace
// is configured after the loader is created and before Run() is called.
log.Debugf("Configuring host network")
// Apply any net-related sysctls to the host kernel in our
// network namespace now.
specutils.ApplySysctls(l.root.spec, "net.")
s := l.k.RootNetworkNamespace().Stack().(*hostinet.Stack)
if err := s.Configure(l.root.conf.EnableRaw); err != nil {
return err
+21
View File
@@ -698,3 +698,24 @@ func ResolveEnvs(envs ...[]string) ([]string, error) {
func FaqErrorMsg(anchor, msg string) string {
return fmt.Sprintf("%s; see https://gvisor.dev/faq#%s for more details", msg, anchor)
}
// ApplySysctls applies the sysctls from the spec with the given prefix to the
// host kernel. Falures are not fatal, but a warning is logged.
func ApplySysctls(spec *specs.Spec, prefix string) {
if spec.Linux == nil {
return
}
for k, v := range spec.Linux.Sysctl {
if !strings.HasPrefix(k, prefix) {
continue
}
// Turn the sysctl name into corresponding proc file. We will
// write to the proc file directly, rather than rely on the
// sysctl binary which might not exist in our filesystem
pFile := path.Join("/proc/sys", strings.ReplaceAll(k, ".", "/"))
log.Infof("Applying sysctl name=%q value=%q", k, v)
if err := os.WriteFile(pFile, []byte(v), 0644); err != nil {
log.Warningf("Failed to set sysctl name=%q (%s) value=%q: %v", k, pFile, v, err)
}
}
}
+20 -11
View File
@@ -510,18 +510,27 @@ func TestPing4Loopback(t *testing.T) {
// This test ensures we can enable ipv6 on loopback and run ping6 without
// errors.
func TestPing6Loopback(t *testing.T) {
if testutil.IsRunningWithHostNet() {
// TODO(gvisor.dev/issue/5011): support ICMP sockets in hostnet and enable
// this test.
t.Skip("hostnet only supports TCP/UDP sockets, so ping6 is not supported.")
}
// We must set sysctl net.ipv6.conf.all.disable_ipv6=0 to enable ipv6
// inside Docker. Sometimes that's still not enough to get the loopback
// device, so the test tries to add it with 'ip' tool, requiring
// CAP_NET_ADMIN.
ctx := context.Background()
d := dockerutil.MakeContainer(ctx, t)
defer d.CleanUp(ctx)
// The CAP_NET_ADMIN capability is required to use the `ip` utility, which
// we use to enable ipv6 on loopback.
//
// By default, ipv6 loopback is not enabled by runsc, because docker does
// not assign an ipv6 address to the test container.
runIntegrationTest(t, []string{"NET_ADMIN"}, "./ping6.sh")
opts := dockerutil.RunOpts{
Image: "basic/integrationtest",
WorkDir: "/root",
CapAdd: []string{"NET_ADMIN"},
Sysctls: map[string]string{
"net.ipv6.conf.all.disable_ipv6": "0",
},
}
if got, err := d.Run(ctx, opts, "./ping6.sh"); err != nil {
t.Fatalf("docker run failed: %v", err)
} else if got != "" {
t.Errorf("test failed:\n%s", got)
}
}
// This test checks that the owner of the sticky directory can delete files