1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Vendor-in 2baa2ddc78b42f011f55633282ac63a72e1b09c1 for userns support

Changes include :
* libnetwork support for userns
* driver api change to have 1 interface per endpoint

Signed-off-by: Madhu Venugopal <madhu@docker.com>
This commit is contained in:
Madhu Venugopal 2015-09-14 11:04:12 -07:00
parent d25dada639
commit d0e0c13b60
25 changed files with 490 additions and 246 deletions

View file

@ -580,13 +580,11 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet
return networkSettings, nil return networkSettings, nil
} }
ifaceList := epInfo.InterfaceList() iface := epInfo.Iface()
if len(ifaceList) == 0 { if iface == nil {
return networkSettings, nil return networkSettings, nil
} }
iface := ifaceList[0]
ones, _ := iface.Address().Mask.Size() ones, _ := iface.Address().Mask.Size()
networkSettings.IPAddress = iface.Address().IP.String() networkSettings.IPAddress = iface.Address().IP.String()
networkSettings.IPPrefixLen = ones networkSettings.IPPrefixLen = ones
@ -597,24 +595,6 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet
networkSettings.GlobalIPv6PrefixLen = onesv6 networkSettings.GlobalIPv6PrefixLen = onesv6
} }
if len(ifaceList) == 1 {
return networkSettings, nil
}
networkSettings.SecondaryIPAddresses = make([]network.Address, 0, len(ifaceList)-1)
networkSettings.SecondaryIPv6Addresses = make([]network.Address, 0, len(ifaceList)-1)
for _, iface := range ifaceList[1:] {
ones, _ := iface.Address().Mask.Size()
addr := network.Address{Addr: iface.Address().IP.String(), PrefixLen: ones}
networkSettings.SecondaryIPAddresses = append(networkSettings.SecondaryIPAddresses, addr)
if iface.AddressIPv6().IP.To16() != nil {
onesv6, _ := iface.AddressIPv6().Mask.Size()
addrv6 := network.Address{Addr: iface.AddressIPv6().IP.String(), PrefixLen: onesv6}
networkSettings.SecondaryIPv6Addresses = append(networkSettings.SecondaryIPv6Addresses, addrv6)
}
}
return networkSettings, nil return networkSettings, nil
} }

View file

@ -820,9 +820,9 @@ func (daemon *Daemon) Shutdown() error {
} }
group.Wait() group.Wait()
// trigger libnetwork GC only if it's initialized // trigger libnetwork Stop only if it's initialized
if daemon.netController != nil { if daemon.netController != nil {
daemon.netController.GC() daemon.netController.Stop()
} }
} }

View file

@ -20,7 +20,7 @@ clone git github.com/tchap/go-patricia v2.1.0
clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
#get libnetwork packages #get libnetwork packages
clone git github.com/docker/libnetwork 3e31cead05cba8ec20241630d051e6d73765b3a2 clone git github.com/docker/libnetwork 2baa2ddc78b42f011f55633282ac63a72e1b09c1
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4

View file

@ -4,6 +4,7 @@
*.so *.so
# Folders # Folders
integration-tmp/
_obj _obj
_test _test

View file

@ -1,4 +1,4 @@
.PHONY: all all-local build build-local check check-code check-format run-tests check-local install-deps coveralls circle-ci .PHONY: all all-local build build-local check check-code check-format run-tests check-local integration-tests install-deps coveralls circle-ci
SHELL=/bin/bash SHELL=/bin/bash
build_image=libnetwork-build build_image=libnetwork-build
dockerargs = --privileged -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork dockerargs = --privileged -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork
@ -7,8 +7,15 @@ docker = docker run --rm -it ${dockerargs} ${container_env} ${build_image}
ciargs = -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=-incontainer=true" ciargs = -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=-incontainer=true"
cidocker = docker run ${ciargs} ${dockerargs} golang:1.4 cidocker = docker run ${ciargs} ${dockerargs} golang:1.4
all: ${build_image}.created all: ${build_image}.created build check integration-tests
${docker} ./wrapmake.sh all-local
integration-tests:
@if [ ! -d ./integration-tmp ]; then \
mkdir -p ./integration-tmp; \
git clone https://github.com/sstephenson/bats.git ./integration-tmp/bats; \
./integration-tmp/bats/install.sh ./integration-tmp; \
fi
@./integration-tmp/bin/bats ./test/integration/dnet
all-local: check-local build-local all-local: check-local build-local
@ -19,13 +26,16 @@ ${build_image}.created:
touch ${build_image}.created touch ${build_image}.created
build: ${build_image}.created build: ${build_image}.created
${docker} ./wrapmake.sh build-local @echo "Building code... "
@${docker} ./wrapmake.sh build-local
@echo "Done building code"
build-local: build-local:
$(shell which godep) go build -tags libnetwork_discovery ./... @$(shell which godep) go build -tags libnetwork_discovery ./...
@$(shell which godep) go build -o ./cmd/dnet/dnet ./cmd/dnet
check: ${build_image}.created check: ${build_image}.created
${docker} ./wrapmake.sh check-local @${docker} ./wrapmake.sh check-local
check-code: check-code:
@echo "Checking code... " @echo "Checking code... "
@ -76,4 +86,5 @@ coveralls:
# The following target is a workaround for this # The following target is a workaround for this
circle-ci: circle-ci:
@${cidocker} make install-deps check-local coveralls @${cidocker} make install-deps build-local check-local coveralls
make integration-tests

View file

