Skip to content

Commit af3eb25

Browse files
committed
Phase-2 bridge driver changes to support IPAM
- Set bridge ipv4 address when bridge is present - IPv6 changes for bridge - Convert unit tests to the new model Signed-off-by: Alessandro Boch <aboch@docker.com>
1 parent f2f5360 commit af3eb25

17 files changed

+331
-326
lines changed

libnetwork/bitseq/sequence.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package bitseq
55

66
import (
77
"encoding/binary"
8+
"encoding/json"
89
"fmt"
910
"sync"
1011

@@ -392,6 +393,38 @@ func (h *Handle) String() string {
392393
h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString())
393394
}
394395

396+
// MarshalJSON encodes Handle into json message
397+
func (h *Handle) MarshalJSON() ([]byte, error) {
398+
m := map[string]interface{}{
399+
"id": h.id,
400+
}
401+
402+
b, err := h.ToByteArray()
403+
if err != nil {
404+
return nil, err
405+
}
406+
m["sequence"] = b
407+
return json.Marshal(m)
408+
}
409+
410+
// UnmarshalJSON decodes json message into Handle
411+
func (h *Handle) UnmarshalJSON(data []byte) error {
412+
var (
413+
m map[string]interface{}
414+
b []byte
415+
err error
416+
)
417+
if err = json.Unmarshal(data, &m); err != nil {
418+
return err
419+
}
420+
h.id = m["id"].(string)
421+
bi, _ := json.Marshal(m["sequence"])
422+
if err := json.Unmarshal(bi, &b); err != nil {
423+
return err
424+
}
425+
return h.FromByteArray(b)
426+
}
427+
395428
// getFirstAvailable looks for the first unset bit in passed mask starting from start
396429
func getFirstAvailable(head *sequence, start uint32) (uint32, uint32, error) {
397430
// Find sequence which contains the start bit

libnetwork/bitseq/store.go

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"encoding/json"
55
"fmt"
66

7-
log "github.com/Sirupsen/logrus"
87
"github.com/docker/libnetwork/datastore"
98
"github.com/docker/libnetwork/types"
109
)
@@ -25,27 +24,16 @@ func (h *Handle) KeyPrefix() []string {
2524

2625
// Value marshals the data to be stored in the KV store
2726
func (h *Handle) Value() []byte {
28-
b, err := h.ToByteArray()
27+
b, err := json.Marshal(h)
2928
if err != nil {
30-
log.Warnf("Failed to serialize Handle: %v", err)
31-
b = []byte{}
32-
}
33-
jv, err := json.Marshal(b)
34-
if err != nil {
35-
log.Warnf("Failed to json encode bitseq handler byte array: %v", err)
36-
return []byte{}
29+
return nil
3730
}
38-
return jv
31+
return b
3932
}
4033

4134
// SetValue unmarshals the data from the KV store
4235
func (h *Handle) SetValue(value []byte) error {
43-
var b []byte
44-
if err := json.Unmarshal(value, &b); err != nil {
45-
return err
46-
}
47-
48-
return h.FromByteArray(b)
36+
return json.Unmarshal(value, h)
4937
}
5038

5139
// Index returns the latest DB Index as seen by this object
@@ -77,7 +65,6 @@ func (h *Handle) New() datastore.KVObject {
7765

7866
return &Handle{
7967
app: h.app,
80-
id: h.id,
8168
store: h.store,
8269
}
8370
}

libnetwork/cmd/dnet/dnet.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ import (
2929
"github.com/docker/libnetwork/config"
3030
"github.com/docker/libnetwork/datastore"
3131
"github.com/docker/libnetwork/driverapi"
32+
"github.com/docker/libnetwork/ipamutils"
3233
"github.com/docker/libnetwork/netlabel"
3334
"github.com/docker/libnetwork/options"
35+
"github.com/docker/libnetwork/types"
3436
"github.com/gorilla/mux"
3537
)
3638

@@ -187,7 +189,12 @@ func createDefaultNetwork(c libnetwork.NetworkController) {
187189
}
188190
createOptions = append(createOptions,
189191
libnetwork.NetworkOptionGeneric(genericOption),
190-
libnetwork.NetworkOptionPersist(false))
192+
ipamOption(nw))
193+
}
194+
195+
if _, err := c.NetworkByName(nw); err == nil {
196+
logrus.Debugf("Default network %s already present", nw)
197+
return
191198
}
192199
_, err := c.NewNetwork(d, nw, createOptions...)
193200
if err != nil {
@@ -405,3 +412,15 @@ func encodeData(data interface{}) (*bytes.Buffer, error) {
405412
}
406413
return params, nil
407414
}
415+
416+
func ipamOption(bridgeName string) libnetwork.NetworkOption {
417+
if nw, _, err := ipamutils.ElectInterfaceAddresses(bridgeName); err == nil {
418+
ipamV4Conf := &libnetwork.IpamConf{PreferredPool: nw.String()}
419+
hip, _ := types.GetHostPartIP(nw.IP, nw.Mask)
420+
if hip.IsGlobalUnicast() {
421+
ipamV4Conf.Gateway = nw.IP.String()
422+
}
423+
return libnetwork.NetworkOptionIpam("default", "", []*libnetwork.IpamConf{ipamV4Conf}, nil)
424+
}
425+
return nil
426+
}

