Ver Fonte

Merge pull request #803 from aboch/pm

Libnetwork to program container interface's MAC
Madhu Venugopal há 9 anos atrás
pai
commit
86db344e56

+ 4 - 13
libnetwork/drivers/bridge/bridge.go

@@ -951,28 +951,19 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 		}
 	}
 
-	// Create the sandbox side pipe interface
+	// Store the sandbox side pipe interface parameters
 	endpoint.srcName = containerIfName
 	endpoint.macAddress = ifInfo.MacAddress()
 	endpoint.addr = ifInfo.Address()
 	endpoint.addrv6 = ifInfo.AddressIPv6()
 
-	// Down the interface before configuring mac address.
-	if err = netlink.LinkSetDown(sbox); err != nil {
-		return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err)
-	}
-
-	// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
+	// Set the sbox's MAC if not provided. If specified, use the one configured by user, otherwise generate one based on IP.
 	if endpoint.macAddress == nil {
 		endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
-		if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
+		if err = ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
 			return err
 		}
 	}
-	err = netlink.LinkSetHardwareAddr(sbox, endpoint.macAddress)
-	if err != nil {
-		return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
-	}
 
 	// Up the host interface after finishing all netlink configuration
 	if err = netlink.LinkSetUp(host); err != nil {
@@ -999,7 +990,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 		}
 
 		endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
-		if err := ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
+		if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
 			return err
 		}
 	}

+ 0 - 46
libnetwork/drivers/bridge/bridge_test.go

@@ -1,7 +1,6 @@
 package bridge
 
 import (
-	"bytes"
 	"fmt"
 	"net"
 	"regexp"
@@ -13,7 +12,6 @@ import (
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/testutils"
 	"github.com/docker/libnetwork/types"
-	"github.com/vishvananda/netlink"
 )
 
 func getIPv4Data(t *testing.T) []driverapi.IPAMData {
@@ -506,50 +504,6 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
 	}
 }
 