@ -249,6 +249,9 @@ func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
if sc.UseDefaultSandbox { if sc.UseDefaultSandbox {
setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox()) setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
} }
if sc.UseExternalKey {
setFctList = append(setFctList, libnetwork.OptionUseExternalKey())
}
if sc.DNS != nil { if sc.DNS != nil {
for _, d := range sc.DNS { for _, d := range sc.DNS {
setFctList = append(setFctList, libnetwork.OptionDNS(d)) setFctList = append(setFctList, libnetwork.OptionDNS(d))

View file

@ -57,6 +57,7 @@ type sandboxCreate struct {
DNS []string `json:"dns"` DNS []string `json:"dns"`
ExtraHosts []extraHost `json:"extra_hosts"` ExtraHosts []extraHost `json:"extra_hosts"`
UseDefaultSandbox bool `json:"use_default_sandbox"` UseDefaultSandbox bool `json:"use_default_sandbox"`
UseExternalKey bool `json:"use_external_key"`
} }
// endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages // endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages

View file

@ -115,7 +115,7 @@ func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) {
} }
func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) { func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) {
obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?container-id=%s", containerID), nil, nil)) obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?partial-container-id=%s", containerID), nil, nil))
if err != nil { if err != nil {
return "", err return "", err
} }
@ -360,12 +360,17 @@ func (cli *NetworkCli) CmdServiceDetach(chain string, args ...string) error {
return err return err
} }
sandboxID, err := lookupSandboxID(cli, containerID)
if err != nil {
return err
}
serviceID, err := lookupServiceID(cli, nn, sn) serviceID, err := lookupServiceID(cli, nn, sn)
if err != nil { if err != nil {
return err return err
} }
_, _, err = readBody(cli.call("DELETE", "/services/"+serviceID+"/backend/"+containerID, nil, nil)) _, _, err = readBody(cli.call("DELETE", "/services/"+serviceID+"/backend/"+sandboxID, nil, nil))
if err != nil { if err != nil {
return err return err
} }

View file