libnetwork/drivers/bridge/bridge.go

Lines changed: 64 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,17 @@ type configuration struct {
5656
// networkConfiguration for network specific configuration
5757
type networkConfiguration struct {
5858
BridgeName string
59-
AddressIPv4 *net.IPNet
6059
EnableIPv6 bool
6160
EnableIPMasquerade bool
6261
EnableICC bool
6362
Mtu int
64-
DefaultGatewayIPv4 net.IP
65-
DefaultGatewayIPv6 net.IP
6663
DefaultBindingIP net.IP
6764
DefaultBridge bool
65+
// Internal fields set after ipam data parsing
66+
AddressIPv4 *net.IPNet
67+
AddressIPv6 *net.IPNet
68+
DefaultGatewayIPv4 net.IP
69+
DefaultGatewayIPv6 net.IP
6870
}
6971

7072
// endpointConfiguration represents the user specified configuration for the sandbox endpoint
@@ -161,27 +163,39 @@ func (c *networkConfiguration) Validate() error {
161163
}
162164
}
163165

166+
// If default v6 gw is specified, AddressIPv6 must be specified and gw must belong to AddressIPv6 subnet
167+
if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
168+
if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) {
169+
return &ErrInvalidGateway{}
170+
}
171+
}
164172
return nil
165173
}
166174

167175
// Conflicts check if two NetworkConfiguration objects overlap
168-
func (c *networkConfiguration) Conflicts(o *networkConfiguration) bool {
176+
func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
169177
if o == nil {
170-
return false
178+
return fmt.Errorf("same configuration")
171179
}
172180

173181
// Also empty, becasue only one network with empty name is allowed
174182
if c.BridgeName == o.BridgeName {
175-
return true
183+
return fmt.Errorf("networks have same name")
176184
}
177185

178186
// They must be in different subnets
179187
if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
180188
(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
181-
return true
189+
return fmt.Errorf("networks have overlapping IPv4")
190+
}
191+
192+
// They must be in different v6 subnets
193+
if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) &&
194+
(c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) {
195+
return fmt.Errorf("networks have overlapping IPv6")
182196
}
183197

184-
return false
198+
return nil
185199
}
186200

187201
// fromMap retrieve the configuration data from the map form.
@@ -456,18 +470,18 @@ func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []d
456470
c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway)
457471
}
458472

