From cfc28a900a7ac29bc91cb1d4fa1c4890eebf2791 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Mon, 1 Jun 2015 13:14:29 -0700 Subject: [PATCH] One port mapper per bridge network Signed-off-by: Alessandro Boch --- libnetwork/drivers/bridge/bridge.go | 24 ++++++++++------- libnetwork/drivers/bridge/bridge_test.go | 2 +- libnetwork/drivers/bridge/port_mapping.go | 26 +++++++++---------- .../drivers/bridge/port_mapping_test.go | 2 +- libnetwork/drivers/bridge/setup_ip_tables.go | 4 +-- .../drivers/bridge/setup_ip_tables_test.go | 4 ++- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index ceff412549..1a6d18a41f 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -29,7 +29,6 @@ const ( var ( ipAllocator *ipallocator.IPAllocator - portMapper *portmapper.PortMapper ) // configuration info for the "bridge" driver. @@ -78,10 +77,11 @@ type bridgeEndpoint struct { } type bridgeNetwork struct { - id types.UUID - bridge *bridgeInterface // The bridge's L3 interface - config *networkConfiguration - endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id + id types.UUID + bridge *bridgeInterface // The bridge's L3 interface + config *networkConfiguration + endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id + portMapper *portmapper.PortMapper sync.Mutex } @@ -94,7 +94,6 @@ type driver struct { func init() { ipAllocator = ipallocator.New() - portMapper = portmapper.New() } // New constructs a new bridge driver @@ -451,7 +450,12 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err } // Create and set network handler in driver - network := &bridgeNetwork{id: id, endpoints: make(map[types.UUID]*bridgeEndpoint), config: config} + network := &bridgeNetwork{ + id: id, + endpoints: make(map[types.UUID]*bridgeEndpoint), + config: config, + portMapper: portmapper.New(), + } d.networks[id] = network d.Unlock() @@ -537,7 +541,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err {!config.EnableUserlandProxy, setupLoopbackAdressesRouting}, // Setup IPTables. - {config.EnableIPTables, setupIPTables}, + {config.EnableIPTables, network.setupIPTables}, // Setup DefaultGatewayIPv4 {config.DefaultGatewayIPv4 != nil, setupGatewayIPv4}, @@ -792,7 +796,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn } // Program any required port mapping and store them in the endpoint - endpoint.portMapping, err = allocatePorts(epConfig, intf, config.DefaultBindingIP, config.EnableUserlandProxy) + endpoint.portMapping, err = n.allocatePorts(epConfig, intf, config.DefaultBindingIP, config.EnableUserlandProxy) if err != nil { return err } @@ -851,7 +855,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error { }() // Remove port mappings. Do not stop endpoint delete on unmap failure - releasePorts(ep) + n.releasePorts(ep) // Release the v4 address allocated to this endpoint's sandbox interface err = ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, ep.intf.Address.IP) diff --git a/libnetwork/drivers/bridge/bridge_test.go b/libnetwork/drivers/bridge/bridge_test.go index aba46977e6..e43856cd12 100644 --- a/libnetwork/drivers/bridge/bridge_test.go +++ b/libnetwork/drivers/bridge/bridge_test.go @@ -227,7 +227,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) { } // Cleanup as host ports are there - err = releasePorts(ep) + err = network.releasePorts(ep) if err != nil { t.Fatalf("Failed to release mapped ports: %v", err) } diff --git a/libnetwork/drivers/bridge/port_mapping.go b/libnetwork/drivers/bridge/port_mapping.go index bf5ac5741b..8f377954b8 100644 --- a/libnetwork/drivers/bridge/port_mapping.go +++ b/libnetwork/drivers/bridge/port_mapping.go @@ -15,7 +15,7 @@ var ( defaultBindingIP = net.IPv4(0, 0, 0, 0) ) -func allocatePorts(epConfig *endpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { +func (n *bridgeNetwork) allocatePorts(epConfig *endpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { if epConfig == nil || epConfig.PortBindings == nil { return nil, nil } @@ -25,16 +25,16 @@ func allocatePorts(epConfig *endpointConfiguration, intf *sandbox.Interface, req defHostIP = reqDefBindIP } - return allocatePortsInternal(epConfig.PortBindings, intf.Address.IP, defHostIP, ulPxyEnabled) + return n.allocatePortsInternal(epConfig.PortBindings, intf.Address.IP, defHostIP, ulPxyEnabled) } -func allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { +func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) { bs := make([]types.PortBinding, 0, len(bindings)) for _, c := range bindings { b := c.GetCopy() - if err := allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil { + if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil { // On allocation failure, release previously allocated ports. On cleanup error, just log a warning message - if cuErr := releasePortsInternal(bs); cuErr != nil { + if cuErr := n.releasePortsInternal(bs); cuErr != nil { logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr) } return nil, err @@ -44,7 +44,7 @@ func allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP return bs, nil } -func allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error { +func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error { var ( host net.Addr err error @@ -66,7 +66,7 @@ func allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEn // Try up to maxAllocatePortAttempts times to get a port that's not already allocated. for i := 0; i < maxAllocatePortAttempts; i++ { - if host, err = portMapper.Map(container, bnd.HostIP, int(bnd.HostPort), ulPxyEnabled); err == nil { + if host, err = n.portMapper.Map(container, bnd.HostIP, int(bnd.HostPort), ulPxyEnabled); err == nil { break } // There is no point in immediately retrying to map an explicitly chosen port. @@ -94,16 +94,16 @@ func allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEn } } -func releasePorts(ep *bridgeEndpoint) error { - return releasePortsInternal(ep.portMapping) +func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error { + return n.releasePortsInternal(ep.portMapping) } -func releasePortsInternal(bindings []types.PortBinding) error { +func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error { var errorBuf bytes.Buffer // Attempt to release all port bindings, do not stop on failure for _, m := range bindings { - if err := releasePort(m); err != nil { + if err := n.releasePort(m); err != nil { errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err)) } } @@ -114,11 +114,11 @@ func releasePortsInternal(bindings []types.PortBinding) error { return nil } -func releasePort(bnd types.PortBinding) error { +func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error { // Construct the host side transport address host, err := bnd.HostAddr() if err != nil { return err } - return portMapper.Unmap(host) + return n.portMapper.Unmap(host) } diff --git a/libnetwork/drivers/bridge/port_mapping_test.go b/libnetwork/drivers/bridge/port_mapping_test.go index 3a7a30796c..52cb3eacb2 100644 --- a/libnetwork/drivers/bridge/port_mapping_test.go +++ b/libnetwork/drivers/bridge/port_mapping_test.go @@ -64,7 +64,7 @@ func TestPortMappingConfig(t *testing.T) { t.Fatalf("operational port mapping data not found on bridgeEndpoint") } - err = releasePorts(ep) + err = network.releasePorts(ep) if err != nil { t.Fatalf("Failed to release mapped ports: %v", err) } diff --git a/libnetwork/drivers/bridge/setup_ip_tables.go b/libnetwork/drivers/bridge/setup_ip_tables.go index e616d8b63b..d8c929af75 100644 --- a/libnetwork/drivers/bridge/setup_ip_tables.go +++ b/libnetwork/drivers/bridge/setup_ip_tables.go @@ -13,7 +13,7 @@ const ( DockerChain = "DOCKER" ) -func setupIPTables(config *networkConfiguration, i *bridgeInterface) error { +func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInterface) error { // Sanity check. if config.EnableIPTables == false { return IPTableCfgError(config.BridgeName) @@ -39,7 +39,7 @@ func setupIPTables(config *networkConfiguration, i *bridgeInterface) error { return fmt.Errorf("Failed to create FILTER chain: %s", err.Error()) } - portMapper.SetIptablesChain(chain) + n.portMapper.SetIptablesChain(chain) return nil } diff --git a/libnetwork/drivers/bridge/setup_ip_tables_test.go b/libnetwork/drivers/bridge/setup_ip_tables_test.go index 6f326dfe43..b371822304 100644 --- a/libnetwork/drivers/bridge/setup_ip_tables_test.go +++ b/libnetwork/drivers/bridge/setup_ip_tables_test.go @@ -6,6 +6,7 @@ import ( "github.com/docker/libnetwork/iptables" "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/portmapper" ) const ( @@ -95,8 +96,9 @@ func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) { // Assert function which pushes chains based on bridge config parameters. func assertBridgeConfig(config *networkConfiguration, br *bridgeInterface, t *testing.T) { + nw := bridgeNetwork{portMapper: portmapper.New()} // Attempt programming of ip tables. - err := setupIPTables(config, br) + err := nw.setupIPTables(config, br) if err != nil { t.Fatalf("%v", err) }