mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #202 from aboch/mn
Bridge driver to support multiple networks
This commit is contained in:
commit
03dc873478
6 changed files with 137 additions and 51 deletions
|
@ -13,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
nullNetType = "null"
|
defaultDriverType = "bridge"
|
||||||
)
|
)
|
||||||
|
|
||||||
type command struct {
|
type command struct {
|
||||||
|
@ -52,7 +52,7 @@ func (cli *NetworkCli) CmdNetworkCreate(chain string, args ...string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if *flDriver == "" {
|
if *flDriver == "" {
|
||||||
*flDriver = nullNetType
|
*flDriver = defaultDriverType
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct network create request body
|
// Construct network create request body
|
||||||
|
|
|
@ -88,6 +88,7 @@ type bridgeNetwork struct {
|
||||||
type driver struct {
|
type driver struct {
|
||||||
config *configuration
|
config *configuration
|
||||||
network *bridgeNetwork
|
network *bridgeNetwork
|
||||||
|
networks map[types.UUID]*bridgeNetwork
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +99,7 @@ func init() {
|
||||||
|
|
||||||
// New constructs a new bridge driver
|
// New constructs a new bridge driver
|
||||||
func newDriver() driverapi.Driver {
|
func newDriver() driverapi.Driver {
|
||||||
return &driver{}
|
return &driver{networks: map[types.UUID]*bridgeNetwork{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init registers a new instance of bridge driver
|
// Init registers a new instance of bridge driver
|
||||||
|
@ -146,6 +147,27 @@ func (c *networkConfiguration) Validate() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Conflict check if two NetworkConfiguration objects overlap in the multinetwork
|
||||||
|
func (c *networkConfiguration) Conflict(o *networkConfiguration) bool {
|
||||||
|
if o == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also empty, becasue only one network with empty name is allowed
|
||||||
|
if c.BridgeName == o.BridgeName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// They must be in different subnets
|
||||||
|
|
||||||
|
if (c.AddressIPv4 != nil && o.AddressIPv4.IP != nil) &&
|
||||||
|
(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// FromMap retrieve the configuration data from the map form.
|
// FromMap retrieve the configuration data from the map form.
|
||||||
func (c *networkConfiguration) FromMap(data map[string]interface{}) error {
|
func (c *networkConfiguration) FromMap(data map[string]interface{}) error {
|
||||||
if i, ok := data["BridgeName"]; ok && i != nil {
|
if i, ok := data["BridgeName"]; ok && i != nil {
|
||||||
|
@ -340,11 +362,18 @@ func (d *driver) Config(option map[string]interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) getNetwork(id types.UUID) (*bridgeNetwork, error) {
|
func (d *driver) getNetwork(id types.UUID) (*bridgeNetwork, error) {
|
||||||
// Just a dummy function to return the only network managed by Bridge driver.
|
|
||||||
// But this API makes the caller code unchanged when we move to support multiple networks.
|
|
||||||
d.Lock()
|
d.Lock()
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
return d.network, nil
|
|
||||||
|
if id == "" {
|
||||||
|
return nil, types.BadRequestErrorf("invalid network id: %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if nw, ok := d.networks[id]; ok {
|
||||||
|
return nw, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseNetworkOptions(option options.Generic) (*networkConfiguration, error) {
|
func parseNetworkOptions(option options.Generic) (*networkConfiguration, error) {
|
||||||
|
@ -387,35 +416,71 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
||||||
d.Lock()
|
d.Lock()
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
if d.network != nil {
|
if _, ok := d.networks[id]; ok {
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
return &ErrNetworkExists{}
|
return types.ForbiddenErrorf("network %s exists", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse and validate the config. It should not conflict with existing networks' config
|
||||||
|
config, err := parseNetworkOptions(option)
|
||||||
|
if err != nil {
|
||||||
|
d.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, nw := range d.networks {
|
||||||
|
if nw.config.Conflict(config) {
|
||||||
|
d.Unlock()
|
||||||
|
return types.ForbiddenErrorf("conflicts with network %s (%s)", nw.id, nw.config.BridgeName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create and set network handler in driver
|
// Create and set network handler in driver
|
||||||
d.network = &bridgeNetwork{id: id, endpoints: make(map[types.UUID]*bridgeEndpoint)}
|
network := &bridgeNetwork{id: id, endpoints: make(map[types.UUID]*bridgeEndpoint), config: config}
|
||||||
network := d.network
|
d.networks[id] = network
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
|
|
||||||
// On failure make sure to reset driver network handler to nil
|
// On failure make sure to reset driver network handler to nil
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
d.network = nil
|
delete(d.networks, id)
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
config, err := parseNetworkOptions(option)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
network.config = config
|
|
||||||
|
|
||||||
// Create or retrieve the bridge L3 interface
|
// Create or retrieve the bridge L3 interface
|
||||||
bridgeIface := newInterface(config)
|
bridgeIface := newInterface(config)
|
||||||
network.bridge = bridgeIface
|
network.bridge = bridgeIface
|
||||||
|
|
||||||
|
// Verify network does not conflict with previously configured networks
|
||||||
|
// on parameters that were chosen by the driver.
|
||||||
|
d.Lock()
|
||||||
|
for _, nw := range d.networks {
|
||||||
|
if nw.id == id {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Verify the name (which may have been set by newInterface()) does not conflict with
|
||||||
|
// existing bridge interfaces. Ironically the system chosen name gets stored in the config...
|
||||||
|
// Basically we are checking if the two original configs were both empty.
|
||||||
|
if nw.config.BridgeName == config.BridgeName {
|
||||||
|
d.Unlock()
|
||||||
|
return types.ForbiddenErrorf("conflicts with network %s (%s)", nw.id, nw.config.BridgeName)
|
||||||
|
}
|
||||||
|
// If this network config specifies the AddressIPv4, we need
|
||||||
|
// to make sure it does not conflict with any previously allocated
|
||||||
|
// bridges. This could not be completely caught by the config conflict
|
||||||
|
// check, because networks which config does not specify the AddressIPv4
|
||||||
|
// get their address and subnet selected by the driver (see electBridgeIPv4())
|
||||||
|
if config.AddressIPv4 != nil {
|
||||||
|
if nw.bridge.bridgeIPv4.Contains(config.AddressIPv4.IP) ||
|
||||||
|
config.AddressIPv4.Contains(nw.bridge.bridgeIPv4.IP) {
|
||||||
|
d.Unlock()
|
||||||
|
return types.ForbiddenErrorf("conflicts with network %s (%s)", nw.id, nw.config.BridgeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.Unlock()
|
||||||
|
|
||||||
// Prepare the bridge setup configuration
|
// Prepare the bridge setup configuration
|
||||||
bridgeSetup := newBridgeSetup(config, bridgeIface)
|
bridgeSetup := newBridgeSetup(config, bridgeIface)
|
||||||
|
|
||||||
|
@ -485,8 +550,12 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||||
|
|
||||||
// Get network handler and remove it from driver
|
// Get network handler and remove it from driver
|
||||||
d.Lock()
|
d.Lock()
|
||||||
n := d.network
|
n, ok := d.networks[nid]
|
||||||
d.network = nil
|
if !ok {
|
||||||
|
d.Unlock()
|
||||||
|
return types.InternalMaskableErrorf("network %s does not exist", nid)
|
||||||
|
}
|
||||||
|
delete(d.networks, nid)
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
|
|
||||||
// On failure set network handler back in driver, but
|
// On failure set network handler back in driver, but
|
||||||
|
@ -494,8 +563,8 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
if d.network == nil {
|
if _, ok := d.networks[nid]; !ok {
|
||||||
d.network = n
|
d.networks[nid] = n
|
||||||
}
|
}
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -535,7 +604,11 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||||
|
|
||||||
// Get the network handler and make sure it exists
|
// Get the network handler and make sure it exists
|
||||||
d.Lock()
|
d.Lock()
|
||||||
n := d.network
|
n, ok := d.networks[nid]
|
||||||
|
if !ok {
|
||||||
|
d.Unlock()
|
||||||
|
return types.NotFoundErrorf("network %s does not exist", nid)
|
||||||
|
}
|
||||||
config := n.config
|
config := n.config
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
if n == nil {
|
if n == nil {
|
||||||
|
@ -716,7 +789,11 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||||
|
|
||||||
// Get the network handler and make sure it exists
|
// Get the network handler and make sure it exists
|
||||||
d.Lock()
|
d.Lock()
|
||||||
n := d.network
|
n, ok := d.networks[nid]
|
||||||
|
if !ok {
|
||||||
|
d.Unlock()
|
||||||
|
return types.NotFoundErrorf("network %s does not exist", nid)
|
||||||
|
}
|
||||||
config := n.config
|
config := n.config
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
if n == nil {
|
if n == nil {
|
||||||
|
@ -787,7 +864,11 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||||
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
|
||||||
// Get the network handler and make sure it exists
|
// Get the network handler and make sure it exists
|
||||||
d.Lock()
|
d.Lock()
|
||||||
n := d.network
|
n, ok := d.networks[nid]
|
||||||
|
if !ok {
|
||||||
|
d.Unlock()
|
||||||
|
return nil, types.NotFoundErrorf("network %s does not exist", nid)
|
||||||
|
}
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
if n == nil {
|
if n == nil {
|
||||||
return nil, driverapi.ErrNoNetwork(nid)
|
return nil, driverapi.ErrNoNetwork(nid)
|
||||||
|
|
|
@ -194,8 +194,12 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
|
||||||
t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
t.Fatalf("Failed to create an endpoint : %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
ep, _ := dd.network.endpoints["ep1"]
|
network, ok := dd.networks["net1"]
|
||||||
data, err := d.EndpointOperInfo(dd.network.id, ep.id)
|
if !ok {
|
||||||
|
t.Fatalf("Cannot find network %s inside driver", "net1")
|
||||||
|
}
|
||||||
|
ep, _ := network.endpoints["ep1"]
|
||||||
|
data, err := d.EndpointOperInfo(network.id, ep.id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to ask for endpoint operational data: %v", err)
|
t.Fatalf("Failed to ask for endpoint operational data: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,10 @@ func TestLinkCreate(t *testing.T) {
|
||||||
t.Fatalf("Could not find source link %s: %v", te.ifaces[0].srcName, err)
|
t.Fatalf("Could not find source link %s: %v", te.ifaces[0].srcName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
n := dr.network
|
n, ok := dr.networks["dummy"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Cannot find network %s inside driver", "dummy")
|
||||||
|
}
|
||||||
ip := te.ifaces[0].addr.IP
|
ip := te.ifaces[0].addr.IP
|
||||||
if !n.bridge.bridgeIPv4.Contains(ip) {
|
if !n.bridge.bridgeIPv4.Contains(ip) {
|
||||||
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), n.bridge.bridgeIPv4.String())
|
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), n.bridge.bridgeIPv4.String())
|
||||||
|
|
|
@ -47,7 +47,11 @@ func TestPortMappingConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dd := d.(*driver)
|
dd := d.(*driver)
|
||||||
ep, _ := dd.network.endpoints["ep1"]
|
network, ok := dd.networks["dummy"]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Cannot find network %s inside driver", "dummy")
|
||||||
|
}
|
||||||
|
ep, _ := network.endpoints["ep1"]
|
||||||
if len(ep.portMapping) != 2 {
|
if len(ep.portMapping) != 2 {
|
||||||
t.Fatalf("Failed to store the port bindings into the sandbox info. Found: %v", ep.portMapping)
|
t.Fatalf("Failed to store the port bindings into the sandbox info. Found: %v", ep.portMapping)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,27 +19,21 @@ func init() {
|
||||||
// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
|
// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
|
||||||
// on the internal addressing or other stupid things like that.
|
// on the internal addressing or other stupid things like that.
|
||||||
// They shouldn't, but hey, let's not break them unless we really have to.
|
// They shouldn't, but hey, let's not break them unless we really have to.
|
||||||
for _, addr := range []string{
|
// Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
|
||||||
"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
|
|
||||||
"10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive
|
// 172.[17-31].42.1/16
|
||||||
"10.1.42.1/16",
|
mask := []byte{255, 255, 0, 0}
|
||||||
"10.42.42.1/16",
|
for i := 17; i < 32; i++ {
|
||||||
"172.16.42.1/24",
|
bridgeNetworks = append(bridgeNetworks, &net.IPNet{IP: []byte{172, byte(i), 42, 1}, Mask: mask})
|
||||||
"172.16.43.1/24",
|
|
||||||
"172.16.44.1/24",
|
|
||||||
"10.0.42.1/24",
|
|
||||||
"10.0.43.1/24",
|
|
||||||
"192.168.42.1/24",
|
|
||||||
"192.168.43.1/24",
|
|
||||||
"192.168.44.1/24",
|
|
||||||
} {
|
|
||||||
ip, net, err := net.ParseCIDR(addr)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to parse address %s", addr)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
net.IP = ip.To4()
|
// 10.[0-255].42.1/16
|
||||||
bridgeNetworks = append(bridgeNetworks, net)
|
for i := 0; i < 256; i++ {
|
||||||
|
bridgeNetworks = append(bridgeNetworks, &net.IPNet{IP: []byte{10, byte(i), 42, 1}, Mask: mask})
|
||||||
|
}
|
||||||
|
// 192.168.[42-44].1/24
|
||||||
|
mask[2] = 255
|
||||||
|
for i := 42; i < 45; i++ {
|
||||||
|
bridgeNetworks = append(bridgeNetworks, &net.IPNet{IP: []byte{192, 168, byte(i), 1}, Mask: mask})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue