diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index 7991c6f67c..3169753391 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -934,28 +934,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 { @@ -982,7 +973,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 } } diff --git a/libnetwork/drivers/bridge/bridge_test.go b/libnetwork/drivers/bridge/bridge_test.go index e039a53e61..54b43d2dff 100644 --- a/libnetwork/drivers/bridge/bridge_test.go +++ b/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 { @@ -497,50 +495,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{ types.TransportPort{Proto: types.TCP, Port: uint16(5000)}, diff --git a/libnetwork/drivers/remote/driver_test.go b/libnetwork/drivers/remote/driver_test.go index da1a365df3..f71c4e3238 100644 --- a/libnetwork/drivers/remote/driver_test.go +++ b/libnetwork/drivers/remote/driver_test.go @@ -1,6 +1,7 @@ package remote import ( + "bytes" "encoding/json" "fmt" "io/ioutil" @@ -290,7 +291,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", @@ -326,7 +327,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, @@ -401,11 +404,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 { diff --git a/libnetwork/osl/interface_linux.go b/libnetwork/osl/interface_linux.go index d57e7601b1..b448ea8627 100644 --- a/libnetwork/osl/interface_linux.go +++ b/libnetwork/osl/interface_linux.go @@ -19,6 +19,7 @@ type nwIface struct { dstName string master string dstMaster string + mac net.HardwareAddr address *net.IPNet addressIPv6 *net.IPNet routes []*net.IPNet @@ -62,6 +63,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() @@ -291,6 +299,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())}, @@ -313,6 +322,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 diff --git a/libnetwork/osl/options_linux.go b/libnetwork/osl/options_linux.go index 5295eb85c5..ea28e8b6be 100644 --- a/libnetwork/osl/options_linux.go +++ b/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 diff --git a/libnetwork/osl/sandbox.go b/libnetwork/osl/sandbox.go index 3a824ae6ad..db49d43dce 100644 --- a/libnetwork/osl/sandbox.go +++ b/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 diff --git a/libnetwork/sandbox.go b/libnetwork/sandbox.go index d24c43a460..b53f62dc0c 100644 --- a/libnetwork/sandbox.go +++ b/libnetwork/sandbox.go @@ -466,6 +466,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)