Skip to content

Commit 48d1403

Browse files
committed
Libnetwork to set container interface's MAC
- Consistently with what it does for IP addresses, libnetwork will also program the container interface's MAC address with the value set by network driver in InterfaceInfo. Signed-off-by: Alessandro Boch <aboch@docker.com>
1 parent 077b076 commit 48d1403

7 files changed

Lines changed: 46 additions & 62 deletions

File tree

drivers/bridge/bridge.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -934,28 +934,19 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
934934
}
935935
}
936936

937-
// Create the sandbox side pipe interface
937+
// Store the sandbox side pipe interface parameters
938938
endpoint.srcName = containerIfName
939939
endpoint.macAddress = ifInfo.MacAddress()
940940
endpoint.addr = ifInfo.Address()
941941
endpoint.addrv6 = ifInfo.AddressIPv6()
942942

943-
// Down the interface before configuring mac address.
944-
if err = netlink.LinkSetDown(sbox); err != nil {
945-
return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err)
946-
}
947-
948-
// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
943+
// Set the sbox's MAC if not provided. If specified, use the one configured by user, otherwise generate one based on IP.
949944
if endpoint.macAddress == nil {
950945
endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
951-
if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
946+
if err = ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
952947
return err
953948
}
954949
}
955-
err = netlink.LinkSetHardwareAddr(sbox, endpoint.macAddress)
956-
if err != nil {
957-
return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
958-
}
959950

960951
// Up the host interface after finishing all netlink configuration
961952
if err = netlink.LinkSetUp(host); err != nil {
@@ -982,7 +973,7 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
982973
}
983974

984975
endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
985-
if err := ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
976+
if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
986977
return err
987978
}
988979
}

drivers/bridge/bridge_test.go

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package bridge
22

33
import (
4-
"bytes"
54
"fmt"
65
"net"
76
"regexp"
@@ -13,7 +12,6 @@ import (
1312
"github.com/docker/libnetwork/netlabel"
1413
"github.com/docker/libnetwork/testutils"
1514
"github.com/docker/libnetwork/types"
16-
"github.com/vishvananda/netlink"
1715
)
1816

1917
func getIPv4Data(t *testing.T) []driverapi.IPAMData {
@@ -497,50 +495,6 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
497495
}
498496
}
499497