@ -109,7 +109,7 @@ func (c *Config) ProcessOptions(options ...Option) {
// IsValidName validates configuration objects supported by libnetwork // IsValidName validates configuration objects supported by libnetwork
func IsValidName(name string) bool { func IsValidName(name string) bool {
if name == "" || strings.Contains(name, ".") { if strings.TrimSpace(name) == "" || strings.Contains(name, ".") {
return false return false
} }
return true return true

View file

@ -65,6 +65,9 @@ import (
// NetworkController provides the interface for controller instance which manages // NetworkController provides the interface for controller instance which manages
// networks. // networks.
type NetworkController interface { type NetworkController interface {
// ID provides an unique identity for the controller
ID() string
// ConfigureNetworkDriver applies the passed options to the driver instance for the specified network type // ConfigureNetworkDriver applies the passed options to the driver instance for the specified network type
ConfigureNetworkDriver(networkType string, options map[string]interface{}) error ConfigureNetworkDriver(networkType string, options map[string]interface{}) error
@ -99,8 +102,8 @@ type NetworkController interface {
// SandboxByID returns the Sandbox which has the passed id. If not found, a types.NotFoundError is returned. // SandboxByID returns the Sandbox which has the passed id. If not found, a types.NotFoundError is returned.
SandboxByID(id string) (Sandbox, error) SandboxByID(id string) (Sandbox, error)
// GC triggers immediate garbage collection of resources which are garbage collected. // Stop network controller
GC() Stop()
} }
// NetworkWalker is a client provided function which will be used to walk the Networks. // NetworkWalker is a client provided function which will be used to walk the Networks.
@ -122,11 +125,13 @@ type endpointTable map[string]*endpoint
type sandboxTable map[string]*sandbox type sandboxTable map[string]*sandbox
type controller struct { type controller struct {
networks networkTable id string
drivers driverTable networks networkTable
sandboxes sandboxTable drivers driverTable
cfg *config.Config sandboxes sandboxTable
store datastore.DataStore cfg *config.Config
store datastore.DataStore
extKeyListener net.Listener
sync.Mutex sync.Mutex
} }
@ -138,6 +143,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
cfg.ProcessOptions(cfgOptions...) cfg.ProcessOptions(cfgOptions...)
} }
c := &controller{ c := &controller{
id: stringid.GenerateRandomID(),
cfg: cfg, cfg: cfg,
networks: networkTable{}, networks: networkTable{},
sandboxes: sandboxTable{}, sandboxes: sandboxTable{},
@ -159,9 +165,17 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
} }
} }
if err := c.startExternalKeyListener(); err != nil {
return nil, err
}
return c, nil return c, nil
} }
func (c *controller) ID() string {
return c.id
}
func (c *controller) validateHostDiscoveryConfig() bool { func (c *controller) validateHostDiscoveryConfig() bool {
if c.cfg == nil || c.cfg.Cluster.Discovery == "" || c.cfg.Cluster.Address == "" { if c.cfg == nil || c.cfg.Cluster.Discovery == "" || c.cfg.Cluster.Address == "" {
return false return false
@ -204,11 +218,11 @@ func (c *controller) ConfigureNetworkDriver(networkType string, options map[stri
} }
func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error { func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
c.Lock()
if !config.IsValidName(networkType) { if !config.IsValidName(networkType) {
c.Unlock()
return ErrInvalidName(networkType) return ErrInvalidName(networkType)
} }
c.Lock()
if _, ok := c.drivers[networkType]; ok { if _, ok := c.drivers[networkType]; ok {
c.Unlock() c.Unlock()
return driverapi.ErrActiveRegistration(networkType) return driverapi.ErrActiveRegistration(networkType)
@ -414,7 +428,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
return nil, err return nil, err
} }
if sb.osSbox == nil { if sb.osSbox == nil && !sb.config.useExternalKey {
if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil { if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil {
return nil, fmt.Errorf("failed to create new osl sandbox: %v", err) return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
} }
@ -514,6 +528,7 @@ func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) {
return false, nil return false, nil
} }
func (c *controller) GC() { func (c *controller) Stop() {
c.stopExternalKeyListener()
osl.GC() osl.GC()
} }

View file

@ -45,18 +45,16 @@ type Driver interface {
// EndpointInfo provides a go interface to fetch or populate endpoint assigned network resources. // EndpointInfo provides a go interface to fetch or populate endpoint assigned network resources.
type EndpointInfo interface { type EndpointInfo interface {
// Interfaces returns a list of interfaces bound to the endpoint. // Interface returns the interface bound to the endpoint.
// If the list is not empty the driver is only expected to consume the interfaces. // If the value is not nil the driver is only expected to consume the interface.
// It is an error to try to add interfaces to a non-empty list. // It is an error to try to add interface if the passed down value is non-nil
// If the list is empty the driver is expected to populate with 0 or more interfaces. // If the value is nil the driver is expected to add an interface
Interfaces() []InterfaceInfo Interface() InterfaceInfo
// AddInterface is used by the driver to add an interface to the interface list. // AddInterface is used by the driver to add an interface for the endpoint.
// This method will return an error if the driver attempts to add interfaces // This method will return an error if the driver attempts to add interface
// if the Interfaces() method returned a non-empty list. // if the Interface() method returned a non-nil value.
// ID field need only have significance within the endpoint so it can be a simple AddInterface(mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error
// monotonically increasing number
AddInterface(ID int, mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error
} }
// InterfaceInfo provides a go interface for drivers to retrive // InterfaceInfo provides a go interface for drivers to retrive
@ -70,10 +68,6 @@ type InterfaceInfo interface {
// AddressIPv6 returns the IPv6 address. // AddressIPv6 returns the IPv6 address.
AddressIPv6() net.IPNet AddressIPv6() net.IPNet
// ID returns the numerical id of the interface and has significance only within
// the endpoint.
ID() int
} }
// InterfaceNameInfo provides a go interface for the drivers to assign names // InterfaceNameInfo provides a go interface for the drivers to assign names
@ -81,18 +75,14 @@ type InterfaceInfo interface {
type InterfaceNameInfo interface { type InterfaceNameInfo interface {
// SetNames method assigns the srcName and dstPrefix for the interface. // SetNames method assigns the srcName and dstPrefix for the interface.
SetNames(srcName, dstPrefix string) error SetNames(srcName, dstPrefix string) error
// ID returns the numerical id that was assigned to the interface by the driver
// CreateEndpoint.
ID() int
} }
// JoinInfo represents a set of resources that the driver has the ability to provide during // JoinInfo represents a set of resources that the driver has the ability to provide during
// join time. // join time.
type JoinInfo interface { type JoinInfo interface {
// InterfaceNames returns a list of InterfaceNameInfo go interface to facilitate // InterfaceName returns a InterfaceNameInfo go interface to facilitate
// setting the names for the interfaces. // setting the names for the interface.
InterfaceNames() []InterfaceNameInfo InterfaceName() InterfaceNameInfo
// SetGateway sets the default IPv4 gateway when a container joins the endpoint. // SetGateway sets the default IPv4 gateway when a container joins the endpoint.
SetGateway(net.IP) error SetGateway(net.IP) error
@ -102,7 +92,7 @@ type JoinInfo interface {
// AddStaticRoute adds a routes to the sandbox. // AddStaticRoute adds a routes to the sandbox.
// It may be used in addtion to or instead of a default gateway (as above). // It may be used in addtion to or instead of a default gateway (as above).
AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP, interfaceID int) error AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error
} }
// DriverCallback provides a Callback interface for Drivers into LibNetwork // DriverCallback provides a Callback interface for Drivers into LibNetwork

View file

@ -32,7 +32,6 @@ const (
vethLen = 7 vethLen = 7
containerVethPrefix = "eth" containerVethPrefix = "eth"
maxAllocatePortAttempts = 10 maxAllocatePortAttempts = 10
ifaceID = 1
) )
var ( var (
@ -883,8 +882,8 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
return errors.New("invalid endpoint info passed") return errors.New("invalid endpoint info passed")
} }
if len(epInfo.Interfaces()) != 0 { if epInfo.Interface() != nil {
return errors.New("non empty interface list passed to bridge(local) driver") return errors.New("non-nil interface passed to bridge(local) driver")
} }
// Get the network handler and make sure it exists // Get the network handler and make sure it exists
@ -1070,7 +1069,7 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
endpoint.addrv6 = ipv6Addr endpoint.addrv6 = ipv6Addr
} }
err = epInfo.AddInterface(ifaceID, endpoint.macAddress, *ipv4Addr, *ipv6Addr) err = epInfo.AddInterface(endpoint.macAddress, *ipv4Addr, *ipv6Addr)
if err != nil { if err != nil {
return err return err
} }
@ -1244,14 +1243,10 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return EndpointNotFoundError(eid) return EndpointNotFoundError(eid)
} }
for _, iNames := range jinfo.InterfaceNames() { iNames := jinfo.InterfaceName()
// Make sure to set names on the correct interface ID. err = iNames.SetNames(endpoint.srcName, containerVethPrefix)
if iNames.ID() == ifaceID { if err != nil {
err = iNames.SetNames(endpoint.srcName, containerVethPrefix) return err
if err != nil {
return err
}
}
} }
err = jinfo.SetGateway(network.bridge.gatewayIPv4) err = jinfo.SetGateway(network.bridge.gatewayIPv4)

View file

@ -65,13 +65,10 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return fmt.Errorf("could not set mac address to the container interface: %v", err) return fmt.Errorf("could not set mac address to the container interface: %v", err)
} }
for _, iNames := range jinfo.InterfaceNames() { if iNames := jinfo.InterfaceName(); iNames != nil {
// Make sure to set names on the correct interface ID. err = iNames.SetNames(name2, "eth")
if iNames.ID() == 1 { if err != nil {
err = iNames.SetNames(name2, "eth") return err
if err != nil {
return err
}
} }
} }

View file

@ -51,10 +51,10 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
id: eid, id: eid,
} }
if epInfo != nil && (len(epInfo.Interfaces()) > 0) { if epInfo != nil && epInfo.Interface() != nil {
addr := epInfo.Interfaces()[0].Address() addr := epInfo.Interface().Address()
ep.addr = &addr ep.addr = &addr
ep.mac = epInfo.Interfaces()[0].MacAddress() ep.mac = epInfo.Interface().MacAddress()
n.addEndpoint(ep) n.addEndpoint(ep)
return nil return nil
} }
@ -74,7 +74,7 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
ep.mac = netutils.GenerateMACFromIP(ep.addr.IP) ep.mac = netutils.GenerateMACFromIP(ep.addr.IP)
err = epInfo.AddInterface(1, ep.mac, *ep.addr, net.IPNet{}) err = epInfo.AddInterface(ep.mac, *ep.addr, net.IPNet{})
if err != nil { if err != nil {
return fmt.Errorf("could not add interface to endpoint info: %v", err) return fmt.Errorf("could not add interface to endpoint info: %v", err)
} }