-func TestCreateLinkWithOptions(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
-	d := newDriver()
-
-	if err := d.configure(nil); err != nil {
-		t.Fatalf("Failed to setup driver config: %v", err)
-	}
-
-	netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
-	netOptions := make(map[string]interface{})
-	netOptions[netlabel.GenericData] = netconfig
-
-	ipdList := getIPv4Data(t)
-	err := d.CreateNetwork("net1", netOptions, ipdList, nil)
-	if err != nil {
-		t.Fatalf("Failed to create bridge: %v", err)
-	}
-
-	mac := net.HardwareAddr([]byte{0x1e, 0x67, 0x66, 0x44, 0x55, 0x66})
-	epOptions := make(map[string]interface{})
-	epOptions[netlabel.MacAddress] = mac
-
-	te := newTestEndpoint(ipdList[0].Pool, 11)
-	err = d.CreateEndpoint("net1", "ep", te.Interface(), epOptions)
-	if err != nil {
-		t.Fatalf("Failed to create an endpoint: %s", err.Error())
-	}
-
-	err = d.Join("net1", "ep", "sbox", te, nil)
-	if err != nil {
-		t.Fatalf("Failed to join the endpoint: %v", err)
-	}
-
-	ifaceName := te.iface.srcName
-	veth, err := netlink.LinkByName(ifaceName)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if !bytes.Equal(mac, veth.Attrs().HardwareAddr) {
-		t.Fatalf("Failed to parse and program endpoint configuration")
-	}
-}
-
 func getExposedPorts() []types.TransportPort {
 	return []types.TransportPort{
 		{Proto: types.TCP, Port: uint16(5000)},

+ 14 - 3
libnetwork/drivers/remote/driver_test.go

@@ -1,6 +1,7 @@
 package remote
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
 	"io"
@@ -292,7 +293,7 @@ func TestRemoteDriver(t *testing.T) {
 		dst:            "vethdst",
 		address:        "192.168.5.7/16",
 		addressIPv6:    "2001:DB8::5:7/48",
-		macAddress:     "",
+		macAddress:     "ab:cd:ef:ee:ee:ee",
 		gateway:        "192.168.0.1",
 		gatewayIPv6:    "2001:DB8::1",
 		hostsPath:      "/here/comes/the/host/path",
@@ -328,7 +329,9 @@ func TestRemoteDriver(t *testing.T) {
 	})
 	handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
 		iface := map[string]interface{}{
-			"MacAddress": ep.macAddress,
+			"MacAddress":  ep.macAddress,
+			"Address":     ep.address,
+			"AddressIPv6": ep.addressIPv6,
 		}
 		return map[string]interface{}{
 			"Interface": iface,
@@ -403,11 +406,19 @@ func TestRemoteDriver(t *testing.T) {
 	}
 
 	endID := "dummy-endpoint"
-	err = d.CreateEndpoint(netID, endID, ep, map[string]interface{}{})
+	ifInfo := &testEndpoint{}
+	err = d.CreateEndpoint(netID, endID, ifInfo, map[string]interface{}{})
 	if err != nil {
 		t.Fatal(err)
 	}
 
+	if !bytes.Equal(ep.MacAddress(), ifInfo.MacAddress()) || !types.CompareIPNet(ep.Address(), ifInfo.Address()) ||
+		!types.CompareIPNet(ep.AddressIPv6(), ifInfo.AddressIPv6()) {
+		t.Fatalf("Unexpected InterfaceInfo data. Expected (%s, %s, %s). Got (%v, %v, %v)",
+			ep.MacAddress(), ep.Address(), ep.AddressIPv6(),
+			ifInfo.MacAddress(), ifInfo.Address(), ifInfo.AddressIPv6())
+	}
+
 	joinOpts := map[string]interface{}{"foo": "fooValue"}
 	err = d.Join(netID, endID, "sandbox-key", ep, joinOpts)
 	if err != nil {

+ 16 - 0
libnetwork/osl/interface_linux.go

@@ -21,6 +21,7 @@ type nwIface struct {
 	dstName     string
 	master      string
 	dstMaster   string
+	mac         net.HardwareAddr
 	address     *net.IPNet
 	addressIPv6 *net.IPNet
 	routes      []*net.IPNet
@@ -64,6 +65,13 @@ func (i *nwIface) Master() string {
 	return i.master
 }
 
+func (i *nwIface) MacAddress() net.HardwareAddr {
+	i.Lock()
+	defer i.Unlock()
+
+	return types.GetMacCopy(i.mac)
+}
+
 func (i *nwIface) Address() *net.IPNet {
 	i.Lock()
 	defer i.Unlock()
@@ -304,6 +312,7 @@ func configureInterface(iface netlink.Link, i *nwIface) error {
 		ErrMessage string
 	}{
 		{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
+		{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())},
 		{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, i.Address())},
 		{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, i.AddressIPv6())},
 		{setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())},
@@ -326,6 +335,13 @@ func setInterfaceMaster(iface netlink.Link, i *nwIface) error {
 		LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
 }
 
+func setInterfaceMAC(iface netlink.Link, i *nwIface) error {
+	if i.MacAddress() == nil {
+		return nil
+	}
+	return netlink.LinkSetHardwareAddr(iface, i.MacAddress())
+}
+
 func setInterfaceIP(iface netlink.Link, i *nwIface) error {
 	if i.Address() == nil {
 		return nil

+ 6 - 0
libnetwork/osl/options_linux.go

@@ -42,6 +42,12 @@ func (n *networkNamespace) Master(name string) IfaceOption {
 	}
 }
 
+func (n *networkNamespace) MacAddress(mac net.HardwareAddr) IfaceOption {
+	return func(i *nwIface) {
+		i.mac = mac
+	}
+}
+
 func (n *networkNamespace) Address(addr *net.IPNet) IfaceOption {
 	return func(i *nwIface) {
 		i.address = addr

+ 3 - 0
libnetwork/osl/sandbox.go

@@ -76,6 +76,9 @@ type IfaceOptionSetter interface {
 	// Bridge returns an option setter to set if the interface is a bridge.
 	Bridge(bool) IfaceOption
 
+	// MacAddress returns an option setter to set the MAC address.
+	MacAddress(net.HardwareAddr) IfaceOption
+
 	// Address returns an option setter to set IPv4 address.
 	Address(*net.IPNet) IfaceOption
 

+ 3 - 0
libnetwork/sandbox.go

@@ -613,6 +613,9 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
 		if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
 			ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
 		}
+		if i.mac != nil {
+			ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac))
+		}
 
 		if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
 			return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)