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
}
ifaceList := epInfo.InterfaceList()
if len(ifaceList) == 0 {
iface := epInfo.Iface()
if iface == nil {
return networkSettings, nil
}
iface := ifaceList[0]
ones, _ := iface.Address().Mask.Size()
networkSettings.IPAddress = iface.Address().IP.String()
networkSettings.IPPrefixLen = ones
@ -597,24 +595,6 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet
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
}

View file

@ -820,9 +820,9 @@ func (daemon *Daemon) Shutdown() error {
}
group.Wait()
// trigger libnetwork GC only if it's initialized
// trigger libnetwork Stop only if it's initialized
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
#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/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4

View file

@ -4,6 +4,7 @@
*.so
# Folders
integration-tmp/
_obj
_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
build_image=libnetwork-build
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"
cidocker = docker run ${ciargs} ${dockerargs} golang:1.4
all: ${build_image}.created
${docker} ./wrapmake.sh all-local
all: ${build_image}.created build check integration-tests
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
@ -19,13 +26,16 @@ ${build_image}.created:
touch ${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:
$(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
${docker} ./wrapmake.sh check-local
@${docker} ./wrapmake.sh check-local
check-code:
@echo "Checking code... "
@ -76,4 +86,5 @@ coveralls:
# The following target is a workaround for this
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 {
setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
}
if sc.UseExternalKey {
setFctList = append(setFctList, libnetwork.OptionUseExternalKey())
}
if sc.DNS != nil {
for _, d := range sc.DNS {
setFctList = append(setFctList, libnetwork.OptionDNS(d))

View file

@ -57,6 +57,7 @@ type sandboxCreate struct {
DNS []string `json:"dns"`
ExtraHosts []extraHost `json:"extra_hosts"`
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

View file

@ -115,7 +115,7 @@ func lookupContainerID(cli *NetworkCli, cnNameID 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 {
return "", err
}
@ -360,12 +360,17 @@ func (cli *NetworkCli) CmdServiceDetach(chain string, args ...string) error {
return err
}
sandboxID, err := lookupSandboxID(cli, containerID)
if err != nil {
return err
}
serviceID, err := lookupServiceID(cli, nn, sn)
if err != nil {
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 {
return err
}

View file

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

View file

@ -65,6 +65,9 @@ import (
// NetworkController provides the interface for controller instance which manages
// networks.
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(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(id string) (Sandbox, error)
// GC triggers immediate garbage collection of resources which are garbage collected.
GC()
// Stop network controller
Stop()
}
// 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 controller struct {
networks networkTable
drivers driverTable
sandboxes sandboxTable
cfg *config.Config
store datastore.DataStore
id string
networks networkTable
drivers driverTable
sandboxes sandboxTable
cfg *config.Config
store datastore.DataStore
extKeyListener net.Listener
sync.Mutex
}
@ -138,6 +143,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
cfg.ProcessOptions(cfgOptions...)
}
c := &controller{
id: stringid.GenerateRandomID(),
cfg: cfg,
networks: networkTable{},
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
}
func (c *controller) ID() string {
return c.id
}
func (c *controller) validateHostDiscoveryConfig() bool {
if c.cfg == nil || c.cfg.Cluster.Discovery == "" || c.cfg.Cluster.Address == "" {
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 {
c.Lock()
if !config.IsValidName(networkType) {
c.Unlock()
return ErrInvalidName(networkType)
}
c.Lock()
if _, ok := c.drivers[networkType]; ok {
c.Unlock()
return driverapi.ErrActiveRegistration(networkType)
@ -414,7 +428,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
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 {
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
}
func (c *controller) GC() {
func (c *controller) Stop() {
c.stopExternalKeyListener()
osl.GC()
}

View file

@ -45,18 +45,16 @@ type Driver interface {
// EndpointInfo provides a go interface to fetch or populate endpoint assigned network resources.
type EndpointInfo interface {
// Interfaces returns a list of interfaces bound to the endpoint.
// If the list is not empty the driver is only expected to consume the interfaces.
// It is an error to try to add interfaces to a non-empty list.
// If the list is empty the driver is expected to populate with 0 or more interfaces.
Interfaces() []InterfaceInfo
// Interface returns the interface bound to the endpoint.
// If the value is not nil the driver is only expected to consume the interface.
// It is an error to try to add interface if the passed down value is non-nil
// If the value is nil the driver is expected to add an interface
Interface() InterfaceInfo
// AddInterface is used by the driver to add an interface to the interface list.
// This method will return an error if the driver attempts to add interfaces
// if the Interfaces() method returned a non-empty list.
// ID field need only have significance within the endpoint so it can be a simple
// monotonically increasing number
AddInterface(ID int, mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error
// 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 interface
// if the Interface() method returned a non-nil value.
AddInterface(mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error
}
// InterfaceInfo provides a go interface for drivers to retrive
@ -70,10 +68,6 @@ type InterfaceInfo interface {
// AddressIPv6 returns the IPv6 address.
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
@ -81,18 +75,14 @@ type InterfaceInfo interface {
type InterfaceNameInfo interface {
// SetNames method assigns the srcName and dstPrefix for the interface.
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
// join time.
type JoinInfo interface {
// InterfaceNames returns a list of InterfaceNameInfo go interface to facilitate
// setting the names for the interfaces.
InterfaceNames() []InterfaceNameInfo
// InterfaceName returns a InterfaceNameInfo go interface to facilitate
// setting the names for the interface.
InterfaceName() InterfaceNameInfo
// SetGateway sets the default IPv4 gateway when a container joins the endpoint.
SetGateway(net.IP) error
@ -102,7 +92,7 @@ type JoinInfo interface {
// AddStaticRoute adds a routes to the sandbox.
// 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

View file

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

View file

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

View file

@ -48,13 +48,12 @@ type CreateEndpointRequest struct {
NetworkID string
// The ID of the endpoint for later reference.
EndpointID string
Interfaces []*EndpointInterface
Interface *EndpointInterface
Options map[string]interface{}
}
// EndpointInterface represents an interface endpoint.
type EndpointInterface struct {
ID int
Address string
AddressIPv6 string
MacAddress string
@ -63,12 +62,11 @@ type EndpointInterface struct {
// CreateEndpointResponse is the response to the CreateEndpoint action.
type CreateEndpointResponse struct {
Response
Interfaces []*EndpointInterface
Interface *EndpointInterface
}
// Interface is the representation of a linux interface.
type Interface struct {
ID int
Address *net.IPNet
AddressIPv6 *net.IPNet
MacAddress net.HardwareAddr
@ -118,16 +116,15 @@ type StaticRoute struct {
Destination string
RouteType int
NextHop string
InterfaceID int
}
// JoinResponse is the response to a JoinRequest.
type JoinResponse struct {
Response
InterfaceNames []*InterfaceName
Gateway string
GatewayIPv6 string
StaticRoutes []StaticRoute
InterfaceName *InterfaceName
Gateway string
GatewayIPv6 string
StaticRoutes []StaticRoute
}
// 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 {
var reqIface *api.EndpointInterface
if epInfo == nil {
return fmt.Errorf("must not be called with nil EndpointInfo")
}
reqIfaces := make([]*api.EndpointInterface, len(epInfo.Interfaces()))
for i, iface := range epInfo.Interfaces() {
iface := epInfo.Interface()
if iface != nil {
addr4 := iface.Address()
addr6 := iface.AddressIPv6()
reqIfaces[i] = &api.EndpointInterface{
ID: iface.ID(),
reqIface = &api.EndpointInterface{
Address: addr4.String(),
AddressIPv6: addr6.String(),
MacAddress: iface.MacAddress().String(),
@ -89,7 +90,7 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
create := &api.CreateEndpointRequest{
NetworkID: nid,
EndpointID: eid,
Interfaces: reqIfaces,
Interface: reqIface,
Options: epOptions,
}
var res api.CreateEndpointResponse
@ -97,25 +98,26 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
return err
}
ifaces, err := parseInterfaces(res)
inIface, err := parseInterface(res)
if err != nil {
return err
}
if len(reqIfaces) > 0 && len(ifaces) > 0 {
// We're not supposed to add interfaces if there already are
// some. Attempt to roll back
return errorWithRollback("driver attempted to add more interfaces", d.DeleteEndpoint(nid, eid))
if reqIface != nil && inIface != nil {
// We're not supposed to add interface if there is already
// one. Attempt to roll back
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
if iface.Address != nil {
addr4 = *(iface.Address)
if inIface.Address != nil {
addr4 = *(inIface.Address)
}
if iface.AddressIPv6 != nil {
addr6 = *(iface.AddressIPv6)
if inIface.AddressIPv6 != nil {
addr6 = *(inIface.AddressIPv6)
}
if err := epInfo.AddInterface(iface.ID, iface.MacAddress, addr4, addr6); err != nil {
return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", iface, err), d.DeleteEndpoint(nid, eid))
if err := epInfo.AddInterface(inIface.MacAddress, addr4, addr6); err != nil {
return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", inIface, err), d.DeleteEndpoint(nid, eid))
}
}
return nil
@ -165,18 +167,13 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return err
}
// Expect each interface ID given by CreateEndpoint to have an
// entry at that index in the names supplied here. In other words,
// if you supply 0..n interfaces with IDs 0..n above, you should
// supply the names in the same order.
ifaceNames := res.InterfaceNames
for _, iface := range jinfo.InterfaceNames() {
i := iface.ID()
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 {
ifaceName := res.InterfaceName
if ifaceName == nil {
return fmt.Errorf("no interface name information received")
}
if iface := jinfo.InterfaceName(); iface != nil {
if err := iface.SetNames(ifaceName.SrcName, ifaceName.DstPrefix); err != nil {
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
}
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))
}
}
@ -229,7 +226,7 @@ func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
var routes = make([]*types.StaticRoute, len(r.StaticRoutes))
for i, inRoute := range r.StaticRoutes {
var err error
outRoute := &types.StaticRoute{InterfaceID: inRoute.InterfaceID, RouteType: inRoute.RouteType}
outRoute := &types.StaticRoute{RouteType: inRoute.RouteType}
if inRoute.Destination != "" {
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.
func parseInterfaces(r api.CreateEndpointResponse) ([]*api.Interface, error) {
var (
Interfaces = make([]*api.Interface, len(r.Interfaces))
)
for i, inIf := range r.Interfaces {
func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) {
var outIf *api.Interface
inIf := r.Interface
if inIf != nil {
var err error
outIf := &api.Interface{ID: inIf.ID}
outIf = &api.Interface{}
if inIf.Address != "" {
if outIf.Address, err = toAddr(inIf.Address); err != nil {
return nil, err
@ -272,9 +269,9 @@ func parseInterfaces(r api.CreateEndpointResponse) ([]*api.Interface, error) {
return nil, err
}
}
Interfaces[i] = outIf
}
return Interfaces, nil
return outIf, nil
}
func toAddr(ipAddr string) (*net.IPNet, error) {

View file

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

View file

@ -10,9 +10,11 @@ import (
// EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
type EndpointInfo interface {
// InterfaceList returns an interface list which were assigned to the endpoint
// by the driver. This can be used after the endpoint has been created.
InterfaceList() []InterfaceInfo
// Iface returns InterfaceInfo, go interface that can be used
// to get more information on the interface which was assigned to
// 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.
// This will only return a valid value if a container has joined the endpoint.
@ -39,7 +41,6 @@ type InterfaceInfo interface {
}
type endpointInterface struct {
id int
mac net.HardwareAddr
addr net.IPNet
addrv6 net.IPNet
@ -50,7 +51,6 @@ type endpointInterface struct {
func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
epMap := make(map[string]interface{})
epMap["id"] = epi.id
epMap["mac"] = epi.mac.String()
epMap["addr"] = epi.addr.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 {
return err
}
epi.id = int(epMap["id"].(float64))
mac, _ := net.ParseMAC(epMap["mac"].(string))
epi.mac = mac
@ -128,51 +127,42 @@ func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
return driver.EndpointOperInfo(nid, epid)
}
func (ep *endpoint) InterfaceList() []InterfaceInfo {
func (ep *endpoint) Iface() InterfaceInfo {
ep.Lock()
defer ep.Unlock()
iList := make([]InterfaceInfo, len(ep.iFaces))
for i, iface := range ep.iFaces {
iList[i] = iface
if ep.iface != nil {
return ep.iface
}
return iList
return nil
}
func (ep *endpoint) Interfaces() []driverapi.InterfaceInfo {
func (ep *endpoint) Interface() driverapi.InterfaceInfo {
ep.Lock()
defer ep.Unlock()
iList := make([]driverapi.InterfaceInfo, len(ep.iFaces))
for i, iface := range ep.iFaces {
iList[i] = iface
if ep.iface != nil {
return ep.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()
defer ep.Unlock()
iface := &endpointInterface{
id: id,
addr: *types.GetIPNetCopy(&ipv4),
addrv6: *types.GetIPNetCopy(&ipv6),
}
iface.mac = types.GetMacCopy(mac)
ep.iFaces = append(ep.iFaces, iface)
ep.iface = iface
return nil
}
func (epi *endpointInterface) ID() int {
return epi.id
}
func (epi *endpointInterface) MacAddress() net.HardwareAddr {
return types.GetMacCopy(epi.mac)
}
@ -191,24 +181,22 @@ func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
return nil
}
func (ep *endpoint) InterfaceNames() []driverapi.InterfaceNameInfo {
func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo {
ep.Lock()
defer ep.Unlock()
iList := make([]driverapi.InterfaceNameInfo, len(ep.iFaces))
for i, iface := range ep.iFaces {
iList[i] = iface
if ep.iface != nil {
return ep.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()
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 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 {
for _, iface := range ep.iFaces {
if iface.id == route.InterfaceID {
iface.routes = append(iface.routes, route.Destination)
return nil
}
}
return types.BadRequestErrorf("Interface with ID %d doesn't exist.",
route.InterfaceID)
ep.Lock()
defer ep.Unlock()
iface := ep.iface
iface.routes = append(iface.routes, route.Destination)
return nil
}
func (ep *endpoint) Sandbox() Sandbox {

View file

@ -305,7 +305,6 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
}
ep := &endpoint{name: name,
iFaces: []*endpointInterface{},
generic: make(map[string]interface{})}
ep.id = stringid.GenerateRandomID()
ep.network = n
@ -409,7 +408,7 @@ func (n *network) isGlobalScoped() (bool, error) {
func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
n.Lock()
var recs []etchosts.Record
for _, iface := range ep.InterfaceList() {
if iface := ep.Iface(); iface != nil {
if isAdd {
n.svcRecords[ep.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
}
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() {
if len(os.Args) < 2 {
log.Fatal("no namespace path provided")
}
if err := syscall.Mount("/proc/self/ns/net", os.Args[1], "bind", syscall.MS_BIND, ""); err != nil {
log.Fatal(err)
}
if err := loopbackUp(); err != nil {
if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
log.Fatal(err)
}
}
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 {
return err
}

View file

@ -6,3 +6,7 @@ package osl
// and waits for it.
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
}
func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
return nil, nil
}
// GC triggers garbage collection of namespace path right away
// and waits for it.
func GC() {

View file

@ -32,6 +32,8 @@ type Sandbox interface {
// Refresh leaves all the endpoints, resets and re-apply the options,
// re-joins all the endpoints without destroying the osl sandbox
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() error
}
@ -102,6 +104,7 @@ type containerConfig struct {
resolvConfPathConfig
generic map[string]interface{}
useDefaultSandBox bool
useExternalKey bool
prio int // higher the value, more the priority
}
@ -241,8 +244,14 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
}
func (sb *sandbox) updateGateway(ep *endpoint) error {
sb.osSbox.UnsetGateway()
sb.osSbox.UnsetGatewayIPv6()
sb.Lock()
osSbox := sb.osSbox
sb.Unlock()
if osSbox == nil {
return nil
}
osSbox.UnsetGateway()
osSbox.UnsetGatewayIPv6()
if ep == nil {
return nil
@ -252,24 +261,66 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
joinInfo := ep.joinInfo
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)
}
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 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 {
sb.Lock()
if sb.osSbox == nil {
sb.Unlock()
return nil
}
sb.Unlock()
ep.Lock()
joinInfo := ep.joinInfo
ifaces := ep.iFaces
i := ep.iface
ep.Unlock()
for _, i := range ifaces {
if i != nil {
var ifaceOptions []osl.IfaceOption
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()
heap.Push(&sb.endpoints, ep)
highEp := sb.endpoints[0]
sb.Unlock()
if ep == highEp {
@ -305,24 +355,28 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
}
func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
for _, i := range sb.osSbox.Info().Interfaces() {
// 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)
sb.Lock()
osSbox := sb.osSbox
sb.Unlock()
if osSbox != nil {
for _, i := range osSbox.Info().Interfaces() {
// 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()
joinInfo := ep.joinInfo
ep.Unlock()
ep.Lock()
joinInfo := ep.joinInfo
ep.Unlock()
// Remove non-interface routes.
for _, r := range joinInfo.StaticRoutes {
if err := sb.osSbox.RemoveStaticRoute(r); err != nil {
log.Debugf("Remove route failed: %v", err)
// Remove non-interface routes.
for _, r := range joinInfo.StaticRoutes {
if err := osSbox.RemoveStaticRoute(r); err != nil {
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
// 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.

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 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
@ -279,9 +273,9 @@ func (r *StaticRoute) GetCopy() *StaticRoute {
d := GetIPNetCopy(r.Destination)
nh := GetIPCopy(r.NextHop)
return &StaticRoute{Destination: d,
RouteType: r.RouteType,
NextHop: nh,
InterfaceID: r.InterfaceID}
RouteType: r.RouteType,
NextHop: nh,
}
}
/******************************