Libnetwork refactor for container network model
- Added controller, network, endpoint and sandbox interfaces - Created netutils package for miscallaneous network utilities - Created driverapi package to break cyclic dependency b/w driver and libnetwork - Made libnetwork multithread safe - Made bridge driver multithread safe - Fixed README.md Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
parent
53541c24a4
commit
68ae284db5
31 changed files with 910 additions and 483 deletions
|
@ -17,34 +17,43 @@ Please refer to the [roadmap](ROADMAP.md) for more information.
|
|||
There are many networking solutions available to suit a broad range of use-cases. libnetwork uses a driver / plugin model to support all of these solutions while abstracting the complexity of the driver implementations by exposing a simple and consistent Network Model to users.
|
||||
|
||||
```go
|
||||
//Create a network for containers to join.
|
||||
network, err := libnetwork.NewNetwork("simplebridge", &Options{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//
|
||||
// For a new container: create network namespace (providing the path).
|
||||
networkPath := "/var/lib/docker/.../4d23e"
|
||||
networkNamespace, err := libnetwork.NewNetworkNamespace(networkPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//
|
||||
// For each new container: allocate IP and interfaces. The returned network
|
||||
// settings will be used for container infos (inspect and such), as well as
|
||||
// iptables rules for port publishing.
|
||||
interfaces, err := network.Link(containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//
|
||||
// Add interfaces to the namespace.
|
||||
for _, interface := range interfaces {
|
||||
if err := networkNamespace.AddInterface(interface); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
//
|
||||
// Create a new controller instance
|
||||
controller := libnetwork.New()
|
||||
|
||||
options := options.Generic{}
|
||||
// Create a network for containers to join.
|
||||
network, err := controller.NewNetwork("simplebridge", "network1", options)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// For a new container: create a sandbox instance (providing a unique key).
|
||||
// For linux it is a filesystem path
|
||||
networkPath := "/var/lib/docker/.../4d23e"
|
||||
networkNamespace, err := sandbox.NewSandbox(networkPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// For each new container: allocate IP and interfaces. The returned network
|
||||
// settings will be used for container infos (inspect and such), as well as
|
||||
// iptables rules for port publishing.
|
||||
_, sinfo, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Add interfaces to the namespace.
|
||||
for _, iface := range sinfo.Interfaces {
|
||||
if err := networkNamespace.AddInterface(iface); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Set the gateway IP
|
||||
if err := networkNamespace.SetGateway(sinfo.Gateway); err != nil {
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
## Future
|
||||
|
|
|
@ -6,15 +6,16 @@ import (
|
|||
"net"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
_ "github.com/docker/libnetwork/drivers/bridge"
|
||||
"github.com/docker/libnetwork/pkg/options"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ip, net, _ := net.ParseCIDR("192.168.100.1/24")
|
||||
net.IP = ip
|
||||
|
||||
options := libnetwork.DriverParams{"AddressIPv4": net}
|
||||
netw, err := libnetwork.NewNetwork("simplebridge", "dummy", options)
|
||||
options := options.Generic{"AddressIPv4": net}
|
||||
controller := libnetwork.New()
|
||||
netw, err := controller.NewNetwork("simplebridge", "dummy", options)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func configureInterface(iface netlink.Link, settings *Interface) error {
|
||||
ifaceName := iface.Attrs().Name
|
||||
ifaceConfigurators := []struct {
|
||||
Fn func(netlink.Link, *Interface) error
|
||||
ErrMessage string
|
||||
}{
|
||||
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, settings.DstName)},
|
||||
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, settings.Address)},
|
||||
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, settings.AddressIPv6)},
|
||||
{setInterfaceGateway, fmt.Sprintf("error setting interface %q gateway to %q", ifaceName, settings.Gateway)},
|
||||
{setInterfaceGatewayIPv6, fmt.Sprintf("error setting interface %q IPv6 gateway to %q", ifaceName, settings.GatewayIPv6)},
|
||||
}
|
||||
|
||||
for _, config := range ifaceConfigurators {
|
||||
if err := config.Fn(iface, settings); err != nil {
|
||||
return fmt.Errorf("%s: %v", config.ErrMessage, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setGatewayIP(iface netlink.Link, ip net.IP) error {
|
||||
return netlink.RouteAdd(&netlink.Route{
|
||||
LinkIndex: iface.Attrs().Index,
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
Gw: ip,
|
||||
})
|
||||
}
|
||||
|
||||
func setInterfaceGateway(iface netlink.Link, settings *Interface) error {
|
||||
ip := net.ParseIP(settings.Gateway)
|
||||
if ip == nil {
|
||||
return fmt.Errorf("bad address format %q", settings.Gateway)
|
||||
}
|
||||
return setGatewayIP(iface, ip)
|
||||
}
|
||||
|
||||
func setInterfaceGatewayIPv6(iface netlink.Link, settings *Interface) error {
|
||||
if settings.GatewayIPv6 != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
ip := net.ParseIP(settings.GatewayIPv6)
|
||||
if ip == nil {
|
||||
return fmt.Errorf("bad address format %q", settings.GatewayIPv6)
|
||||
}
|
||||
return setGatewayIP(iface, ip)
|
||||
}
|
||||
|
||||
func setInterfaceIP(iface netlink.Link, settings *Interface) (err error) {
|
||||
var ipAddr *netlink.Addr
|
||||
if ipAddr, err = netlink.ParseAddr(settings.Address); err == nil {
|
||||
err = netlink.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setInterfaceIPv6(iface netlink.Link, settings *Interface) (err error) {
|
||||
if settings.AddressIPv6 != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var ipAddr *netlink.Addr
|
||||
if ipAddr, err = netlink.ParseAddr(settings.AddressIPv6); err == nil {
|
||||
err = netlink.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setInterfaceName(iface netlink.Link, settings *Interface) error {
|
||||
return netlink.LinkSetName(iface, settings.DstName)
|
||||
}
|
72
libnetwork/driverapi/driverapi.go
Normal file
72
libnetwork/driverapi/driverapi.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package driverapi
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrEndpointExists is returned if more than one endpoint is added to the network
|
||||
ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
|
||||
// ErrNoNetwork is returned if no network with the specified id exists
|
||||
ErrNoNetwork = errors.New("No network exists")
|
||||
// ErrNoEndpoint is returned if no endpoint with the specified id exists
|
||||
ErrNoEndpoint = errors.New("No endpoint exists")
|
||||
)
|
||||
|
||||
// UUID represents a globally unique ID of various resources like network and endpoint
|
||||
type UUID string
|
||||
|
||||
// Driver is an interface that every plugin driver needs to implement.
|
||||
type Driver interface {
|
||||
// CreateNetwork invokes the driver method to create a network passing
|
||||
// the network id and driver specific config. The config mechanism will
|
||||
// eventually be replaced with labels which are yet to be introduced.
|
||||
CreateNetwork(nid UUID, config interface{}) error
|
||||
|
||||
// DeleteNetwork invokes the driver method to delete network passing
|
||||
// the network id.
|
||||
DeleteNetwork(nid UUID) error
|
||||
|
||||
// CreateEndpoint invokes the driver method to create an endpoint
|
||||
// passing the network id, endpoint id, sandbox key and driver
|
||||
// specific config. The config mechanism will eventually be replaced
|
||||
// with labels which are yet to be introduced.
|
||||
CreateEndpoint(nid, eid UUID, key string, config interface{}) (*SandboxInfo, error)
|
||||
|
||||
// DeleteEndpoint invokes the driver method to delete an endpoint
|
||||
// passing the network id and endpoint id.
|
||||
DeleteEndpoint(nid, eid UUID) error
|
||||
}
|
||||
|
||||
// Interface represents the settings and identity of a network device. It is
|
||||
// used as a return type for Network.Link, and it is common practice for the
|
||||
// caller to use this information when moving interface SrcName from host
|
||||
// namespace to DstName in a different net namespace with the appropriate
|
||||
// network settings.
|
||||
type Interface struct {
|
||||
// The name of the interface in the origin network namespace.
|
||||
SrcName string
|
||||
|
||||
// The name that will be assigned to the interface once moves inside a
|
||||
// network namespace.
|
||||
DstName string
|
||||
|
||||
// IPv4 address for the interface.
|
||||
Address string
|
||||
|
||||
// IPv6 address for the interface.
|
||||
AddressIPv6 string
|
||||
}
|
||||
|
||||
// SandboxInfo represents all possible information that
|
||||
// the driver wants to place in the sandbox which includes
|
||||
// interfaces, routes and gateway
|
||||
type SandboxInfo struct {
|
||||
Interfaces []*Interface
|
||||
|
||||
// IPv4 gateway for the sandbox.
|
||||
Gateway string
|
||||
|
||||
// IPv6 gateway for the sandbox.
|
||||
GatewayIPv6 string
|
||||
|
||||
// TODO: Add routes and ip tables etc.
|
||||
}
|
|
@ -1,65 +1,18 @@
|
|||
package libnetwork
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/libnetwork/pkg/options"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/drivers/bridge"
|
||||
)
|
||||
|
||||
// DriverParams are a generic structure to hold driver specific settings.
|
||||
type DriverParams options.Generic
|
||||
type driverTable map[string]driverapi.Driver
|
||||
|
||||
// DriverInterface is an interface that every plugin driver needs to implement.
|
||||
type DriverInterface interface {
|
||||
CreateNetwork(string, interface{}) (Network, error)
|
||||
}
|
||||
|
||||
var drivers = map[string]struct {
|
||||
creatorFn DriverInterface
|
||||
creatorArg interface{}
|
||||
}{}
|
||||
|
||||
// RegisterNetworkType associates a textual identifier with a way to create a
|
||||
// new network. It is called by the various network implementations, and used
|
||||
// upon invokation of the libnetwork.NetNetwork function.
|
||||
//
|
||||
// creatorFn must implement DriverInterface
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type driver struct{}
|
||||
//
|
||||
// func (d *driver) CreateNetwork(name string, config *TestNetworkConfig) (Network, error) {
|
||||
// }
|
||||
//
|
||||
// func init() {
|
||||
// RegisterNetworkType("test", &driver{}, &TestNetworkConfig{})
|
||||
// }
|
||||
//
|
||||
func RegisterNetworkType(name string, creatorFn DriverInterface, creatorArg interface{}) error {
|
||||
// Store the new driver information to invoke at creation time.
|
||||
if _, ok := drivers[name]; ok {
|
||||
return fmt.Errorf("a driver for network type %q is already registed", name)
|
||||
func enumerateDrivers() driverTable {
|
||||
var drivers driverTable
|
||||
for _, fn := range [](func() (string, driverapi.Driver)){bridge.New} {
|
||||
name, driver := fn()
|
||||
drivers[name] = driver
|
||||
}
|
||||
|
||||
drivers[name] = struct {
|
||||
creatorFn DriverInterface
|
||||
creatorArg interface{}
|
||||
}{creatorFn, creatorArg}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createNetwork(networkType, name string, generic DriverParams) (Network, error) {
|
||||
d, ok := drivers[networkType]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown driver %q", networkType)
|
||||
}
|
||||
|
||||
config, err := options.GenerateFromModel(options.Generic(generic), d.creatorArg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate driver config: %v", err)
|
||||
}
|
||||
|
||||
return d.creatorFn.CreateNetwork(name, config)
|
||||
return drivers
|
||||
}
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libcontainer/utils"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/ipallocator"
|
||||
"github.com/docker/libnetwork/pkg/options"
|
||||
"github.com/docker/libnetwork/portmapper"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -39,23 +45,76 @@ type Configuration struct {
|
|||
EnableIPForwarding bool
|
||||
}
|
||||
|
||||
type driver struct{}
|
||||
type bridgeEndpoint struct {
|
||||
id driverapi.UUID
|
||||
addressIPv4 net.IP
|
||||
addressIPv6 net.IP
|
||||
}
|
||||
|
||||
type bridgeNetwork struct {
|
||||
id driverapi.UUID
|
||||
// bridge interface points to the linux bridge and it's configuration
|
||||
bridge *bridgeInterface
|
||||
endpoint *bridgeEndpoint
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
network *bridgeNetwork
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func init() {
|
||||
ipAllocator = ipallocator.New()
|
||||
initPortMapper()
|
||||
libnetwork.RegisterNetworkType(networkType, &driver{}, &Configuration{})
|
||||
}
|
||||
|
||||
// New provides a new instance of bridge driver instance
|
||||
func New() (string, driverapi.Driver) {
|
||||
return networkType, &driver{}
|
||||
}
|
||||
|
||||
// Create a new network using simplebridge plugin
|
||||
func (d *driver) CreateNetwork(name string, opaqueConfig interface{}) (libnetwork.Network, error) {
|
||||
config := opaqueConfig.(*Configuration)
|
||||
bridgeIntfc := newInterface(config)
|
||||
bridgeSetup := newBridgeSetup(bridgeIntfc)
|
||||
func (d *driver) CreateNetwork(id driverapi.UUID, option interface{}) error {
|
||||
|
||||
var (
|
||||
config *Configuration
|
||||
err error
|
||||
)
|
||||
|
||||
d.Lock()
|
||||
if d.network != nil {
|
||||
d.Unlock()
|
||||
return fmt.Errorf("network already exists, simplebridge can only have one network")
|
||||
}
|
||||
d.network = &bridgeNetwork{id: id}
|
||||
d.Unlock()
|
||||
defer func() {
|
||||
// On failure make sure to reset d.network to nil
|
||||
if err != nil {
|
||||
d.Lock()
|
||||
d.network = nil
|
||||
d.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
switch opt := option.(type) {
|
||||
case options.Generic:
|
||||
opaqueConfig, err := options.GenerateFromModel(opt, &Configuration{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate driver config: %v", err)
|
||||
}
|
||||
config = opaqueConfig.(*Configuration)
|
||||
case *Configuration:
|
||||
config = opt
|
||||
}
|
||||
|
||||
bridgeIface := newInterface(config)
|
||||
bridgeSetup := newBridgeSetup(bridgeIface)
|
||||
|
||||
// If the bridge interface doesn't exist, we need to start the setup steps
|
||||
// by creating a new device and assigning it an IPv4 address.
|
||||
bridgeAlreadyExists := bridgeIntfc.exists()
|
||||
bridgeAlreadyExists := bridgeIface.exists()
|
||||
if !bridgeAlreadyExists {
|
||||
bridgeSetup.queueStep(setupDevice)
|
||||
bridgeSetup.queueStep(setupBridgeIPv4)
|
||||
|
@ -97,9 +156,226 @@ func (d *driver) CreateNetwork(name string, opaqueConfig interface{}) (libnetwor
|
|||
|
||||
// Apply the prepared list of steps, and abort at the first error.
|
||||
bridgeSetup.queueStep(setupDeviceUp)
|
||||
if err := bridgeSetup.apply(); err != nil {
|
||||
if err = bridgeSetup.apply(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.network.bridge = bridgeIface
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid driverapi.UUID) error {
|
||||
var err error
|
||||
d.Lock()
|
||||
n := d.network
|
||||
d.network = nil
|
||||
d.Unlock()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
// On failure set d.network back to n
|
||||
// but only if is not already take over
|
||||
// by some other thread
|
||||
d.Lock()
|
||||
if d.network == nil {
|
||||
d.network = n
|
||||
}
|
||||
d.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
if n == nil {
|
||||
err = driverapi.ErrNoNetwork
|
||||
return err
|
||||
}
|
||||
|
||||
if n.endpoint != nil {
|
||||
err = fmt.Errorf("Network %s has active endpoint %s", n.id, n.endpoint.id)
|
||||
return err
|
||||
}
|
||||
|
||||
err = netlink.LinkDel(n.bridge.Link)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid driverapi.UUID, sboxKey string, config interface{}) (*driverapi.SandboxInfo, error) {
|
||||
var (
|
||||
ipv6Addr net.IPNet
|
||||
err error
|
||||
)
|
||||
|
||||
d.Lock()
|
||||
n := d.network
|
||||
d.Unlock()
|
||||
if n == nil {
|
||||
return nil, driverapi.ErrNoNetwork
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
if n.id != nid {
|
||||
n.Unlock()
|
||||
return nil, fmt.Errorf("invalid network id %s", nid)
|
||||
}
|
||||
|
||||
if n.endpoint != nil {
|
||||
n.Unlock()
|
||||
return nil, driverapi.ErrEndpointExists
|
||||
}
|
||||
n.endpoint = &bridgeEndpoint{id: eid}
|
||||
n.Unlock()
|
||||
defer func() {
|
||||
// On failye make sure to reset n.endpoint to nil
|
||||
if err != nil {
|
||||
n.Lock()
|
||||
n.endpoint = nil
|
||||
n.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
name1, err := generateIfaceName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &bridgeNetwork{NetworkName: name, bridge: bridgeIntfc}, nil
|
||||
name2, err := generateIfaceName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
veth := &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
|
||||
PeerName: name2}
|
||||
if err = netlink.LinkAdd(veth); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
host, err := netlink.LinkByName(name1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
netlink.LinkDel(host)
|
||||
}
|
||||
}()
|
||||
|
||||
container, err := netlink.LinkByName(name2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
netlink.LinkDel(container)
|
||||
}
|
||||
}()
|
||||
|
||||
if err = netlink.LinkSetMaster(host,
|
||||
&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: n.bridge.Config.BridgeName}}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv4Addr := net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
|
||||
|
||||
if n.bridge.Config.EnableIPv6 {
|
||||
ip6, err := ipAllocator.RequestIP(n.bridge.bridgeIPv6, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv6Addr = net.IPNet{IP: ip6, Mask: n.bridge.bridgeIPv6.Mask}
|
||||
}
|
||||
|
||||
var interfaces []*driverapi.Interface
|
||||
sinfo := &driverapi.SandboxInfo{}
|
||||
|
||||
intf := &driverapi.Interface{}
|
||||
intf.SrcName = name2
|
||||
intf.DstName = "eth0"
|
||||
intf.Address = ipv4Addr.String()
|
||||
sinfo.Gateway = n.bridge.bridgeIPv4.IP.String()
|
||||
if n.bridge.Config.EnableIPv6 {
|
||||
intf.AddressIPv6 = ipv6Addr.String()
|
||||
sinfo.GatewayIPv6 = n.bridge.bridgeIPv6.IP.String()
|
||||
}
|
||||
|
||||
n.endpoint.addressIPv4 = ip4
|
||||
n.endpoint.addressIPv6 = ipv6Addr.IP
|
||||
interfaces = append(interfaces, intf)
|
||||
sinfo.Interfaces = interfaces
|
||||
return sinfo, nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid driverapi.UUID) error {
|
||||
var err error
|
||||
|
||||
d.Lock()
|
||||
n := d.network
|
||||
d.Unlock()
|
||||
if n == nil {
|
||||
return driverapi.ErrNoNetwork
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
if n.id != nid {
|
||||
n.Unlock()
|
||||
return fmt.Errorf("invalid network id %s", nid)
|
||||
}
|
||||
|
||||
if n.endpoint == nil {
|
||||
n.Unlock()
|
||||
return driverapi.ErrNoEndpoint
|
||||
}
|
||||
|
||||
ep := n.endpoint
|
||||
if ep.id != eid {
|
||||
n.Unlock()
|
||||
return fmt.Errorf("invalid endpoint id %s", eid)
|
||||
}
|
||||
|
||||
n.endpoint = nil
|
||||
n.Unlock()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
// On failure make to set back n.endpoint with ep
|
||||
// but only if it hasn't been taken over
|
||||
// already by some other thread.
|
||||
n.Lock()
|
||||
if n.endpoint == nil {
|
||||
n.endpoint = ep
|
||||
}
|
||||
n.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
err = ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, ep.addressIPv4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n.bridge.Config.EnableIPv6 {
|
||||
err := ipAllocator.ReleaseIP(n.bridge.bridgeIPv6, n.endpoint.addressIPv6)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateIfaceName() (string, error) {
|
||||
for i := 0; i < 10; i++ {
|
||||
name, err := utils.GenerateRandomName("veth", 7)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if _, err := net.InterfaceByName(name); err != nil {
|
||||
if strings.Contains(err.Error(), "no such") {
|
||||
return name, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return "", errors.New("Failed to find name for new interface")
|
||||
}
|
||||
|
|
|
@ -4,37 +4,33 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
_, d := New()
|
||||
|
||||
config := &Configuration{BridgeName: DefaultBridgeName}
|
||||
netw, err := d.CreateNetwork("dummy", config)
|
||||
err := d.CreateNetwork("dummy", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
if expected := networkType; netw.Type() != expected {
|
||||
t.Fatalf("Expected networkType %q, got %q", expected, netw.Type())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFail(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
_, d := New()
|
||||
|
||||
config := &Configuration{BridgeName: "dummy0"}
|
||||
if _, err := d.CreateNetwork("dummy", config); err == nil {
|
||||
if err := d.CreateNetwork("dummy", config); err == nil {
|
||||
t.Fatal("Bridge creation was expected to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFullOptions(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
_, d := New()
|
||||
|
||||
config := &Configuration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
|
@ -45,12 +41,8 @@ func TestCreateFullOptions(t *testing.T) {
|
|||
}
|
||||
_, config.FixedCIDRv6, _ = net.ParseCIDR("2001:db8::/48")
|
||||
|
||||
netw, err := d.CreateNetwork("dummy", config)
|
||||
err := d.CreateNetwork("dummy", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
if expected := networkType; netw.Type() != expected {
|
||||
t.Fatalf("Expected networkType %q, got %q", expected, netw.Type())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ package bridge
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestInterfaceDefaultName(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
if inf := newInterface(&Configuration{}); inf.Config.BridgeName != DefaultBridgeName {
|
||||
t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, inf.Config.BridgeName)
|
||||
|
@ -16,7 +16,7 @@ func TestInterfaceDefaultName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAddressesEmptyInterface(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
inf := newInterface(&Configuration{})
|
||||
addrv4, addrsv6, err := inf.addresses()
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/libcontainer/utils"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// ErrEndpointExists is returned if more than one endpoint is added to the network
|
||||
var ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
|
||||
|
||||
type bridgeNetwork struct {
|
||||
NetworkName string
|
||||
bridge *bridgeInterface
|
||||
EndPoint *libnetwork.Interface
|
||||
}
|
||||
|
||||
func (b *bridgeNetwork) Name() string {
|
||||
return b.NetworkName
|
||||
}
|
||||
|
||||
func (b *bridgeNetwork) Type() string {
|
||||
return networkType
|
||||
}
|
||||
|
||||
func (b *bridgeNetwork) Link(name string) ([]*libnetwork.Interface, error) {
|
||||
|
||||
var ipv6Addr net.IPNet
|
||||
|
||||
if b.EndPoint != nil {
|
||||
return nil, ErrEndpointExists
|
||||
}
|
||||
|
||||
name1, err := generateIfaceName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name2, err := generateIfaceName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
veth := &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
|
||||
PeerName: name2}
|
||||
if err := netlink.LinkAdd(veth); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
host, err := netlink.LinkByName(name1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
netlink.LinkDel(host)
|
||||
}
|
||||
}()
|
||||
|
||||
container, err := netlink.LinkByName(name2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
netlink.LinkDel(container)
|
||||
}
|
||||
}()
|
||||
|
||||
if err = netlink.LinkSetMaster(host,
|
||||
&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: b.bridge.Config.BridgeName}}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ip4, err := ipAllocator.RequestIP(b.bridge.bridgeIPv4, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv4Addr := net.IPNet{IP: ip4, Mask: b.bridge.bridgeIPv4.Mask}
|
||||
|
||||
if b.bridge.Config.EnableIPv6 {
|
||||
ip6, err := ipAllocator.RequestIP(b.bridge.bridgeIPv6, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv6Addr = net.IPNet{IP: ip6, Mask: b.bridge.bridgeIPv6.Mask}
|
||||
}
|
||||
|
||||
var interfaces []*libnetwork.Interface
|
||||
intf := &libnetwork.Interface{}
|
||||
intf.SrcName = name2
|
||||
intf.DstName = "eth0"
|
||||
intf.Address = ipv4Addr.String()
|
||||
intf.Gateway = b.bridge.bridgeIPv4.IP.String()
|
||||
if b.bridge.Config.EnableIPv6 {
|
||||
intf.AddressIPv6 = ipv6Addr.String()
|
||||
intf.GatewayIPv6 = b.bridge.bridgeIPv6.IP.String()
|
||||
}
|
||||
|
||||
b.EndPoint = intf
|
||||
interfaces = append(interfaces, intf)
|
||||
return interfaces, nil
|
||||
}
|
||||
|
||||
func generateIfaceName() (string, error) {
|
||||
for i := 0; i < 10; i++ {
|
||||
name, err := utils.GenerateRandomName("veth", 7)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if _, err := net.InterfaceByName(name); err != nil {
|
||||
if strings.Contains(err.Error(), "no such") {
|
||||
return name, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return "", errors.New("Failed to find name for new interface")
|
||||
}
|
||||
|
||||
func (b *bridgeNetwork) Delete() error {
|
||||
return netlink.LinkDel(b.bridge.Link)
|
||||
}
|
|
@ -4,27 +4,30 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestLinkCreate(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
_, d := New()
|
||||
dr := d.(*driver)
|
||||
|
||||
config := &Configuration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableIPv6: true}
|
||||
netw, err := d.CreateNetwork("dummy", config)
|
||||
err := d.CreateNetwork("dummy", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
interfaces, err := netw.Link("ep")
|
||||
sinfo, err := d.CreateEndpoint("dummy", "ep", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %v", err)
|
||||
}
|
||||
|
||||
interfaces := sinfo.Interfaces
|
||||
if len(interfaces) != 1 {
|
||||
t.Fatalf("Expected exactly one interface. Instead got %d interface(s)", len(interfaces))
|
||||
}
|
||||
|
@ -43,9 +46,9 @@ func TestLinkCreate(t *testing.T) {
|
|||
t.Fatalf("Invalid IPv4 address returned, ip = %s: %v", interfaces[0].Address, err)
|
||||
}
|
||||
|
||||
b := netw.(*bridgeNetwork)
|
||||
if !b.bridge.bridgeIPv4.Contains(ip) {
|
||||
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), b.bridge.bridgeIPv4.String())
|
||||
n := dr.network
|
||||
if !n.bridge.bridgeIPv4.Contains(ip) {
|
||||
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), n.bridge.bridgeIPv4.String())
|
||||
}
|
||||
|
||||
ip6, _, err := net.ParseCIDR(interfaces[0].AddressIPv6)
|
||||
|
@ -53,41 +56,41 @@ func TestLinkCreate(t *testing.T) {
|
|||
t.Fatalf("Invalid IPv6 address returned, ip = %s: %v", interfaces[0].AddressIPv6, err)
|
||||
}
|
||||
|
||||
if !b.bridge.bridgeIPv6.Contains(ip6) {
|
||||
if !n.bridge.bridgeIPv6.Contains(ip6) {
|
||||
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip6.String(), bridgeIPv6.String())
|
||||
}
|
||||
|
||||
if interfaces[0].Gateway != b.bridge.bridgeIPv4.IP.String() {
|
||||
t.Fatalf("Invalid default gateway. Expected %s. Got %s", b.bridge.bridgeIPv4.IP.String(),
|
||||
interfaces[0].Gateway)
|
||||
if sinfo.Gateway != n.bridge.bridgeIPv4.IP.String() {
|
||||
t.Fatalf("Invalid default gateway. Expected %s. Got %s", n.bridge.bridgeIPv4.IP.String(),
|
||||
sinfo.Gateway)
|
||||
}
|
||||
|
||||
if interfaces[0].GatewayIPv6 != b.bridge.bridgeIPv6.IP.String() {
|
||||
t.Fatalf("Invalid default gateway for IPv6. Expected %s. Got %s", b.bridge.bridgeIPv6.IP.String(),
|
||||
interfaces[0].GatewayIPv6)
|
||||
if sinfo.GatewayIPv6 != n.bridge.bridgeIPv6.IP.String() {
|
||||
t.Fatalf("Invalid default gateway for IPv6. Expected %s. Got %s", n.bridge.bridgeIPv6.IP.String(),
|
||||
sinfo.GatewayIPv6)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkCreateTwo(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
_, d := New()
|
||||
|
||||
config := &Configuration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableIPv6: true}
|
||||
netw, err := d.CreateNetwork("dummy", config)
|
||||
err := d.CreateNetwork("dummy", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
_, err = netw.Link("ep")
|
||||
_, err = d.CreateEndpoint("dummy", "ep", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %v", err)
|
||||
}
|
||||
|
||||
_, err = netw.Link("ep1")
|
||||
_, err = d.CreateEndpoint("dummy", "ep1", "", "")
|
||||
if err != nil {
|
||||
if err != ErrEndpointExists {
|
||||
if err != driverapi.ErrEndpointExists {
|
||||
t.Fatalf("Failed with a wrong error :%v", err)
|
||||
}
|
||||
} else {
|
||||
|
@ -96,24 +99,25 @@ func TestLinkCreateTwo(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestLinkCreateNoEnableIPv6(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
_, d := New()
|
||||
|
||||
config := &Configuration{
|
||||
BridgeName: DefaultBridgeName}
|
||||
netw, err := d.CreateNetwork("dummy", config)
|
||||
err := d.CreateNetwork("dummy", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
interfaces, err := netw.Link("ep")
|
||||
sinfo, err := d.CreateEndpoint("dummy", "ep", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %v", err)
|
||||
}
|
||||
|
||||
interfaces := sinfo.Interfaces
|
||||
if interfaces[0].AddressIPv6 != "" ||
|
||||
interfaces[0].GatewayIPv6 != "" {
|
||||
sinfo.GatewayIPv6 != "" {
|
||||
t.Fatalf("Expected IPv6 address and GatewayIPv6 to be empty when IPv6 enabled. Instead got IPv6 = %s and GatewayIPv6 = %s",
|
||||
interfaces[0].AddressIPv6, interfaces[0].GatewayIPv6)
|
||||
interfaces[0].AddressIPv6, sinfo.GatewayIPv6)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/pkg/parsers/kernel"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
|
@ -28,7 +28,7 @@ func setupDevice(i *bridgeInterface) error {
|
|||
// was not supported before that.
|
||||
kv, err := kernel.GetKernelVersion()
|
||||
if err == nil && (kv.Kernel >= 3 && kv.Major >= 3) {
|
||||
i.Link.Attrs().HardwareAddr = libnetwork.GenerateRandomMAC()
|
||||
i.Link.Attrs().HardwareAddr = netutils.GenerateRandomMAC()
|
||||
log.Debugf("Setting bridge mac address to %s", i.Link.Attrs().HardwareAddr)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestSetupNewBridge(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
br := &bridgeInterface{
|
||||
Config: &Configuration{
|
||||
|
@ -33,7 +33,7 @@ func TestSetupNewBridge(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupNewNonDefaultBridge(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
br := &bridgeInterface{
|
||||
Config: &Configuration{
|
||||
|
@ -46,7 +46,7 @@ func TestSetupNewNonDefaultBridge(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupDeviceUp(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
br := &bridgeInterface{
|
||||
Config: &Configuration{
|
||||
|
@ -67,10 +67,10 @@ func TestSetupDeviceUp(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGenerateRandomMAC(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
mac1 := libnetwork.GenerateRandomMAC()
|
||||
mac2 := libnetwork.GenerateRandomMAC()
|
||||
mac1 := netutils.GenerateRandomMAC()
|
||||
mac2 := netutils.GenerateRandomMAC()
|
||||
if bytes.Compare(mac1, mac2) == 0 {
|
||||
t.Fatalf("Generated twice the same MAC address %v", mac1)
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
func TestSetupFixedCIDRv4(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
br := &bridgeInterface{
|
||||
Config: &Configuration{
|
||||
|
@ -36,7 +36,7 @@ func TestSetupFixedCIDRv4(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupBadFixedCIDRv4(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
br := &bridgeInterface{
|
||||
Config: &Configuration{
|
||||
|
|
|
@ -4,11 +4,11 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
func TestSetupFixedCIDRv6(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
br := newInterface(&Configuration{})
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"net"
|
||||
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
// DockerChain: DOCKER iptable chain name
|
||||
|
@ -19,7 +19,7 @@ func setupIPTables(i *bridgeInterface) error {
|
|||
return fmt.Errorf("Unexpected request to set IP tables for interface: %s", i.Config.BridgeName)
|
||||
}
|
||||
|
||||
addrv4, _, err := libnetwork.GetIfaceAddr(i.Config.BridgeName)
|
||||
addrv4, _, err := netutils.GetIfaceAddr(i.Config.BridgeName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to setup IP tables, cannot acquire Interface address: %s", err.Error())
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/docker/docker/pkg/iptables"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -14,7 +14,7 @@ const (
|
|||
|
||||
func TestProgramIPTable(t *testing.T) {
|
||||
// Create a test bridge with a basic bridge configuration (name + IPv4).
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
createTestBridge(getBasicTestConfig(), t)
|
||||
|
||||
// Store various iptables chain rules we care for.
|
||||
|
@ -38,7 +38,7 @@ func TestProgramIPTable(t *testing.T) {
|
|||
|
||||
func TestSetupIPTables(t *testing.T) {
|
||||
// Create a test bridge with a basic bridge configuration (name + IPv4).
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
br := getBasicTestConfig()
|
||||
createTestBridge(br, t)
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"net"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
|
@ -73,8 +73,8 @@ func electBridgeIPv4(config *Configuration) (*net.IPNet, error) {
|
|||
|
||||
// Try to automatically elect appropriate brige IPv4 settings.
|
||||
for _, n := range bridgeNetworks {
|
||||
if err := libnetwork.CheckNameserverOverlaps(nameservers, n); err == nil {
|
||||
if err := libnetwork.CheckRouteOverlaps(n); err == nil {
|
||||
if err := netutils.CheckNameserverOverlaps(nameservers, n); err == nil {
|
||||
if err := netutils.CheckRouteOverlaps(n); err == nil {
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
|
@ -21,7 +21,7 @@ func setupTestInterface(t *testing.T) *bridgeInterface {
|
|||
}
|
||||
|
||||
func TestSetupBridgeIPv4Fixed(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
ip, netw, err := net.ParseCIDR("192.168.1.1/24")
|
||||
if err != nil {
|
||||
|
@ -53,7 +53,7 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupBridgeIPv4Auto(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
br := setupTestInterface(t)
|
||||
if err := setupBridgeIPv4(br); err != nil {
|
||||
|
|
|
@ -6,12 +6,12 @@ import (
|
|||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestSetupIPv6(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
br := setupTestInterface(t)
|
||||
if err := setupBridgeIPv6(br); err != nil {
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
|
@ -23,7 +23,7 @@ func setupVerifyTest(t *testing.T) *bridgeInterface {
|
|||
}
|
||||
|
||||
func TestSetupVerify(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
|
@ -39,7 +39,7 @@ func TestSetupVerify(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupVerifyBad(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
|
@ -56,7 +56,7 @@ func TestSetupVerifyBad(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupVerifyMissing(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
|
@ -68,7 +68,7 @@ func TestSetupVerifyMissing(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupVerifyIPv6(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
|
@ -88,7 +88,7 @@ func TestSetupVerifyIPv6(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupVerifyIPv6Missing(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
defer netutils.SetupTestNetNS(t)()
|
||||
|
||||
addrv4 := net.IPv4(192, 168, 1, 1)
|
||||
inf := setupVerifyTest(t)
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
)
|
||||
|
||||
// allocatedMap is thread-unsafe set of allocated IP
|
||||
|
@ -21,7 +21,7 @@ type allocatedMap struct {
|
|||
}
|
||||
|
||||
func newAllocatedMap(network *net.IPNet) *allocatedMap {
|
||||
firstIP, lastIP := libnetwork.NetworkRange(network)
|
||||
firstIP, lastIP := netutils.NetworkRange(network)
|
||||
begin := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
|
||||
end := big.NewInt(0).Sub(ipToBigInt(lastIP), big.NewInt(1))
|
||||
|
||||
|
@ -71,7 +71,7 @@ func (a *IPAllocator) RegisterSubnet(network *net.IPNet, subnet *net.IPNet) erro
|
|||
return ErrNetworkAlreadyRegistered
|
||||
}
|
||||
n := newAllocatedMap(network)
|
||||
beginIP, endIP := libnetwork.NetworkRange(subnet)
|
||||
beginIP, endIP := netutils.NetworkRange(subnet)
|
||||
begin := big.NewInt(0).Add(ipToBigInt(beginIP), big.NewInt(1))
|
||||
end := big.NewInt(0).Sub(ipToBigInt(endIP), big.NewInt(1))
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork"
|
||||
_ "github.com/docker/libnetwork/drivers/bridge"
|
||||
"github.com/docker/libnetwork/pkg/options"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
|
@ -41,7 +42,7 @@ func TestSimplebridge(t *testing.T) {
|
|||
cidrv6.IP = ip
|
||||
|
||||
log.Debug("Adding a simple bridge")
|
||||
options := libnetwork.DriverParams{
|
||||
options := options.Generic{
|
||||
"BridgeName": bridgeName,
|
||||
"AddressIPv4": subnet,
|
||||
"FixedCIDR": cidr,
|
||||
|
@ -52,7 +53,9 @@ func TestSimplebridge(t *testing.T) {
|
|||
"EnableICC": true,
|
||||
"EnableIPForwarding": true}
|
||||
|
||||
network, err := libnetwork.NewNetwork("simplebridge", "dummy", options)
|
||||
controller := libnetwork.New()
|
||||
|
||||
network, err := controller.NewNetwork("simplebridge", "dummy", options)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package libnetwork
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"runtime"
|
|
@ -1,7 +1,7 @@
|
|||
// Network utility functions.
|
||||
// Imported unchanged from Docker
|
||||
|
||||
package libnetwork
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"errors"
|
|
@ -1,4 +1,4 @@
|
|||
package libnetwork
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"net"
|
|
@ -1,60 +1,61 @@
|
|||
// Package libnetwork provides basic fonctionalities and extension points to
|
||||
// create network namespaces and allocate interfaces for containers to use.
|
||||
//
|
||||
// // Create a network for containers to join.
|
||||
// network, err := libnetwork.NewNetwork("simplebridge", &Options{})
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// // For a new container: create network namespace (providing the path).
|
||||
// networkPath := "/var/lib/docker/.../4d23e"
|
||||
// networkNamespace, err := libnetwork.NewNetworkNamespace(networkPath)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// // For each new container: allocate IP and interfaces. The returned network
|
||||
// // settings will be used for container infos (inspect and such), as well as
|
||||
// // iptables rules for port publishing.
|
||||
// interfaces, err := network.Link(containerID)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// // Add interfaces to the namespace.
|
||||
// for _, interface := range interfaces {
|
||||
// if err := networkNamespace.AddInterface(interface); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Package libnetwork provides basic fonctionalities and extension points to
|
||||
create network namespaces and allocate interfaces for containers to use.
|
||||
|
||||
// Create a new controller instance
|
||||
controller := libnetwork.New()
|
||||
|
||||
options := options.Generic{}
|
||||
// Create a network for containers to join.
|
||||
network, err := controller.NewNetwork("simplebridge", "network1", options)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// For a new container: create a sandbox instance (providing a unique key).
|
||||
// For linux it is a filesystem path
|
||||
networkPath := "/var/lib/docker/.../4d23e"
|
||||
networkNamespace, err := sandbox.NewSandbox(networkPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// For each new container: allocate IP and interfaces. The returned network
|
||||
// settings will be used for container infos (inspect and such), as well as
|
||||
// iptables rules for port publishing.
|
||||
_, sinfo, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Add interfaces to the namespace.
|
||||
for _, iface := range sinfo.Interfaces {
|
||||
if err := networkNamespace.AddInterface(iface); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Set the gateway IP
|
||||
if err := networkNamespace.SetGateway(sinfo.Gateway); err != nil {
|
||||
return
|
||||
}
|
||||
*/
|
||||
package libnetwork
|
||||
|
||||
// Interface represents the settings and identity of a network device. It is
|
||||
// used as a return type for Network.Link, and it is common practice for the
|
||||
// caller to use this information when moving interface SrcName from host
|
||||
// namespace to DstName in a different net namespace with the appropriate
|
||||
// network settings.
|
||||
type Interface struct {
|
||||
// The name of the interface in the origin network namespace.
|
||||
SrcName string
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
// The name that will be assigned to the interface once moves inside a
|
||||
// network namespace.
|
||||
DstName string
|
||||
"github.com/docker/docker/pkg/common"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
)
|
||||
|
||||
// IPv4 address for the interface.
|
||||
Address string
|
||||
|
||||
// IPv6 address for the interface.
|
||||
AddressIPv6 string
|
||||
|
||||
// IPv4 gateway for the interface.
|
||||
Gateway string
|
||||
|
||||
// IPv6 gateway for the interface.
|
||||
GatewayIPv6 string
|
||||
// NetworkController provides the interface for controller instance which manages
|
||||
// networks.
|
||||
type NetworkController interface {
|
||||
// Create a new network. The options parameter carry driver specific options.
|
||||
// Labels support will be added in the near future.
|
||||
NewNetwork(networkType, name string, options interface{}) (Network, error)
|
||||
}
|
||||
|
||||
// A Network represents a logical connectivity zone that containers may
|
||||
|
@ -64,42 +65,176 @@ type Network interface {
|
|||
// A user chosen name for this network.
|
||||
Name() string
|
||||
|
||||
// A system generated id for this network.
|
||||
ID() string
|
||||
|
||||
// The type of network, which corresponds to its managing driver.
|
||||
Type() string
|
||||
|
||||
// Create a new link to this network symbolically identified by the
|
||||
// specified unique name.
|
||||
Link(name string) ([]*Interface, error)
|
||||
// Create a new endpoint to this network symbolically identified by the
|
||||
// specified unique name. The options parameter carry driver specific options.
|
||||
// Labels support will be added in the near future.
|
||||
CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, *driverapi.SandboxInfo, error)
|
||||
|
||||
// Delete the network.
|
||||
Delete() error
|
||||
}
|
||||
|
||||
// Namespace represents a network namespace, mounted on a specific Path. It
|
||||
// holds a list of Interface, and more can be added dynamically.
|
||||
type Namespace interface {
|
||||
// The path where the network namespace is mounted.
|
||||
Path() string
|
||||
// Endpoint represents a logical connection between a network and a sandbox.
|
||||
type Endpoint interface {
|
||||
// Delete endpoint.
|
||||
Delete() error
|
||||
}
|
||||
|
||||
// The collection of Interface previously added with the AddInterface
|
||||
// method. Note that this doesn't incude network interfaces added in any
|
||||
// other way (such as the default loopback interface existing in any newly
|
||||
// created network namespace).
|
||||
Interfaces() []*Interface
|
||||
type endpoint struct {
|
||||
name string
|
||||
id driverapi.UUID
|
||||
network *network
|
||||
sandboxInfo *driverapi.SandboxInfo
|
||||
}
|
||||
|
||||
// Add an existing Interface to this namespace. The operation will rename
|
||||
// from the Interface SrcName to DstName as it moves, and reconfigure the
|
||||
// interface according to the specified settings.
|
||||
AddInterface(*Interface) error
|
||||
type network struct {
|
||||
ctrlr *controller
|
||||
name string
|
||||
networkType string
|
||||
id driverapi.UUID
|
||||
endpoints map[driverapi.UUID]*endpoint
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type networkTable map[driverapi.UUID]*network
|
||||
|
||||
type controller struct {
|
||||
networks networkTable
|
||||
drivers driverTable
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
// New creates a new instance of network controller.
|
||||
func New() NetworkController {
|
||||
return &controller{networkTable{}, enumerateDrivers(), sync.Mutex{}}
|
||||
}
|
||||
|
||||
// NewNetwork creates a new network of the specified networkType. The options
|
||||
// are driver specific and modeled in a generic way.
|
||||
func NewNetwork(networkType, name string, options DriverParams) (Network, error) {
|
||||
return createNetwork(networkType, name, options)
|
||||
func (c *controller) NewNetwork(networkType, name string, options interface{}) (Network, error) {
|
||||
network := &network{name: name, networkType: networkType}
|
||||
network.id = driverapi.UUID(common.GenerateRandomID())
|
||||
network.ctrlr = c
|
||||
|
||||
d, ok := c.drivers[networkType]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown driver %q", networkType)
|
||||
}
|
||||
|
||||
if err := d.CreateNetwork(network.id, options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
c.networks[network.id] = network
|
||||
c.Unlock()
|
||||
|
||||
return network, nil
|
||||
}
|
||||
|
||||
// NewNetworkNamespace creates a new network namespace mounted on the specified
|
||||
// path.
|
||||
func NewNetworkNamespace(path string) (Namespace, error) {
|
||||
return createNetworkNamespace(path)
|
||||
func (n *network) Name() string {
|
||||
return n.name
|
||||
}
|
||||
|
||||
func (n *network) ID() string {
|
||||
return string(n.id)
|
||||
}
|
||||
|
||||
func (n *network) Type() string {
|
||||
return n.networkType
|
||||
}
|
||||
|
||||
func (n *network) Delete() error {
|
||||
var err error
|
||||
|
||||
d, ok := n.ctrlr.drivers[n.networkType]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown driver %q", n.networkType)
|
||||
}
|
||||
|
||||
n.ctrlr.Lock()
|
||||
_, ok = n.ctrlr.networks[n.id]
|
||||
if !ok {
|
||||
n.ctrlr.Unlock()
|
||||
return fmt.Errorf("unknown network %s id %s", n.name, n.id)
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
numEps := len(n.endpoints)
|
||||
n.Unlock()
|
||||
if numEps != 0 {
|
||||
n.ctrlr.Unlock()
|
||||
return fmt.Errorf("network %s has active endpoints", n.id)
|
||||
}
|
||||
|
||||
delete(n.ctrlr.networks, n.id)
|
||||
n.ctrlr.Unlock()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
n.ctrlr.Lock()
|
||||
n.ctrlr.networks[n.id] = n
|
||||
n.ctrlr.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
err = d.DeleteNetwork(n.id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *network) CreateEndpoint(name string, sboxKey string, options interface{}) (Endpoint, *driverapi.SandboxInfo, error) {
|
||||
ep := &endpoint{name: name}
|
||||
ep.id = driverapi.UUID(common.GenerateRandomID())
|
||||
ep.network = n
|
||||
|
||||
d, ok := n.ctrlr.drivers[n.networkType]
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("unknown driver %q", n.networkType)
|
||||
}
|
||||
|
||||
sinfo, err := d.CreateEndpoint(n.id, ep.id, sboxKey, options)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ep.sandboxInfo = sinfo
|
||||
n.Lock()
|
||||
n.endpoints[ep.id] = ep
|
||||
n.Unlock()
|
||||
return ep, sinfo, nil
|
||||
}
|
||||
|
||||
func (ep *endpoint) Delete() error {
|
||||
var err error
|
||||
|
||||
d, ok := ep.network.ctrlr.drivers[ep.network.networkType]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown driver %q", ep.network.networkType)
|
||||
}
|
||||
|
||||
n := ep.network
|
||||
n.Lock()
|
||||
_, ok = n.endpoints[ep.id]
|
||||
if !ok {
|
||||
n.Unlock()
|
||||
return fmt.Errorf("unknown endpoint %s id %s", ep.name, ep.id)
|
||||
}
|
||||
|
||||
delete(n.endpoints, ep.id)
|
||||
n.Unlock()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
n.Lock()
|
||||
n.endpoints[ep.id] = ep
|
||||
n.Unlock()
|
||||
}
|
||||
}()
|
||||
|
||||
err = d.DeleteEndpoint(n.id, ep.id)
|
||||
return err
|
||||
}
|
||||
|
|
66
libnetwork/sandbox/configure_linux.go
Normal file
66
libnetwork/sandbox/configure_linux.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
package sandbox
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func configureInterface(iface netlink.Link, settings *driverapi.Interface) error {
|
||||
ifaceName := iface.Attrs().Name
|
||||
ifaceConfigurators := []struct {
|
||||
Fn func(netlink.Link, *driverapi.Interface) error
|
||||
ErrMessage string
|
||||
}{
|
||||
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, settings.DstName)},
|
||||
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, settings.Address)},
|
||||
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, settings.AddressIPv6)},
|
||||
/* {setInterfaceGateway, fmt.Sprintf("error setting interface %q gateway to %q", ifaceName, settings.Gateway)},
|
||||
{setInterfaceGatewayIPv6, fmt.Sprintf("error setting interface %q IPv6 gateway to %q", ifaceName, settings.GatewayIPv6)}, */
|
||||
}
|
||||
|
||||
for _, config := range ifaceConfigurators {
|
||||
if err := config.Fn(iface, settings); err != nil {
|
||||
return fmt.Errorf("%s: %v", config.ErrMessage, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setGatewayIP(gw string) error {
|
||||
ip := net.ParseIP(gw)
|
||||
if ip == nil {
|
||||
return fmt.Errorf("bad address format %q", gw)
|
||||
}
|
||||
|
||||
return netlink.RouteAdd(&netlink.Route{
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
Gw: ip,
|
||||
})
|
||||
}
|
||||
|
||||
func setInterfaceIP(iface netlink.Link, settings *driverapi.Interface) error {
|
||||
ipAddr, err := netlink.ParseAddr(settings.Address)
|
||||
if err == nil {
|
||||
err = netlink.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setInterfaceIPv6(iface netlink.Link, settings *driverapi.Interface) error {
|
||||
if settings.AddressIPv6 == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
ipAddr, err := netlink.ParseAddr(settings.AddressIPv6)
|
||||
if err == nil {
|
||||
err = netlink.AddrAdd(iface, ipAddr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setInterfaceName(iface netlink.Link, settings *driverapi.Interface) error {
|
||||
return netlink.LinkSetName(iface, settings.DstName)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package libnetwork
|
||||
package sandbox
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -6,19 +6,26 @@ import (
|
|||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/vishvananda/netlink"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
// The networkNamespace type is the default implementation of the Namespace
|
||||
// interface. It simply creates a new network namespace, and moves an interface
|
||||
// into it when called on method AddInterface.
|
||||
// The networkNamespace type is the linux implementation of the Sandbox
|
||||
// interface. It represents a linux network namespace, and moves an interface
|
||||
// into it when called on method AddInterface or sets the gateway etc.
|
||||
type networkNamespace struct {
|
||||
path string
|
||||
interfaces []*Interface
|
||||
path string
|
||||
sinfo *driverapi.SandboxInfo
|
||||
}
|
||||
|
||||
func createNetworkNamespace(path string) (Namespace, error) {
|
||||
// NewSandbox provides a new sandbox instance created in an os specific way
|
||||
// provided a key which uniquely identifies the sandbox
|
||||
func NewSandbox(key string) (Sandbox, error) {
|
||||
return createNetworkNamespace(key)
|
||||
}
|
||||
|
||||
func createNetworkNamespace(path string) (Sandbox, error) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
|
@ -66,7 +73,7 @@ func loopbackUp() error {
|
|||
return netlink.LinkSetUp(iface)
|
||||
}
|
||||
|
||||
func (n *networkNamespace) AddInterface(i *Interface) error {
|
||||
func (n *networkNamespace) AddInterface(i *driverapi.Interface) error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
|
@ -109,15 +116,33 @@ func (n *networkNamespace) AddInterface(i *Interface) error {
|
|||
return err
|
||||
}
|
||||
|
||||
n.interfaces = append(n.interfaces, i)
|
||||
n.sinfo.Interfaces = append(n.sinfo.Interfaces, i)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Interfaces() []*Interface {
|
||||
return n.interfaces
|
||||
func (n *networkNamespace) SetGateway(gw string) error {
|
||||
err := setGatewayIP(gw)
|
||||
if err == nil {
|
||||
n.sinfo.Gateway = gw
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Path() string {
|
||||
func (n *networkNamespace) SetGatewayIPv6(gw string) error {
|
||||
err := setGatewayIP(gw)
|
||||
if err == nil {
|
||||
n.sinfo.GatewayIPv6 = gw
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Interfaces() []*driverapi.Interface {
|
||||
return n.sinfo.Interfaces
|
||||
}
|
||||
|
||||
func (n *networkNamespace) Key() string {
|
||||
return n.path
|
||||
}
|
||||
|
25
libnetwork/sandbox/sandbox.go
Normal file
25
libnetwork/sandbox/sandbox.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package sandbox
|
||||
|
||||
import "github.com/docker/libnetwork/driverapi"
|
||||
|
||||
// Sandbox represents a network sandbox, identified by a specific key. It
|
||||
// holds a list of Interfaces, routes etc, and more can be added dynamically.
|
||||
type Sandbox interface {
|
||||
// The path where the network namespace is mounted.
|
||||
Key() string
|
||||
|
||||
// The collection of Interface previously added with the AddInterface
|
||||
// method. Note that this doesn't incude network interfaces added in any
|
||||
// other way (such as the default loopback interface which are automatically
|
||||
// created on creation of a sandbox).
|
||||
Interfaces() []*driverapi.Interface
|
||||
|
||||
// Add an existing Interface to this sandbox. The operation will rename
|
||||
// from the Interface SrcName to DstName as it moves, and reconfigure the
|
||||
// interface according to the specified settings.
|
||||
AddInterface(*driverapi.Interface) error
|
||||
|
||||
SetGateway(gw string) error
|
||||
|
||||
SetGatewayIPv6(gw string) error
|
||||
}
|
54
libnetwork/sandbox/sandbox_linux_test.go
Normal file
54
libnetwork/sandbox/sandbox_linux_test.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package sandbox
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libcontainer/utils"
|
||||
"github.com/vishvananda/netns"
|
||||
)
|
||||
|
||||
func newKey(t *testing.T) (string, error) {
|
||||
name, err := utils.GenerateRandomName("netns", 12)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
name = filepath.Join("/tmp", name)
|
||||
if _, err := os.Create(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func verifySandbox(t *testing.T, s Sandbox) {
|
||||
_, ok := s.(*networkNamespace)
|
||||
if !ok {
|
||||
t.Fatalf("The sandox interface returned is not of type networkNamespace")
|
||||
}
|
||||
|
||||
origns, err := netns.Get()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not get the current netns: %v", err)
|
||||
}
|
||||
defer origns.Close()
|
||||
|
||||
f, err := os.OpenFile(s.Key(), os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed top open network namespace path %q: %v", s.Key(), err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
nsFD := f.Fd()
|
||||
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
|
||||
t.Fatalf("Setting to the namespace pointed to by the sandbox %s failed: %v", s.Key(), err)
|
||||
}
|
||||
|
||||
netns.Set(origns)
|
||||
}
|
21
libnetwork/sandbox/sandbox_test.go
Normal file
21
libnetwork/sandbox/sandbox_test.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package sandbox
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSandboxCreate(t *testing.T) {
|
||||
key, err := newKey(t)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to obtain a key: %v", err)
|
||||
}
|
||||
|
||||
s, err := NewSandbox(key)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a new sandbox: %v", err)
|
||||
}
|
||||
|
||||
if s.Key() != key {
|
||||
t.Fatalf("s.Key() returned %s. Expected %s", s.Key(), key)
|
||||
}
|
||||
|
||||
verifySandbox(t, s)
|
||||
}
|
Loading…
Reference in a new issue