Merge pull request #246 from mavenugo/rb

Cherry-picking commits from docker_1.7.0_integ into master
This commit is contained in:
Jana Radhakrishnan
2015-06-02 16:03:49 -07:00
7 changed files with 173 additions and 25 deletions
+16
View File
@@ -3,10 +3,12 @@ package bridge
import (
"errors"
"net"
"os/exec"
"strconv"
"strings"
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/ipallocator"
"github.com/docker/libnetwork/netlabel"
@@ -104,6 +106,12 @@ func newDriver() driverapi.Driver {
// Init registers a new instance of bridge driver
func Init(dc driverapi.DriverCallback) error {
// try to modprobe bridge first
// see gh#12177
if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil {
logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err)
}
return dc.RegisterDriver(networkType, newDriver())
}
@@ -510,6 +518,11 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
// Even if a bridge exists try to setup IPv4.
bridgeSetup.queueStep(setupBridgeIPv4)
enableIPv6Forwarding := false
if d.config != nil && d.config.EnableIPForwarding && config.FixedCIDRv6 != nil {
enableIPv6Forwarding = true
}
// Conditionally queue setup steps depending on configuration values.
for _, step := range []struct {
Condition bool
@@ -533,6 +546,9 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
// specified subnet.
{config.FixedCIDRv6 != nil, setupFixedCIDRv6},
// Enable IPv6 Forwarding
{enableIPv6Forwarding, setupIPv6Forwarding},
// Setup Loopback Adresses Routing
{!config.EnableUserlandProxy, setupLoopbackAdressesRouting},
+13
View File
@@ -1,7 +1,10 @@
package bridge
import (
"os"
log "github.com/Sirupsen/logrus"
"github.com/vishvananda/netlink"
)
func setupFixedCIDRv6(config *networkConfiguration, i *bridgeInterface) error {
@@ -10,5 +13,15 @@ func setupFixedCIDRv6(config *networkConfiguration, i *bridgeInterface) error {
return &FixedCIDRv6Error{Net: config.FixedCIDRv6, Err: err}
}
// Setting route to global IPv6 subnet
log.Debugf("Adding route to IPv6 network %s via device %s", config.FixedCIDRv6.String(), config.BridgeName)
err := netlink.RouteAdd(&netlink.Route{
Scope: netlink.SCOPE_UNIVERSE,
LinkIndex: i.Link.Attrs().Index,
Dst: config.FixedCIDRv6,
})
if err != nil && !os.IsExist(err) {
log.Errorf("Could not add route to IPv6 network %s via device %s", config.FixedCIDRv6.String(), config.BridgeName)
}
return nil
}
+17 -2
View File
@@ -5,12 +5,16 @@ import (
"io/ioutil"
"net"
"github.com/Sirupsen/logrus"
"github.com/vishvananda/netlink"
)
var bridgeIPv6 *net.IPNet
const bridgeIPv6Str = "fe80::1/64"
const (
bridgeIPv6Str = "fe80::1/64"
ipv6ForwardConfPerm = 0644
)
func init() {
// We allow ourselves to panic in this special case because we indicate a
@@ -25,7 +29,7 @@ func init() {
func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
// Enable IPv6 on the bridge
procFile := "/proc/sys/net/ipv6/conf/" + config.BridgeName + "/disable_ipv6"
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil {
if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, ipv6ForwardConfPerm); err != nil {
return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
}
@@ -64,3 +68,14 @@ func setupGatewayIPv6(config *networkConfiguration, i *bridgeInterface) error {
return nil
}
func setupIPv6Forwarding(config *networkConfiguration, i *bridgeInterface) error {
// Enable IPv6 forwarding
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
logrus.Warnf("Unable to enable IPv6 default forwarding: %v", err)
}
if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
logrus.Warnf("Unable to enable IPv6 all forwarding: %v", err)
}
return nil
}
+9
View File
@@ -64,14 +64,23 @@ type network struct {
}
func (n *network) Name() string {
n.Lock()
defer n.Unlock()
return n.name
}
func (n *network) ID() string {
n.Lock()
defer n.Unlock()
return string(n.id)
}
func (n *network) Type() string {
n.Lock()
defer n.Unlock()
if n.driver == nil {
return ""
}
+94 -23
View File
@@ -4,10 +4,14 @@ import (
"fmt"
"net"
"os"
"os/exec"
"runtime"
"sync"
"syscall"
"time"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netns"
@@ -15,7 +19,13 @@ import (
const prefix = "/var/run/docker/netns"
var once sync.Once
var (
once sync.Once
garbagePathMap = make(map[string]bool)
gpmLock sync.Mutex
gpmWg sync.WaitGroup
gpmCleanupPeriod = 60 * time.Second
)
// The networkNamespace type is the linux implementation of the Sandbox
// interface. It represents a linux network namespace, and moves an interface
@@ -27,11 +37,53 @@ type networkNamespace struct {
sync.Mutex
}
func init() {
reexec.Register("netns-create", reexecCreateNamespace)
}
func createBasePath() {
err := os.MkdirAll(prefix, 0644)
if err != nil && !os.IsExist(err) {
panic("Could not create net namespace path directory")
}
// Start the garbage collection go routine
go removeUnusedPaths()
}
func removeUnusedPaths() {
gpmLock.Lock()
period := gpmCleanupPeriod
gpmLock.Unlock()
for range time.Tick(period) {
gpmLock.Lock()
pathList := make([]string, 0, len(garbagePathMap))
for path := range garbagePathMap {
pathList = append(pathList, path)
}
garbagePathMap = make(map[string]bool)
gpmWg.Add(1)
gpmLock.Unlock()
for _, path := range pathList {
os.Remove(path)
}
gpmWg.Done()
}
}
func addToGarbagePaths(path string) {
gpmLock.Lock()
garbagePathMap[path] = true
gpmLock.Unlock()
}
func removeFromGarbagePaths(path string) {
gpmLock.Lock()
delete(garbagePathMap, path)
gpmLock.Unlock()
}
// GenerateKey generates a sandbox key based on the passed
@@ -56,6 +108,20 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
return &networkNamespace{path: key, sinfo: info}, nil
}
func reexecCreateNamespace() {
if len(os.Args) < 2 {
log.Fatal("no namespace path provided")
}
if err := syscall.Mount("/proc/self/ns/net", os.Args[1], "bind", syscall.MS_BIND, ""); err != nil {
log.Fatal(err)
}
if err := loopbackUp(); err != nil {
log.Fatal(err)
}
}
func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -70,23 +136,18 @@ func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
return nil, err
}
if osCreate {
defer netns.Set(origns)
newns, err := netns.New()
if err != nil {
return nil, err
}
defer newns.Close()
if err := loopbackUp(); err != nil {
return nil, err
}
cmd := &exec.Cmd{
Path: reexec.Self(),
Args: append([]string{"netns-create"}, path),
Stdout: os.Stdout,
Stderr: os.Stderr,
}
procNet := fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid())
if err := syscall.Mount(procNet, path, "bind", syscall.MS_BIND, ""); err != nil {
return nil, err
if osCreate {
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNET
}
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("namespace creation reexec command failed: %v", err)
}
interfaces := []*Interface{}
@@ -94,10 +155,9 @@ func createNetworkNamespace(path string, osCreate bool) (*Info, error) {
return info, nil
}
func cleanupNamespaceFile(path string) {
func unmountNamespaceFile(path string) {
if _, err := os.Stat(path); err == nil {
n := &networkNamespace{path: path}
n.Destroy()
syscall.Unmount(path, syscall.MNT_DETACH)
}
}
@@ -105,11 +165,20 @@ func createNamespaceFile(path string) (err error) {
var f *os.File
once.Do(createBasePath)
// cleanup namespace file if it already exists because of a previous ungraceful exit.
cleanupNamespaceFile(path)
// Remove it from garbage collection list if present
removeFromGarbagePaths(path)
// If the path is there unmount it first
unmountNamespaceFile(path)
// wait for garbage collection to complete if it is in progress
// before trying to create the file.
gpmWg.Wait()
if f, err = os.Create(path); err == nil {
f.Close()
}
return err
}
@@ -310,5 +379,7 @@ func (n *networkNamespace) Destroy() error {
return err
}
return os.Remove(n.path)
// Stash it into the garbage collection list
addToGarbagePaths(n.path)
return nil
}
+13
View File
@@ -6,6 +6,7 @@ import (
"path/filepath"
"runtime"
"testing"
"time"
"github.com/docker/libnetwork/netutils"
"github.com/vishvananda/netlink"
@@ -31,6 +32,11 @@ func newKey(t *testing.T) (string, error) {
return "", err
}
// Set the rpmCleanupPeriod to be low to make the test run quicker
gpmLock.Lock()
gpmCleanupPeriod = 2 * time.Second
gpmLock.Unlock()
return name, nil
}
@@ -146,3 +152,10 @@ func verifySandbox(t *testing.T, s Sandbox) {
err)
}
}
func verifyCleanup(t *testing.T, s Sandbox) {
time.Sleep(time.Duration(gpmCleanupPeriod * 2))
if _, err := os.Stat(s.Key()); err == nil {
t.Fatalf("The sandbox path %s is not getting cleanup event after twice the cleanup period", s.Key())
}
}
+11
View File
@@ -2,9 +2,19 @@ package sandbox
import (
"net"
"os"
"testing"
"github.com/docker/docker/pkg/reexec"
)
func TestMain(m *testing.M) {
if reexec.Init() {
return
}
os.Exit(m.Run())
}
func TestSandboxCreate(t *testing.T) {
key, err := newKey(t)
if err != nil {
@@ -44,6 +54,7 @@ func TestSandboxCreate(t *testing.T) {
verifySandbox(t, s)
s.Destroy()
verifyCleanup(t, s)
}
func TestSandboxCreateTwice(t *testing.T) {