View file

@ -48,13 +48,12 @@ type CreateEndpointRequest struct {
NetworkID string NetworkID string
// The ID of the endpoint for later reference. // The ID of the endpoint for later reference.
EndpointID string EndpointID string
Interfaces []*EndpointInterface Interface *EndpointInterface
Options map[string]interface{} Options map[string]interface{}
} }
// EndpointInterface represents an interface endpoint. // EndpointInterface represents an interface endpoint.
type EndpointInterface struct { type EndpointInterface struct {
ID int
Address string Address string
AddressIPv6 string AddressIPv6 string
MacAddress string MacAddress string
@ -63,12 +62,11 @@ type EndpointInterface struct {
// CreateEndpointResponse is the response to the CreateEndpoint action. // CreateEndpointResponse is the response to the CreateEndpoint action.
type CreateEndpointResponse struct { type CreateEndpointResponse struct {
Response Response
Interfaces []*EndpointInterface Interface *EndpointInterface
} }
// Interface is the representation of a linux interface. // Interface is the representation of a linux interface.
type Interface struct { type Interface struct {
ID int
Address *net.IPNet Address *net.IPNet
AddressIPv6 *net.IPNet AddressIPv6 *net.IPNet
MacAddress net.HardwareAddr MacAddress net.HardwareAddr
@ -118,16 +116,15 @@ type StaticRoute struct {
Destination string Destination string
RouteType int RouteType int
NextHop string NextHop string
InterfaceID int
} }
// JoinResponse is the response to a JoinRequest. // JoinResponse is the response to a JoinRequest.
type JoinResponse struct { type JoinResponse struct {
Response Response
InterfaceNames []*InterfaceName InterfaceName *InterfaceName
Gateway string Gateway string
GatewayIPv6 string GatewayIPv6 string
StaticRoutes []StaticRoute StaticRoutes []StaticRoute
} }
// LeaveRequest describes the API for detaching an endpoint from a sandbox. // LeaveRequest describes the API for detaching an endpoint from a sandbox.

View file

@ -71,16 +71,17 @@ func (d *driver) DeleteNetwork(nid string) error {
} }
func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error { func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
var reqIface *api.EndpointInterface
if epInfo == nil { if epInfo == nil {
return fmt.Errorf("must not be called with nil EndpointInfo") return fmt.Errorf("must not be called with nil EndpointInfo")
} }
reqIfaces := make([]*api.EndpointInterface, len(epInfo.Interfaces())) iface := epInfo.Interface()
for i, iface := range epInfo.Interfaces() { if iface != nil {
addr4 := iface.Address() addr4 := iface.Address()
addr6 := iface.AddressIPv6() addr6 := iface.AddressIPv6()
reqIfaces[i] = &api.EndpointInterface{ reqIface = &api.EndpointInterface{
ID: iface.ID(),
Address: addr4.String(), Address: addr4.String(),
AddressIPv6: addr6.String(), AddressIPv6: addr6.String(),
MacAddress: iface.MacAddress().String(), MacAddress: iface.MacAddress().String(),
@ -89,7 +90,7 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
create := &api.CreateEndpointRequest{ create := &api.CreateEndpointRequest{
NetworkID: nid, NetworkID: nid,
EndpointID: eid, EndpointID: eid,
Interfaces: reqIfaces, Interface: reqIface,
Options: epOptions, Options: epOptions,
} }
var res api.CreateEndpointResponse var res api.CreateEndpointResponse
@ -97,25 +98,26 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
return err return err
} }
ifaces, err := parseInterfaces(res) inIface, err := parseInterface(res)
if err != nil { if err != nil {
return err return err
} }
if len(reqIfaces) > 0 && len(ifaces) > 0 { if reqIface != nil && inIface != nil {
// We're not supposed to add interfaces if there already are // We're not supposed to add interface if there is already
// some. Attempt to roll back // one. Attempt to roll back
return errorWithRollback("driver attempted to add more interfaces", d.DeleteEndpoint(nid, eid)) return errorWithRollback("driver attempted to add interface ignoring the one provided", d.DeleteEndpoint(nid, eid))
} }
for _, iface := range ifaces {
if inIface != nil {
var addr4, addr6 net.IPNet var addr4, addr6 net.IPNet
if iface.Address != nil { if inIface.Address != nil {
addr4 = *(iface.Address) addr4 = *(inIface.Address)
} }
if iface.AddressIPv6 != nil { if inIface.AddressIPv6 != nil {
addr6 = *(iface.AddressIPv6) addr6 = *(inIface.AddressIPv6)
} }
if err := epInfo.AddInterface(iface.ID, iface.MacAddress, addr4, addr6); err != nil { if err := epInfo.AddInterface(inIface.MacAddress, addr4, addr6); err != nil {
return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", iface, err), d.DeleteEndpoint(nid, eid)) return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", inIface, err), d.DeleteEndpoint(nid, eid))
} }
} }
return nil return nil
@ -165,18 +167,13 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return err return err
} }
// Expect each interface ID given by CreateEndpoint to have an ifaceName := res.InterfaceName
// entry at that index in the names supplied here. In other words, if ifaceName == nil {
// if you supply 0..n interfaces with IDs 0..n above, you should return fmt.Errorf("no interface name information received")
// supply the names in the same order. }
ifaceNames := res.InterfaceNames
for _, iface := range jinfo.InterfaceNames() { if iface := jinfo.InterfaceName(); iface != nil {
i := iface.ID() if err := iface.SetNames(ifaceName.SrcName, ifaceName.DstPrefix); err != nil {
if i >= len(ifaceNames) || i < 0 {
return fmt.Errorf("no correlating interface %d in supplied interface names", i)
}
supplied := ifaceNames[i]
if err := iface.SetNames(supplied.SrcName, supplied.DstPrefix); err != nil {
return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid)) return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid))
} }
} }
@ -204,7 +201,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return err return err
} }
for _, route := range routes { for _, route := range routes {
if jinfo.AddStaticRoute(route.Destination, route.RouteType, route.NextHop, route.InterfaceID) != nil { if jinfo.AddStaticRoute(route.Destination, route.RouteType, route.NextHop) != nil {
return errorWithRollback(fmt.Sprintf("failed to set static route: %v", route), d.Leave(nid, eid)) return errorWithRollback(fmt.Sprintf("failed to set static route: %v", route), d.Leave(nid, eid))
} }
} }
@ -229,7 +226,7 @@ func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
var routes = make([]*types.StaticRoute, len(r.StaticRoutes)) var routes = make([]*types.StaticRoute, len(r.StaticRoutes))
for i, inRoute := range r.StaticRoutes { for i, inRoute := range r.StaticRoutes {
var err error var err error
outRoute := &types.StaticRoute{InterfaceID: inRoute.InterfaceID, RouteType: inRoute.RouteType} outRoute := &types.StaticRoute{RouteType: inRoute.RouteType}
if inRoute.Destination != "" { if inRoute.Destination != "" {
if outRoute.Destination, err = toAddr(inRoute.Destination); err != nil { if outRoute.Destination, err = toAddr(inRoute.Destination); err != nil {
@ -250,13 +247,13 @@ func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
} }
// parseInterfaces validates all the parameters of an Interface and returns them. // parseInterfaces validates all the parameters of an Interface and returns them.
func parseInterfaces(r api.CreateEndpointResponse) ([]*api.Interface, error) { func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) {
var ( var outIf *api.Interface
Interfaces = make([]*api.Interface, len(r.Interfaces))
) inIf := r.Interface
for i, inIf := range r.Interfaces { if inIf != nil {
var err error var err error
outIf := &api.Interface{ID: inIf.ID} outIf = &api.Interface{}
if inIf.Address != "" { if inIf.Address != "" {
if outIf.Address, err = toAddr(inIf.Address); err != nil { if outIf.Address, err = toAddr(inIf.Address); err != nil {
return nil, err return nil, err
@ -272,9 +269,9 @@ func parseInterfaces(r api.CreateEndpointResponse) ([]*api.Interface, error) {
return nil, err return nil, err
} }
} }
Interfaces[i] = outIf
} }
return Interfaces, nil
return outIf, nil
} }
func toAddr(ipAddr string) (*net.IPNet, error) { func toAddr(ipAddr string) (*net.IPNet, error) {

View file

@ -1,6 +1,7 @@
package libnetwork package libnetwork
import ( import (
"container/heap"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net" "net"
@ -49,7 +50,7 @@ type endpoint struct {
name string name string
id string id string
network *network network *network
iFaces []*endpointInterface iface *endpointInterface
joinInfo *endpointJoinInfo joinInfo *endpointJoinInfo
sandboxID string sandboxID string
exposedPorts []types.TransportPort exposedPorts []types.TransportPort
@ -67,7 +68,7 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
epMap := make(map[string]interface{}) epMap := make(map[string]interface{})
epMap["name"] = ep.name epMap["name"] = ep.name
epMap["id"] = ep.id epMap["id"] = ep.id
epMap["ep_iface"] = ep.iFaces epMap["ep_iface"] = ep.iface
epMap["exposed_ports"] = ep.exposedPorts epMap["exposed_ports"] = ep.exposedPorts
epMap["generic"] = ep.generic epMap["generic"] = ep.generic
epMap["sandbox"] = ep.sandboxID epMap["sandbox"] = ep.sandboxID
@ -86,12 +87,7 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
ep.id = epMap["id"].(string) ep.id = epMap["id"].(string)
ib, _ := json.Marshal(epMap["ep_iface"]) ib, _ := json.Marshal(epMap["ep_iface"])
var ifaces []endpointInterface json.Unmarshal(ib, ep.iface)
json.Unmarshal(ib, &ifaces)
ep.iFaces = make([]*endpointInterface, 0)
for _, iface := range ifaces {
ep.iFaces = append(ep.iFaces, &iface)
}
tb, _ := json.Marshal(epMap["exposed_ports"]) tb, _ := json.Marshal(epMap["exposed_ports"])
var tPorts []types.TransportPort var tPorts []types.TransportPort
@ -289,10 +285,25 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
return err return err
} }
sb.Lock()
heap.Push(&sb.endpoints, ep)
sb.Unlock()
defer func() {
if err != nil {
for i, e := range sb.getConnectedEndpoints() {
if e == ep {
sb.Lock()
heap.Remove(&sb.endpoints, i)
sb.Unlock()
return
}
}
}
}()
if err = sb.populateNetworkResources(ep); err != nil { if err = sb.populateNetworkResources(ep); err != nil {
return err return err
} }
return nil return nil
} }
@ -300,13 +311,7 @@ func (ep *endpoint) hasInterface(iName string) bool {
ep.Lock() ep.Lock()
defer ep.Unlock() defer ep.Unlock()
for _, iface := range ep.iFaces { return ep.iface != nil && ep.iface.srcName == iName
if iface.srcName == iName {
return true
}
}
return false
} }
func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error { func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
@ -463,8 +468,8 @@ func (ep *endpoint) getFirstInterfaceAddress() net.IP {
ep.Lock() ep.Lock()
defer ep.Unlock() defer ep.Unlock()
if len(ep.iFaces) != 0 && ep.iFaces[0] != nil { if ep.iface != nil {
return ep.iFaces[0].addr.IP return ep.iface.addr.IP
} }
return nil return nil

View file

@ -10,9 +10,11 @@ import (
// EndpointInfo provides an interface to retrieve network resources bound to the endpoint. // EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
type EndpointInfo interface { type EndpointInfo interface {
// InterfaceList returns an interface list which were assigned to the endpoint // Iface returns InterfaceInfo, go interface that can be used
// by the driver. This can be used after the endpoint has been created. // to get more information on the interface which was assigned to
InterfaceList() []InterfaceInfo // the endpoint by the driver. This can be used after the
// endpoint has been created.
Iface() InterfaceInfo
// Gateway returns the IPv4 gateway assigned by the driver. // Gateway returns the IPv4 gateway assigned by the driver.
// This will only return a valid value if a container has joined the endpoint. // This will only return a valid value if a container has joined the endpoint.
@ -39,7 +41,6 @@ type InterfaceInfo interface {
} }
type endpointInterface struct { type endpointInterface struct {
id int
mac net.HardwareAddr mac net.HardwareAddr
addr net.IPNet addr net.IPNet
addrv6 net.IPNet addrv6 net.IPNet
@ -50,7 +51,6 @@ type endpointInterface struct {
func (epi *endpointInterface) MarshalJSON() ([]byte, error) { func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
epMap := make(map[string]interface{}) epMap := make(map[string]interface{})
epMap["id"] = epi.id
epMap["mac"] = epi.mac.String() epMap["mac"] = epi.mac.String()
epMap["addr"] = epi.addr.String() epMap["addr"] = epi.addr.String()
epMap["addrv6"] = epi.addrv6.String() epMap["addrv6"] = epi.addrv6.String()
@ -69,7 +69,6 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
if err := json.Unmarshal(b, &epMap); err != nil { if err := json.Unmarshal(b, &epMap); err != nil {
return err return err
} }
epi.id = int(epMap["id"].(float64))
mac, _ := net.ParseMAC(epMap["mac"].(string)) mac, _ := net.ParseMAC(epMap["mac"].(string))
epi.mac = mac epi.mac = mac
@ -128,51 +127,42 @@ func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
return driver.EndpointOperInfo(nid, epid) return driver.EndpointOperInfo(nid, epid)
} }
func (ep *endpoint) InterfaceList() []InterfaceInfo { func (ep *endpoint) Iface() InterfaceInfo {
ep.Lock() ep.Lock()
defer ep.Unlock() defer ep.Unlock()
iList := make([]InterfaceInfo, len(ep.iFaces)) if ep.iface != nil {
return ep.iface
for i, iface := range ep.iFaces {
iList[i] = iface
} }
return iList return nil
} }
func (ep *endpoint) Interfaces() []driverapi.InterfaceInfo { func (ep *endpoint) Interface() driverapi.InterfaceInfo {
ep.Lock() ep.Lock()
defer ep.Unlock() defer ep.Unlock()
iList := make([]driverapi.InterfaceInfo, len(ep.iFaces)) if ep.iface != nil {
return ep.iface
for i, iface := range ep.iFaces {
iList[i] = iface
} }
return iList return nil
} }
func (ep *endpoint) AddInterface(id int, mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error { func (ep *endpoint) AddInterface(mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error {
ep.Lock() ep.Lock()
defer ep.Unlock() defer ep.Unlock()
iface := &endpointInterface{ iface := &endpointInterface{
id: id,
addr: *types.GetIPNetCopy(&ipv4), addr: *types.GetIPNetCopy(&ipv4),
addrv6: *types.GetIPNetCopy(&ipv6), addrv6: *types.GetIPNetCopy(&ipv6),
} }
iface.mac = types.GetMacCopy(mac) iface.mac = types.GetMacCopy(mac)
ep.iFaces = append(ep.iFaces, iface) ep.iface = iface
return nil return nil
} }
func (epi *endpointInterface) ID() int {
return epi.id
}
func (epi *endpointInterface) MacAddress() net.HardwareAddr { func (epi *endpointInterface) MacAddress() net.HardwareAddr {
return types.GetMacCopy(epi.mac) return types.GetMacCopy(epi.mac)
} }
@ -191,24 +181,22 @@ func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
return nil return nil
} }
func (ep *endpoint) InterfaceNames() []driverapi.InterfaceNameInfo { func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo {
ep.Lock() ep.Lock()
defer ep.Unlock() defer ep.Unlock()
iList := make([]driverapi.InterfaceNameInfo, len(ep.iFaces)) if ep.iface != nil {
return ep.iface
for i, iface := range ep.iFaces {
iList[i] = iface
} }
return iList return nil
} }
func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP, interfaceID int) error { func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
ep.Lock() ep.Lock()
defer ep.Unlock() defer ep.Unlock()
r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop, InterfaceID: interfaceID} r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop}
if routeType == types.NEXTHOP { if routeType == types.NEXTHOP {
// If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface). // If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
@ -223,14 +211,12 @@ func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHo
} }
func (ep *endpoint) addInterfaceRoute(route *types.StaticRoute) error { func (ep *endpoint) addInterfaceRoute(route *types.StaticRoute) error {
for _, iface := range ep.iFaces { ep.Lock()
if iface.id == route.InterfaceID { defer ep.Unlock()
iface.routes = append(iface.routes, route.Destination)
return nil iface := ep.iface
} iface.routes = append(iface.routes, route.Destination)
} return nil
return types.BadRequestErrorf("Interface with ID %d doesn't exist.",
route.InterfaceID)
} }
func (ep *endpoint) Sandbox() Sandbox { func (ep *endpoint) Sandbox() Sandbox {

View file

@ -305,7 +305,6 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
} }
ep := &endpoint{name: name, ep := &endpoint{name: name,
iFaces: []*endpointInterface{},
generic: make(map[string]interface{})} generic: make(map[string]interface{})}
ep.id = stringid.GenerateRandomID() ep.id = stringid.GenerateRandomID()
ep.network = n ep.network = n
@ -409,7 +408,7 @@ func (n *network) isGlobalScoped() (bool, error) {
func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) { func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
n.Lock() n.Lock()
var recs []etchosts.Record var recs []etchosts.Record
for _, iface := range ep.InterfaceList() { if iface := ep.Iface(); iface != nil {
if isAdd { if isAdd {
n.svcRecords[ep.Name()] = iface.Address().IP n.svcRecords[ep.Name()] = iface.Address().IP
n.svcRecords[ep.Name()+"."+n.name] = iface.Address().IP n.svcRecords[ep.Name()+"."+n.name] = iface.Address().IP

View file

@ -157,30 +157,43 @@ func (n *networkNamespace) NeighborOptions() NeighborOptionSetter {
return n return n
} }
func mountNetworkNamespace(basePath string, lnPath string) error {
if err := syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, ""); err != nil {
return err
}
if err := loopbackUp(); err != nil {
return err
}
return nil
}
// GetSandboxForExternalKey returns sandbox object for the supplied path
func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
var err error
if err = createNamespaceFile(key); err != nil {
return nil, err
}
n := &networkNamespace{path: basePath}
n.InvokeFunc(func() {
err = mountNetworkNamespace(basePath, key)
})
if err != nil {
return nil, err
}
return &networkNamespace{path: key}, nil
}
func reexecCreateNamespace() { func reexecCreateNamespace() {
if len(os.Args) < 2 { if len(os.Args) < 2 {
log.Fatal("no namespace path provided") log.Fatal("no namespace path provided")
} }
if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
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) log.Fatal(err)
} }
} }
func createNetworkNamespace(path string, osCreate bool) error { func createNetworkNamespace(path string, osCreate bool) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
origns, err := netns.Get()
if err != nil {
return err
}
defer origns.Close()
if err := createNamespaceFile(path); err != nil { if err := createNamespaceFile(path); err != nil {
return err return err
} }

View file

@ -6,3 +6,7 @@ package osl
// and waits for it. // and waits for it.
func GC() { func GC() {
} }
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
return nil, nil
}

View file

@ -19,6 +19,10 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
return nil, nil return nil, nil
} }
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
return nil, nil
}
// GC triggers garbage collection of namespace path right away // GC triggers garbage collection of namespace path right away
// and waits for it. // and waits for it.
func GC() { func GC() {

View file

@ -32,6 +32,8 @@ type Sandbox interface {
// Refresh leaves all the endpoints, resets and re-apply the options, // Refresh leaves all the endpoints, resets and re-apply the options,
// re-joins all the endpoints without destroying the osl sandbox // re-joins all the endpoints without destroying the osl sandbox
Refresh(options ...SandboxOption) error Refresh(options ...SandboxOption) error
// SetKey updates the Sandbox Key
SetKey(key string) error
// Delete destroys this container after detaching it from all connected endpoints. // Delete destroys this container after detaching it from all connected endpoints.
Delete() error Delete() error
} }
@ -102,6 +104,7 @@ type containerConfig struct {
resolvConfPathConfig resolvConfPathConfig
generic map[string]interface{} generic map[string]interface{}
useDefaultSandBox bool useDefaultSandBox bool
useExternalKey bool
prio int // higher the value, more the priority prio int // higher the value, more the priority
} }
@ -241,8 +244,14 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
} }
func (sb *sandbox) updateGateway(ep *endpoint) error { func (sb *sandbox) updateGateway(ep *endpoint) error {
sb.osSbox.UnsetGateway() sb.Lock()
sb.osSbox.UnsetGatewayIPv6() osSbox := sb.osSbox
sb.Unlock()
if osSbox == nil {
return nil
}
osSbox.UnsetGateway()
osSbox.UnsetGatewayIPv6()
if ep == nil { if ep == nil {
return nil return nil
@ -252,24 +261,66 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
joinInfo := ep.joinInfo joinInfo := ep.joinInfo
ep.Unlock() ep.Unlock()
if err := sb.osSbox.SetGateway(joinInfo.gw); err != nil { if err := osSbox.SetGateway(joinInfo.gw); err != nil {
return fmt.Errorf("failed to set gateway while updating gateway: %v", err) return fmt.Errorf("failed to set gateway while updating gateway: %v", err)
} }
if err := sb.osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil { if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil {
return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err) return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
} }
return nil return nil
} }
func (sb *sandbox) SetKey(basePath string) error {
var err error
if basePath == "" {
return types.BadRequestErrorf("invalid sandbox key")
}
sb.Lock()
if sb.osSbox != nil {
sb.Unlock()
return types.ForbiddenErrorf("failed to set sandbox key : already assigned")
}
sb.Unlock()
osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key())
if err != nil {
return err
}
sb.Lock()
sb.osSbox = osSbox
sb.Unlock()
defer func() {
if err != nil {
sb.Lock()
sb.osSbox = nil
sb.Unlock()
}
}()
for _, ep := range sb.getConnectedEndpoints() {
if err = sb.populateNetworkResources(ep); err != nil {
return err
}
}
return nil
}
func (sb *sandbox) populateNetworkResources(ep *endpoint) error { func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
sb.Lock()
if sb.osSbox == nil {
sb.Unlock()
return nil
}
sb.Unlock()
ep.Lock() ep.Lock()
joinInfo := ep.joinInfo joinInfo := ep.joinInfo
ifaces := ep.iFaces i := ep.iface
ep.Unlock() ep.Unlock()
for _, i := range ifaces { if i != nil {
var ifaceOptions []osl.IfaceOption var ifaceOptions []osl.IfaceOption
ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(&i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes)) ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(&i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes))
@ -292,7 +343,6 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
} }
sb.Lock() sb.Lock()
heap.Push(&sb.endpoints, ep)
highEp := sb.endpoints[0] highEp := sb.endpoints[0]
sb.Unlock() sb.Unlock()
if ep == highEp { if ep == highEp {
@ -305,24 +355,28 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
} }
func (sb *sandbox) clearNetworkResources(ep *endpoint) error { func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
sb.Lock()
for _, i := range sb.osSbox.Info().Interfaces() { osSbox := sb.osSbox
// Only remove the interfaces owned by this endpoint from the sandbox. sb.Unlock()
if ep.hasInterface(i.SrcName()) { if osSbox != nil {
if err := i.Remove(); err != nil { for _, i := range osSbox.Info().Interfaces() {
log.Debugf("Remove interface failed: %v", err) // Only remove the interfaces owned by this endpoint from the sandbox.
if ep.hasInterface(i.SrcName()) {
if err := i.Remove(); err != nil {
log.Debugf("Remove interface failed: %v", err)
}
} }
} }
}
ep.Lock() ep.Lock()
joinInfo := ep.joinInfo joinInfo := ep.joinInfo
ep.Unlock() ep.Unlock()
// Remove non-interface routes. // Remove non-interface routes.
for _, r := range joinInfo.StaticRoutes { for _, r := range joinInfo.StaticRoutes {
if err := sb.osSbox.RemoveStaticRoute(r); err != nil { if err := osSbox.RemoveStaticRoute(r); err != nil {
log.Debugf("Remove route failed: %v", err) log.Debugf("Remove route failed: %v", err)
}
} }
} }
@ -670,6 +724,14 @@ func OptionUseDefaultSandbox() SandboxOption {
} }
} }
// OptionUseExternalKey function returns an option setter for using provided namespace
// instead of creating one.
func OptionUseExternalKey() SandboxOption {
return func(sb *sandbox) {
sb.config.useExternalKey = true
}
}
// OptionGeneric function returns an option setter for Generic configuration // OptionGeneric function returns an option setter for Generic configuration
// that is not managed by libNetwork but can be used by the Drivers during the call to // that is not managed by libNetwork but can be used by the Drivers during the call to
// net container creation method. Container Labels are a good example. // net container creation method. Container Labels are a good example.