500-
func TestCreateLinkWithOptions(t *testing.T) {
501-
defer testutils.SetupTestOSContext(t)()
502-
d := newDriver()
503-
504-
if err := d.configure(nil); err != nil {
505-
t.Fatalf("Failed to setup driver config: %v", err)
506-
}
507-
508-
netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
509-
netOptions := make(map[string]interface{})
510-
netOptions[netlabel.GenericData] = netconfig
511-
512-
ipdList := getIPv4Data(t)
513-
err := d.CreateNetwork("net1", netOptions, ipdList, nil)
514-
if err != nil {
515-
t.Fatalf("Failed to create bridge: %v", err)
516-
}
517-
518-
mac := net.HardwareAddr([]byte{0x1e, 0x67, 0x66, 0x44, 0x55, 0x66})
519-
epOptions := make(map[string]interface{})
520-
epOptions[netlabel.MacAddress] = mac
521-
522-
te := newTestEndpoint(ipdList[0].Pool, 11)
523-
err = d.CreateEndpoint("net1", "ep", te.Interface(), epOptions)
524-
if err != nil {
525-
t.Fatalf("Failed to create an endpoint: %s", err.Error())
526-
}
527-
528-
err = d.Join("net1", "ep", "sbox", te, nil)
529-
if err != nil {
530-
t.Fatalf("Failed to join the endpoint: %v", err)
531-
}
532-
533-
ifaceName := te.iface.srcName
534-
veth, err := netlink.LinkByName(ifaceName)
535-
if err != nil {
536-
t.Fatal(err)
537-
}
538-
539-
if !bytes.Equal(mac, veth.Attrs().HardwareAddr) {
540-
t.Fatalf("Failed to parse and program endpoint configuration")
541-
}
542-
}
543-
544498
func getExposedPorts() []types.TransportPort {
545499
return []types.TransportPort{
546500
types.TransportPort{Proto: types.TCP, Port: uint16(5000)},

drivers/remote/driver_test.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package remote
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
67
"io/ioutil"
@@ -290,7 +291,7 @@ func TestRemoteDriver(t *testing.T) {
290291
dst: "vethdst",
291292
address: "192.168.5.7/16",
292293
addressIPv6: "2001:DB8::5:7/48",
293-
macAddress: "",
294+
macAddress: "ab:cd:ef:ee:ee:ee",
294295
gateway: "192.168.0.1",
295296
gatewayIPv6: "2001:DB8::1",
296297
hostsPath: "/here/comes/the/host/path",
@@ -326,7 +327,9 @@ func TestRemoteDriver(t *testing.T) {
326327
})
327328
handle(t, mux, "CreateEndpoint", func(msg map[string]interface{}) interface{} {
328329
iface := map[string]interface{}{
329-
"MacAddress": ep.macAddress,
330+
"MacAddress": ep.macAddress,
331+
"Address": ep.address,
332+
"AddressIPv6": ep.addressIPv6,
330333
}
331334
return map[string]interface{}{
332335
"Interface": iface,
@@ -401,11 +404,19 @@ func TestRemoteDriver(t *testing.T) {
401404
}
402405

403406
endID := "dummy-endpoint"
404-
err = d.CreateEndpoint(netID, endID, ep, map[string]interface{}{})
407+
ifInfo := &testEndpoint{}
408+
err = d.CreateEndpoint(netID, endID, ifInfo, map[string]interface{}{})
405409
if err != nil {
406410
t.Fatal(err)
407411
}
408412

413+
if !bytes.Equal(ep.MacAddress(), ifInfo.MacAddress()) || !types.CompareIPNet(ep.Address(), ifInfo.Address()) ||
414+
!types.CompareIPNet(ep.AddressIPv6(), ifInfo.AddressIPv6()) {
415+
t.Fatalf("Unexpected InterfaceInfo data. Expected (%s, %s, %s). Got (%v, %v, %v)",
416+
ep.MacAddress(), ep.Address(), ep.AddressIPv6(),
417+
ifInfo.MacAddress(), ifInfo.Address(), ifInfo.AddressIPv6())
418+
}
419+
409420
joinOpts := map[string]interface{}{"foo": "fooValue"}
410421
err = d.Join(netID, endID, "sandbox-key", ep, joinOpts)
411422
if err != nil {

osl/interface_linux.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type nwIface struct {
1919
dstName string
2020
master string
2121
dstMaster string
22+
mac net.HardwareAddr
2223
address *net.IPNet
2324
addressIPv6 *net.IPNet
2425
routes []*net.IPNet
@@ -62,6 +63,13 @@ func (i *nwIface) Master() string {
6263
return i.master
6364
}
6465

66+
func (i *nwIface) MacAddress() net.HardwareAddr {
67+
i.Lock()
68+
defer i.Unlock()
69+
70+
return types.GetMacCopy(i.mac)
71+
}
72+
6573
func (i *nwIface) Address() *net.IPNet {
6674
i.Lock()
6775
defer i.Unlock()
@@ -291,6 +299,7 @@ func configureInterface(iface netlink.Link, i *nwIface) error {
291299
ErrMessage string
292300
}{
293301
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
302+
{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())},
294303
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, i.Address())},
295304
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, i.AddressIPv6())},
296305
{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 {
313322
LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
314323
}
315324

325+
func setInterfaceMAC(iface netlink.Link, i *nwIface) error {
326+
if i.MacAddress() == nil {
327+
return nil
328+
}
329+
return netlink.LinkSetHardwareAddr(iface, i.MacAddress())
330+
}
331+
316332
func setInterfaceIP(iface netlink.Link, i *nwIface) error {
317333
if i.Address() == nil {
318334
return nil

osl/options_linux.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ func (n *networkNamespace) Master(name string) IfaceOption {
4242
}
4343
}
4444

45+
func (n *networkNamespace) MacAddress(mac net.HardwareAddr) IfaceOption {
46+
return func(i *nwIface) {
47+
i.mac = mac
48+
}
49+
}
50+
4551
func (n *networkNamespace) Address(addr *net.IPNet) IfaceOption {
4652
return func(i *nwIface) {
4753
i.address = addr

osl/sandbox.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ type IfaceOptionSetter interface {
7676
// Bridge returns an option setter to set if the interface is a bridge.
7777
Bridge(bool) IfaceOption
7878

79+
// MacAddress returns an option setter to set the MAC address.
80+
MacAddress(net.HardwareAddr) IfaceOption
81+
7982
// Address returns an option setter to set IPv4 address.
8083
Address(*net.IPNet) IfaceOption
8184

sandbox.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
466466
if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
467467
ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
468468
}
469+
if i.mac != nil {
470+
ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac))
471+
}
469472

470473
if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
471474
return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)

0 commit comments

Comments
 (0)