459-
if c.EnableIPv6 && len(ipamV6Data) == 0 {
460-
return types.BadRequestErrorf("bridge network %s requires ipv6 configuration", id)
461-
}
462-
463-
gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]
464-
if ok {
473+
if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok {
465474
c.DefaultGatewayIPv4 = gw.IP
466475
}
467476

468-
gw, ok = ipamV4Data[0].AuxAddresses[DefaultGatewayV6AuxKey]
469-
if ok {
470-
c.DefaultGatewayIPv6 = gw.IP
477+
if len(ipamV6Data) > 0 {
478+
if ipamV6Data[0].Gateway != nil {
479+
c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway)
480+
}
481+
482+
if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok {
483+
c.DefaultGatewayIPv6 = gw.IP
484+
}
471485
}
472486

473487
return nil
@@ -502,6 +516,9 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
502516

503517
// Returns the non link-local IPv6 subnet for the containers attached to this bridge if found, nil otherwise
504518
func getV6Network(config *networkConfiguration, i *bridgeInterface) *net.IPNet {
519+
if config.AddressIPv6 != nil {
520+
return config.AddressIPv6
521+
}
505522
if i.bridgeIPv6 != nil && i.bridgeIPv6.IP != nil && !i.bridgeIPv6.IP.IsLinkLocalUnicast() {
506523
return i.bridgeIPv6
507524
}
@@ -551,8 +568,9 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
551568
nw.Lock()
552569
nwConfig := nw.config
553570
nw.Unlock()
554-
if nwConfig.Conflicts(config) {
555-
return types.ForbiddenErrorf("conflicts with network %s (%s)", nw.id, nw.config.BridgeName)
571+
if err := nwConfig.Conflicts(config); err != nil {
572+
return types.ForbiddenErrorf("cannot create network %s (%s): conflicts with network %s (%s): %s",
573+
nwConfig.BridgeName, id, nw.id, nw.config.BridgeName, err.Error())
556574
}
557575
}
558576

@@ -613,10 +631,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
613631
// Even if a bridge exists try to setup IPv4.
614632
bridgeSetup.queueStep(setupBridgeIPv4)
615633

616-
enableIPv6Forwarding := false
617-
if d.config.EnableIPForwarding {
618-
enableIPv6Forwarding = true
619-
}
634+
enableIPv6Forwarding := d.config.EnableIPForwarding && config.AddressIPv6 != nil
620635

621636
// Conditionally queue setup steps depending on configuration values.
622637
for _, step := range []struct {
@@ -797,11 +812,6 @@ func setHairpinMode(link netlink.Link, enable bool) error {
797812
}
798813

799814
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
800-
var (
801-
ipv6Addr *net.IPNet
802-
err error
803-
)
804-
805815
defer osl.InitOSContext()()
806816

807817
if ifInfo == nil {
@@ -931,36 +941,50 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
931941
}
932942
}
933943

934-
ipv4Addr := ifInfo.Address()
944+
// Create the sandbox side pipe interface
945+
endpoint.srcName = containerIfName
946+
endpoint.macAddress = ifInfo.MacAddress()
947+
endpoint.addr = ifInfo.Address()
948+
endpoint.addrv6 = ifInfo.AddressIPv6()
935949

936950
// Down the interface before configuring mac address.
937951
if err = netlink.LinkSetDown(sbox); err != nil {
938952
return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err)
939953
}
940954

941955
// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
942-
mac := ifInfo.MacAddress()
943-
if mac == nil {
944-
mac = electMacAddress(epConfig, ipv4Addr.IP)
956+
if endpoint.macAddress == nil {
957+
endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
958+
if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
959+
return err
960+
}
945961
}
946-
err = netlink.LinkSetHardwareAddr(sbox, mac)
962+
err = netlink.LinkSetHardwareAddr(sbox, endpoint.macAddress)
947963
if err != nil {
948964
return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
949965
}
950-
endpoint.macAddress = mac
951966

952967
// Up the host interface after finishing all netlink configuration
953968
if err = netlink.LinkSetUp(host); err != nil {
954969
return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
955970
}
956971

957-
ipv6Addr = ifInfo.AddressIPv6()
958-
// Create the sandbox side pipe interface
959-
endpoint.srcName = containerIfName
960-
endpoint.addr = ipv4Addr
972+
if endpoint.addrv6 == nil && config.EnableIPv6 {
973+
var ip6 net.IP
974+
network := n.bridge.bridgeIPv6
975+
ones, _ := network.Mask.Size()
976+
if ones <= 80 {
977+
ip6 = make(net.IP, len(network.IP))
978+
copy(ip6, network.IP)
979+
for i, h := range endpoint.macAddress {
980+
ip6[i+10] = h
981+
}
982+
}
961983

962-
if config.EnableIPv6 {
963-
endpoint.addrv6 = ipv6Addr
984+
endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
985+
if err := ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
986+
return err
987+
}
964988
}
965989

966990
// Program any required port mapping and store them in the endpoint
@@ -969,13 +993,6 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
969993
return err
970994
}
971995

972-
if ifInfo.MacAddress() == nil {
973-
err = ifInfo.SetMacAddress(endpoint.macAddress)
974-
if err != nil {
975-
return err
976-
}
977-
}
978-
979996
return nil
980997
}
981998

0 commit comments

Comments
 (0)