View file

@ -0,0 +1,185 @@
package libnetwork
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net"
"os"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/libnetwork/types"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/runc/libcontainer/configs"
)
type setKeyData struct {
ContainerID string
Key string
}
func init() {
reexec.Register("libnetwork-setkey", processSetKeyReexec)
}
const udsBase = "/var/lib/docker/network/files/"
const success = "success"
// processSetKeyReexec is a private function that must be called only on an reexec path
// It expects 3 args { [0] = "libnetwork-setkey", [1] = <container-id>, [2] = <controller-id> }
// It also expects libcontainer.State as a json string in <stdin>
// Refer to https://github.com/opencontainers/runc/pull/160/ for more information
func processSetKeyReexec() {
var err error
// Return a failure to the calling process via ExitCode
defer func() {
if err != nil {
logrus.Fatalf("%v", err)
}
}()
// expecting 3 args {[0]="libnetwork-setkey", [1]=<container-id>, [2]=<controller-id> }
if len(os.Args) < 3 {
err = fmt.Errorf("Re-exec expects 3 args, received : %d", len(os.Args))
return
}
containerID := os.Args[1]
// We expect libcontainer.State as a json string in <stdin>
stateBuf, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return
}
var state libcontainer.State
if err = json.Unmarshal(stateBuf, &state); err != nil {
return
}
controllerID := os.Args[2]
key := state.NamespacePaths[configs.NamespaceType("NEWNET")]
err = SetExternalKey(controllerID, containerID, key)
return
}
// SetExternalKey provides a convenient way to set an External key to a sandbox
func SetExternalKey(controllerID string, containerID string, key string) error {
keyData := setKeyData{
ContainerID: containerID,
Key: key}
c, err := net.Dial("unix", udsBase+controllerID+".sock")
if err != nil {
return err
}
defer c.Close()
if err = sendKey(c, keyData); err != nil {
return fmt.Errorf("sendKey failed with : %v", err)
}
return processReturn(c)
}
func sendKey(c net.Conn, data setKeyData) error {
var err error
defer func() {
if err != nil {
c.Close()
}
}()
var b []byte
if b, err = json.Marshal(data); err != nil {
return err
}
_, err = c.Write(b)
return err
}
func processReturn(r io.Reader) error {
buf := make([]byte, 1024)
n, err := r.Read(buf[:])
if err != nil {
return fmt.Errorf("failed to read buf in processReturn : %v", err)
}
if string(buf[0:n]) != success {
return fmt.Errorf(string(buf[0:n]))
}
return nil
}
func (c *controller) startExternalKeyListener() error {
if err := os.MkdirAll(udsBase, 0600); err != nil {
return err
}
uds := udsBase + c.id + ".sock"
l, err := net.Listen("unix", uds)
if err != nil {
return err
}
if err := os.Chmod(uds, 0600); err != nil {
l.Close()
return err
}
c.Lock()
c.extKeyListener = l
c.Unlock()
go c.acceptClientConnections(uds, l)
return nil
}
func (c *controller) acceptClientConnections(sock string, l net.Listener) {
for {
conn, err := l.Accept()
if err != nil {
if _, err1 := os.Stat(sock); os.IsNotExist(err1) {
logrus.Warnf("Unix socket %s doesnt exist. cannot accept client connections", sock)
return
}
logrus.Errorf("Error accepting connection %v", err)
continue
}
go func() {
err := c.processExternalKey(conn)
ret := success
if err != nil {
ret = err.Error()
}
_, err = conn.Write([]byte(ret))
if err != nil {
logrus.Errorf("Error returning to the client %v", err)
}
}()
}
}
func (c *controller) processExternalKey(conn net.Conn) error {
buf := make([]byte, 1280)
nr, err := conn.Read(buf)
if err != nil {
return err
}
var s setKeyData
if err = json.Unmarshal(buf[0:nr], &s); err != nil {
return err
}
var sandbox Sandbox
search := SandboxContainerWalker(&sandbox, s.ContainerID)
c.WalkSandboxes(search)
if sandbox == nil {
return types.BadRequestErrorf("no sandbox present for %s", s.ContainerID)
}
return sandbox.SetKey(s.Key)
}
func (c *controller) stopExternalKeyListener() {
c.extKeyListener.Close()
}

View file

@ -266,12 +266,6 @@ type StaticRoute struct {
// NextHop will be resolved by the kernel (i.e. as a loose hop). // NextHop will be resolved by the kernel (i.e. as a loose hop).
NextHop net.IP NextHop net.IP
// InterfaceID must refer to a defined interface on the
// Endpoint to which the routes are specified. Routes specified this way
// are interpreted as directly connected to the specified interface (no
// next hop will be used).
InterfaceID int
} }
// GetCopy returns a copy of this StaticRoute structure // GetCopy returns a copy of this StaticRoute structure
@ -279,9 +273,9 @@ func (r *StaticRoute) GetCopy() *StaticRoute {
d := GetIPNetCopy(r.Destination) d := GetIPNetCopy(r.Destination)
nh := GetIPCopy(r.NextHop) nh := GetIPCopy(r.NextHop)
return &StaticRoute{Destination: d, return &StaticRoute{Destination: d,
RouteType: r.RouteType, RouteType: r.RouteType,
NextHop: nh, NextHop: nh,
InterfaceID: r.InterfaceID} }
} }
/****************************** /******************************