1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

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>
This commit is contained in:
Alessandro Boch 2015-10-29 00:04:08 -07:00
parent f3f0bb75b8
commit 6b40581ea5
7 changed files with 46 additions and 62 deletions

View file

@ -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
}
}

View file

@ -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)},

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)