diff --git a/libnetwork/osl/namespace_linux.go b/libnetwork/osl/namespace_linux.go index 6ddf7f16ad..6389215e1a 100644 --- a/libnetwork/osl/namespace_linux.go +++ b/libnetwork/osl/namespace_linux.go @@ -220,9 +220,11 @@ func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) { if err != nil { logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err) } - + // In live-restore mode, IPV6 entries are getting cleaned up due to below code + // We should retain IPV6 configrations in live-restore mode when Docker Daemon + // comes back. It should work as it is on other cases // As starting point, disable IPv6 on all interfaces - if !n.isDefault { + if !isRestore && !n.isDefault { err = setIPv6(n.path, "all", false) if err != nil { logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err) diff --git a/libnetwork/osl/sandbox_linux_test.go b/libnetwork/osl/sandbox_linux_test.go index 45345aa9f0..dd4284d1fe 100644 --- a/libnetwork/osl/sandbox_linux_test.go +++ b/libnetwork/osl/sandbox_linux_test.go @@ -316,3 +316,95 @@ func TestSetInterfaceIP(t *testing.T) { t.Fatalf("Unexpected error: %v", err) } } + +func TestLiveRestore(t *testing.T) { + + defer testutils.SetupTestOSContext(t)() + + key, err := newKey(t) + if err != nil { + t.Fatalf("Failed to obtain a key: %v", err) + } + + s, err := NewSandbox(key, true, false) + if err != nil { + t.Fatalf("Failed to create a new sandbox: %v", err) + } + runtime.LockOSThread() + defer s.Destroy() + + n, ok := s.(*networkNamespace) + if !ok { + t.Fatal(ok) + } + nlh := n.nlHandle + + ipv4, _ := types.ParseCIDR("172.30.0.33/24") + ipv6, _ := types.ParseCIDR("2001:db8::44/64") + iface := &nwIface{address: ipv4, addressIPv6: ipv6, ns: n, dstName: "sideA"} + + if err := nlh.LinkAdd(&netlink.Veth{ + LinkAttrs: netlink.LinkAttrs{Name: "sideA"}, + PeerName: "sideB", + }); err != nil { + t.Fatal(err) + } + + linkA, err := nlh.LinkByName("sideA") + if err != nil { + t.Fatal(err) + } + + linkB, err := nlh.LinkByName("sideB") + if err != nil { + t.Fatal(err) + } + + if err := nlh.LinkSetUp(linkA); err != nil { + t.Fatal(err) + } + + if err := nlh.LinkSetUp(linkB); err != nil { + t.Fatal(err) + } + + if err := setInterfaceIP(nlh, linkA, iface); err != nil { + t.Fatal(err) + } + + if err := setInterfaceIPv6(nlh, linkA, iface); err != nil { + t.Fatal(err) + } + + err = setInterfaceIP(nlh, linkB, iface) + if err == nil { + t.Fatalf("Expected route conflict error, but succeeded") + } + if !strings.Contains(err.Error(), "conflicts with existing route") { + t.Fatalf("Unexpected error: %v", err) + } + + err = setInterfaceIPv6(nlh, linkB, iface) + if err == nil { + t.Fatalf("Expected route conflict error, but succeeded") + } + if !strings.Contains(err.Error(), "conflicts with existing route") { + t.Fatalf("Unexpected error: %v", err) + } + + // Create newsandbox with Restore - TRUE + s, err = NewSandbox(key, true, true) + if err != nil { + t.Fatalf("Failed to create a new sandbox: %v", err) + } + + // Check if the IPV4 & IPV6 entry present + // If present , we should get error in below call + // It shows us , we don't delete any config in live-restore case + if err := setInterfaceIPv6(nlh, linkA, iface); err == nil { + t.Fatalf("Expected route conflict error, but succeeded for IPV6 ") + } + if err := setInterfaceIP(nlh, linkA, iface); err == nil { + t.Fatalf("Expected route conflict error, but succeeded for IPV4 ") + } +}