From 117131c41b022b8529577337b1a602917a7701d2 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Wed, 15 Jun 2016 13:07:52 -0700 Subject: [PATCH] Gracefully handle missing xfrm modules If xfrm modules cannot be loaded: - Create netlink.Handle only for ROUTE socket - Reject local join on overlay secure network Signed-off-by: Alessandro Boch --- libnetwork/drivers/overlay/joinleave.go | 9 +++++++-- libnetwork/drivers/overlay/ov_network.go | 2 +- libnetwork/drivers/overlay/ov_utils.go | 3 ++- libnetwork/ns/init_linux.go | 24 +++++++++++++++++++++++- libnetwork/osl/namespace_linux.go | 6 ++---- libnetwork/osl/sandbox_linux_test.go | 2 +- 6 files changed, 36 insertions(+), 10 deletions(-) diff --git a/libnetwork/drivers/overlay/joinleave.go b/libnetwork/drivers/overlay/joinleave.go index 8cdf3194de..1f21ee9b0d 100644 --- a/libnetwork/drivers/overlay/joinleave.go +++ b/libnetwork/drivers/overlay/joinleave.go @@ -3,6 +3,7 @@ package overlay import ( "fmt" "net" + "syscall" log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/driverapi" @@ -31,6 +32,12 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, return fmt.Errorf("cannot join secure network: encryption keys not present") } + nlh := ns.NlHandle() + + if n.secure && !nlh.SupportsNetlinkFamily(syscall.NETLINK_XFRM) { + return fmt.Errorf("cannot join secure network: required modules to install IPSEC rules are missing on host") + } + s := n.getSubnetforIP(ep.addr) if s == nil { return fmt.Errorf("could not find subnet for endpoint %s", eid) @@ -65,8 +72,6 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, return fmt.Errorf("failed to update overlay endpoint %s to local data store: %v", ep.id[0:7], err) } - nlh := ns.NlHandle() - // Set the container interface and its peer MTU to 1450 to allow // for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) + // outer UDP(8) + vxlan header(8)) diff --git a/libnetwork/drivers/overlay/ov_network.go b/libnetwork/drivers/overlay/ov_network.go index 7edb5077c5..cc2f0879a0 100644 --- a/libnetwork/drivers/overlay/ov_network.go +++ b/libnetwork/drivers/overlay/ov_network.go @@ -284,7 +284,7 @@ func populateVNITbl() { } defer ns.Close() - nlh, err := netlink.NewHandleAt(ns) + nlh, err := netlink.NewHandleAt(ns, syscall.NETLINK_ROUTE) if err != nil { logrus.Errorf("Could not open netlink handle during vni population for ns %s: %v", path, err) return nil diff --git a/libnetwork/drivers/overlay/ov_utils.go b/libnetwork/drivers/overlay/ov_utils.go index f9f32dec48..f49c5d4e5f 100644 --- a/libnetwork/drivers/overlay/ov_utils.go +++ b/libnetwork/drivers/overlay/ov_utils.go @@ -3,6 +3,7 @@ package overlay import ( "fmt" "strings" + "syscall" "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/netutils" @@ -128,7 +129,7 @@ func deleteVxlanByVNI(path string, vni uint32) error { } defer ns.Close() - nlh, err = netlink.NewHandleAt(ns) + nlh, err = netlink.NewHandleAt(ns, syscall.NETLINK_ROUTE) if err != nil { return fmt.Errorf("failed to get netlink handle for ns %s: %v", path, err) } diff --git a/libnetwork/ns/init_linux.go b/libnetwork/ns/init_linux.go index ea0cfc0593..78529c7fbe 100644 --- a/libnetwork/ns/init_linux.go +++ b/libnetwork/ns/init_linux.go @@ -3,6 +3,8 @@ package ns import ( "fmt" "os" + "os/exec" + "strings" "sync" "syscall" @@ -24,7 +26,7 @@ func Init() { if err != nil { log.Errorf("could not get initial namespace: %v", err) } - initNl, err = netlink.NewHandle() + initNl, err = netlink.NewHandle(getSupportedNlFamilies()...) if err != nil { log.Errorf("could not create netlink handle on initial namespace: %v", err) } @@ -32,6 +34,7 @@ func Init() { // SetNamespace sets the initial namespace handler func SetNamespace() error { + initOnce.Do(Init) if err := netns.Set(initNs); err != nil { linkInfo, linkErr := getLink() if linkErr != nil { @@ -62,3 +65,22 @@ func NlHandle() *netlink.Handle { initOnce.Do(Init) return initNl } + +func getSupportedNlFamilies() []int { + fams := []int{syscall.NETLINK_ROUTE} + if err := loadXfrmModules(); err != nil { + log.Warnf("Could not load necessary modules for IPSEC rules: %v", err) + return fams + } + return append(fams, syscall.NETLINK_XFRM) +} + +func loadXfrmModules() error { + if out, err := exec.Command("modprobe", "-va", "xfrm_user").CombinedOutput(); err != nil { + return fmt.Errorf("Running modprobe xfrm_user failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err) + } + if out, err := exec.Command("modprobe", "-va", "xfrm_algo").CombinedOutput(); err != nil { + return fmt.Errorf("Running modprobe xfrm_algo failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err) + } + return nil +} diff --git a/libnetwork/osl/namespace_linux.go b/libnetwork/osl/namespace_linux.go index b9a0201e16..3dad60472a 100644 --- a/libnetwork/osl/namespace_linux.go +++ b/libnetwork/osl/namespace_linux.go @@ -30,7 +30,6 @@ var ( gpmWg sync.WaitGroup gpmCleanupPeriod = 60 * time.Second gpmChan = make(chan chan struct{}) - nsOnce sync.Once ) // The networkNamespace type is the linux implementation of the Sandbox @@ -196,7 +195,7 @@ func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) { } defer sboxNs.Close() - n.nlHandle, err = netlink.NewHandleAt(sboxNs) + n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE) if err != nil { return nil, fmt.Errorf("failed to create a netlink handle: %v", err) } @@ -238,7 +237,7 @@ func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) { } defer sboxNs.Close() - n.nlHandle, err = netlink.NewHandleAt(sboxNs) + n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE) if err != nil { return nil, fmt.Errorf("failed to create a netlink handle: %v", err) } @@ -326,7 +325,6 @@ func (n *networkNamespace) InvokeFunc(f func()) error { // InitOSContext initializes OS context while configuring network resources func InitOSContext() func() { - nsOnce.Do(ns.Init) runtime.LockOSThread() if err := ns.SetNamespace(); err != nil { log.Error(err) diff --git a/libnetwork/osl/sandbox_linux_test.go b/libnetwork/osl/sandbox_linux_test.go index 1c5373e134..b76377806e 100644 --- a/libnetwork/osl/sandbox_linux_test.go +++ b/libnetwork/osl/sandbox_linux_test.go @@ -197,7 +197,7 @@ func TestDisableIPv6DAD(t *testing.T) { LinkAttrs: netlink.LinkAttrs{Name: "sideA"}, PeerName: "sideB", } - nlh, err := netlink.NewHandle() + nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE) if err != nil { t.Fatal(err) }