Merge pull request #968 from aboch/ed6
Control IPv6 on container's interface
This commit is contained in:
commit
176088a742
5 changed files with 149 additions and 11 deletions
|
@ -130,6 +130,7 @@ func TestTCP4Proxy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTCP6Proxy(t *testing.T) {
|
||||
t.Skip("Need to start CI docker with --ipv6")
|
||||
backend := NewEchoServer(t, "tcp", "[::1]:0")
|
||||
defer backend.Close()
|
||||
backend.Run()
|
||||
|
@ -173,6 +174,7 @@ func TestUDP4Proxy(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUDP6Proxy(t *testing.T) {
|
||||
t.Skip("Need to start CI docker with --ipv6")
|
||||
backend := NewEchoServer(t, "udp", "[::1]:0")
|
||||
defer backend.Close()
|
||||
backend.Run()
|
||||
|
|
|
@ -3,6 +3,7 @@ package networkdb
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
|
@ -21,6 +22,7 @@ var (
|
|||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
ioutil.WriteFile("/proc/sys/net/ipv6/conf/lo/disable_ipv6", []byte{'0', '\n'}, 0644)
|
||||
logrus.SetLevel(logrus.ErrorLevel)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
|
|
@ -179,6 +179,8 @@ func (i *nwIface) Remove() error {
|
|||
}
|
||||
n.Unlock()
|
||||
|
||||
n.checkLoV6()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -318,6 +320,8 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
|
|||
n.iFaces = append(n.iFaces, i)
|
||||
n.Unlock()
|
||||
|
||||
n.checkLoV6()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -378,6 +382,9 @@ func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error
|
|||
if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setIPv6(i.ns.path, i.DstName(), true); err != nil {
|
||||
return fmt.Errorf("failed to enable ipv6: %v", err)
|
||||
}
|
||||
ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
|
||||
return nlh.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@ import (
|
|||
|
||||
const defaultPrefix = "/var/run/docker"
|
||||
|
||||
func init() {
|
||||
reexec.Register("set-ipv6", reexecSetIPv6)
|
||||
}
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
garbagePathMap = make(map[string]bool)
|
||||
|
@ -47,6 +51,7 @@ type networkNamespace struct {
|
|||
nextIfIndex int
|
||||
isDefault bool
|
||||
nlHandle *netlink.Handle
|
||||
loV6Enabled bool
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -216,6 +221,12 @@ func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
|
|||
logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
|
||||
}
|
||||
|
||||
// As starting point, disable IPv6 on all interfaces
|
||||
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)
|
||||
}
|
||||
|
||||
if err = n.loopbackUp(); err != nil {
|
||||
n.nlHandle.Delete()
|
||||
return nil, err
|
||||
|
@ -263,6 +274,12 @@ func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
|
|||
logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
|
||||
}
|
||||
|
||||
// As starting point, disable IPv6 on all interfaces
|
||||
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)
|
||||
}
|
||||
|
||||
if err = n.loopbackUp(); err != nil {
|
||||
n.nlHandle.Delete()
|
||||
return nil, err
|
||||
|
@ -508,3 +525,84 @@ func (n *networkNamespace) Restore(ifsopt map[string][]IfaceOption, routes []*ty
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks whether IPv6 needs to be enabled/disabled on the loopback interface
|
||||
func (n *networkNamespace) checkLoV6() {
|
||||
var (
|
||||
enable = false
|
||||
action = "disable"
|
||||
)
|
||||
|
||||
n.Lock()
|
||||
for _, iface := range n.iFaces {
|
||||
if iface.AddressIPv6() != nil {
|
||||
enable = true
|
||||
action = "enable"
|
||||
break
|
||||
}
|
||||
}
|
||||
n.Unlock()
|
||||
|
||||
if n.loV6Enabled == enable {
|
||||
return
|
||||
}
|
||||
|
||||
if err := setIPv6(n.path, "lo", enable); err != nil {
|
||||
logrus.Warnf("Failed to %s IPv6 on loopback interface on network namespace %q: %v", action, n.path, err)
|
||||
}
|
||||
|
||||
n.loV6Enabled = enable
|
||||
}
|
||||
|
||||
func reexecSetIPv6() {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if len(os.Args) < 3 {
|
||||
logrus.Errorf("invalid number of arguments for %s", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
ns, err := netns.GetFromPath(os.Args[1])
|
||||
if err != nil {
|
||||
logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err)
|
||||
os.Exit(2)
|
||||
}
|
||||
defer ns.Close()
|
||||
|
||||
if err = netns.Set(ns); err != nil {
|
||||
logrus.Errorf("setting into container netns %q failed: %v", os.Args[1], err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
var (
|
||||
action = "disable"
|
||||
value = byte('1')
|
||||
path = fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", os.Args[2])
|
||||
)
|
||||
|
||||
if os.Args[3] == "true" {
|
||||
action = "enable"
|
||||
value = byte('0')
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(path, []byte{value, '\n'}, 0644); err != nil {
|
||||
logrus.Errorf("failed to %s IPv6 forwarding for container's interface %s: %v", action, os.Args[2], err)
|
||||
os.Exit(4)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func setIPv6(path, iface string, enable bool) error {
|
||||
cmd := &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: append([]string{"set-ipv6"}, path, iface, strconv.FormatBool(enable)),
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
return fmt.Errorf("reexec to set IPv6 failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
@ -190,17 +191,32 @@ func TestDisableIPv6DAD(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
|
||||
|
||||
ipv6, _ := types.ParseCIDR("2001:db8::44/64")
|
||||
iface := &nwIface{addressIPv6: ipv6}
|
||||
iface := &nwIface{addressIPv6: ipv6, ns: n, dstName: "sideA"}
|
||||
|
||||
veth := &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: "sideA"},
|
||||
PeerName: "sideB",
|
||||
}
|
||||
nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = nlh.LinkAdd(veth)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -229,14 +245,27 @@ func TestDisableIPv6DAD(t *testing.T) {
|
|||
func TestSetInterfaceIP(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}
|
||||
|
||||
nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
iface := &nwIface{address: ipv4, addressIPv6: ipv6, ns: n, dstName: "sideA"}
|
||||
|
||||
if err := nlh.LinkAdd(&netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: "sideA"},
|
||||
|
|
Loading…
Add table
Reference in a new issue