diff --git a/configs/network.go b/configs/network.go index fdccce50..890953a0 100644 --- a/configs/network.go +++ b/configs/network.go @@ -8,6 +8,9 @@ type Network struct { // Type sets the networks type, commonly veth and loopback Type string `json:"type,omitempty"` + // Name of the network interface + Name string `json:"name,omitempty"` + // The bridge to use. Bridge string `json:"bridge,omitempty"` @@ -36,11 +39,9 @@ type Network struct { // Note: This does not apply to loopback interfaces. TxQueueLen int `json:"txqueuelen,omitempty"` - // The name of the veth interface on the Host. - VethHost string `json:"veth_host,omitempty"` - - // The name of the veth interface created inside the container for the child. - VethChild string `json:"veth_child,omitempty"` + // HostInterfaceName is a unique name of a veth pair that resides on in the host interface of the + // container. + HostInterfaceName string `json:"host_interface_name,omitempty"` } // Routes can be specified to create entries in the route table as the container is started diff --git a/integration/init_test.go b/integration/init_test.go index 6b4bc32d..8af88efd 100644 --- a/integration/init_test.go +++ b/integration/init_test.go @@ -15,14 +15,12 @@ func init() { if len(os.Args) < 2 || os.Args[1] != "init" { return } + runtime.GOMAXPROCS(1) runtime.LockOSThread() - factory, err := libcontainer.New("", nil) if err != nil { log.Fatalf("unable to initialize for container: %s", err) } - factory.StartInitialization(3) - os.Exit(1) } diff --git a/linux_container.go b/linux_container.go index 06f90b3c..c92ffa71 100644 --- a/linux_container.go +++ b/linux_container.go @@ -71,7 +71,7 @@ func (c *linuxContainer) Stats() (*Stats, error) { for _, iface := range c.config.Networks { switch iface.Type { case "veth": - istats, err := getNetworkInterfaceStats(iface.VethHost) + istats, err := getNetworkInterfaceStats(iface.HostInterfaceName) if err != nil { return stats, newGenericError(err, SystemError) } @@ -134,6 +134,8 @@ func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) (*exec. } func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) *initProcess { + t := "_LIBCONTAINER_INITTYPE=standard" + cloneFlags := c.config.Namespaces.CloneFlags() if cloneFlags&syscall.CLONE_NEWUSER != 0 { c.addUidGidMappings(cmd.SysProcAttr) @@ -141,9 +143,10 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c if cmd.SysProcAttr.Credential == nil { cmd.SysProcAttr.Credential = &syscall.Credential{} } + t = "_LIBCONTAINER_INITTYPE=userns" } + cmd.Env = append(cmd.Env, t) cmd.SysProcAttr.Cloneflags = cloneFlags - cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE=standard") return &initProcess{ cmd: cmd, childPipe: childPipe, diff --git a/linux_init.go b/linux_init.go index 5ff1afc7..7c56afe8 100644 --- a/linux_init.go +++ b/linux_init.go @@ -29,13 +29,23 @@ type pid struct { Pid int `json:"pid"` } +// network is an internal struct used to setup container networks. +type network struct { + configs.Network + + // TempVethPeerName is a unique tempory veth peer name that was placed into + // the container's namespace. + TempVethPeerName string `json:"temp_veth_peer_name"` +} + // Process is used for transferring parameters from Exec() to Init() type initConfig struct { - Args []string `json:"args"` - Env []string `json:"env"` - Cwd string `json:"cwd"` - User string `json:"user"` - Config *configs.Config `json:"config"` + Args []string `json:"args"` + Env []string `json:"env"` + Cwd string `json:"cwd"` + User string `json:"user"` + Config *configs.Config `json:"config"` + Networks []*network `json:"network"` } type initer interface { @@ -184,18 +194,15 @@ func setupUser(config *initConfig) error { return nil } -// setupVethNetwork uses the Network config if it is not nil to initialize -// the new veth interface inside the container for use by changing the name to eth0 -// setting the MTU and IP address along with the default gateway -func setupNetwork(config *configs.Config) error { +// setupNetwork sets up and initializes any network interface inside the container. +func setupNetwork(config *initConfig) error { for _, config := range config.Networks { strategy, err := getStrategy(config.Type) if err != nil { return err } - err1 := strategy.Initialize(config) - if err1 != nil { - return err1 + if err := strategy.initialize(config); err != nil { + return err } } return nil diff --git a/linux_network.go b/linux_network.go index cc199be4..0b5d3394 100644 --- a/linux_network.go +++ b/linux_network.go @@ -11,12 +11,10 @@ import ( "strconv" "strings" - "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/netlink" + "github.com/docker/libcontainer/utils" ) -const defaultVethInterfaceName = "eth0" - var ( ErrNotValidStrategyType = errors.New("not a valid network strategy type") ) @@ -29,8 +27,8 @@ var strategies = map[string]networkStrategy{ // networkStrategy represents a specific network configuration for // a container's networking stack type networkStrategy interface { - Create(*configs.Network, int) error - Initialize(*configs.Network) error + create(*network, int) error + initialize(*network) error } // getStrategy returns the specific network strategy for the @@ -93,11 +91,11 @@ func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) { type loopback struct { } -func (l *loopback) Create(n *configs.Network, nspid int) error { +func (l *loopback) create(n *network, nspid int) error { return nil } -func (l *loopback) Initialize(config *configs.Network) error { +func (l *loopback) initialize(config *network) error { iface, err := net.InterfaceByName("lo") if err != nil { return err @@ -111,7 +109,18 @@ func (l *loopback) Initialize(config *configs.Network) error { type veth struct { } -func (v *veth) Create(n *configs.Network, nspid int) error { +func (v *veth) create(n *network, nspid int) (err error) { + tmpName, err := v.generateTempPeerName() + if err != nil { + return err + } + n.TempVethPeerName = tmpName + defer func() { + if err != nil { + netlink.NetworkLinkDel(n.HostInterfaceName) + netlink.NetworkLinkDel(n.TempVethPeerName) + } + }() if n.Bridge == "" { return fmt.Errorf("bridge is not specified") } @@ -119,10 +128,10 @@ func (v *veth) Create(n *configs.Network, nspid int) error { if err != nil { return err } - if err := netlink.NetworkCreateVethPair(n.VethHost, n.VethChild, n.TxQueueLen); err != nil { + if err := netlink.NetworkCreateVethPair(n.HostInterfaceName, n.TempVethPeerName, n.TxQueueLen); err != nil { return err } - host, err := net.InterfaceByName(n.VethHost) + host, err := net.InterfaceByName(n.HostInterfaceName) if err != nil { return err } @@ -135,30 +144,34 @@ func (v *veth) Create(n *configs.Network, nspid int) error { if err := netlink.NetworkLinkUp(host); err != nil { return err } - child, err := net.InterfaceByName(n.VethChild) + child, err := net.InterfaceByName(n.TempVethPeerName) if err != nil { return err } return netlink.NetworkSetNsPid(child, nspid) } -func (v *veth) Initialize(config *configs.Network) error { - vethChild := config.VethChild - if vethChild == "" { - return fmt.Errorf("vethChild is not specified") +func (v *veth) generateTempPeerName() (string, error) { + return utils.GenerateRandomName("veth", 7) +} + +func (v *veth) initialize(config *network) error { + peer := config.TempVethPeerName + if peer == "" { + return fmt.Errorf("peer is not specified") } - child, err := net.InterfaceByName(vethChild) + child, err := net.InterfaceByName(peer) if err != nil { return err } if err := netlink.NetworkLinkDown(child); err != nil { return err } - if err := netlink.NetworkChangeName(child, defaultVethInterfaceName); err != nil { + if err := netlink.NetworkChangeName(child, config.Name); err != nil { return err } // get the interface again after we changed the name as the index also changes. - if child, err = net.InterfaceByName(defaultVethInterfaceName); err != nil { + if child, err = net.InterfaceByName(config.Name); err != nil { return err } if config.MacAddress != "" { @@ -188,12 +201,12 @@ func (v *veth) Initialize(config *configs.Network) error { return err } if config.Gateway != "" { - if err := netlink.AddDefaultGw(config.Gateway, defaultVethInterfaceName); err != nil { + if err := netlink.AddDefaultGw(config.Gateway, config.Name); err != nil { return err } } if config.IPv6Gateway != "" { - if err := netlink.AddDefaultGw(config.IPv6Gateway, defaultVethInterfaceName); err != nil { + if err := netlink.AddDefaultGw(config.IPv6Gateway, config.Name); err != nil { return err } } diff --git a/linux_process.go b/linux_process.go index 04c0e5d6..2b434a51 100644 --- a/linux_process.go +++ b/linux_process.go @@ -239,9 +239,13 @@ func (p *initProcess) createNetworkInterfaces() error { if err != nil { return err } - if err := strategy.Create(config, p.pid()); err != nil { + n := &network{ + Network: *config, + } + if err := strategy.create(n, p.pid()); err != nil { return err } + p.config.Networks = append(p.config.Networks, n) } return nil } diff --git a/linux_rootfs.go b/linux_rootfs.go index 20a1a9db..36fc1898 100644 --- a/linux_rootfs.go +++ b/linux_rootfs.go @@ -46,15 +46,11 @@ func setupRootfs(config *configs.Config) (err error) { if err := setupPtmx(config); err != nil { return err } - uid, err := config.HostUID() - if err != nil { - return err - } // stdin, stdout and stderr could be pointing to /dev/null from parent namespace. // Re-open them inside this namespace. // FIXME: Need to fix this for user namespaces. if !config.Namespaces.Contains(configs.NEWUSER) { - if err := reOpenDevNull(config.RootFs); err != nil { + if err := reOpenDevNull(config.Rootfs); err != nil { return err } } diff --git a/linux_standard_init.go b/linux_standard_init.go index 2cf7a9f2..c576bdbd 100644 --- a/linux_standard_init.go +++ b/linux_standard_init.go @@ -35,7 +35,7 @@ func (l *linuxStandardInit) Init() error { return err } } - if err := setupNetwork(l.config.Config); err != nil { + if err := setupNetwork(l.config); err != nil { return err } if err := setupRoute(l.config.Config); err != nil { diff --git a/linux_userns_sidecar_init.go b/linux_userns_sidecar_init.go index 24dea9ef..eedc63e0 100644 --- a/linux_userns_sidecar_init.go +++ b/linux_userns_sidecar_init.go @@ -18,7 +18,7 @@ type linuxUsernsSideCar struct { } func (l *linuxUsernsSideCar) Init() error { - if err := setupNetwork(l.config.Config); err != nil { + if err := setupNetwork(l.config); err != nil { return err } if err := setupRoute(l.config.Config); err != nil { @@ -26,7 +26,7 @@ func (l *linuxUsernsSideCar) Init() error { } label.Init() // InitializeMountNamespace() can be executed only for a new mount namespace - if l.config.Config.Namespaces.Contains(configs.NEWNET) { + if l.config.Config.Namespaces.Contains(configs.NEWNS) { if err := setupRootfs(l.config.Config); err != nil { return err } diff --git a/nsinit/init.go b/nsinit/init.go index d45d1287..9848c42b 100644 --- a/nsinit/init.go +++ b/nsinit/init.go @@ -2,6 +2,7 @@ package main import ( "log" + "runtime" "github.com/codegangsta/cli" "github.com/docker/libcontainer" @@ -15,6 +16,8 @@ var initCommand = cli.Command{ cli.IntFlag{Name: "fd", Value: 0, Usage: "internal pipe fd"}, }, Action: func(context *cli.Context) { + runtime.GOMAXPROCS(1) + runtime.LockOSThread() factory, err := libcontainer.New("", nil) if err != nil { log.Fatal(err)