mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
- Added support to bridgeNetwork.Link
- Removed MAC and MTU configuration via AddInterface Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
parent
d6cc62a13b
commit
2d364e2c34
7 changed files with 235 additions and 25 deletions
|
@ -14,10 +14,8 @@ func configureInterface(iface netlink.Link, settings *Interface) error {
|
|||
ErrMessage string
|
||||
}{
|
||||
{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, settings.DstName)},
|
||||
{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC address to %q", ifaceName, settings.MacAddress)},
|
||||
{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, settings.Address)},
|
||||
{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, settings.AddressIPv6)},
|
||||
{setInterfaceMTU, fmt.Sprintf("error setting interface %q MTU to %q", ifaceName, settings.MTU)},
|
||||
{setInterfaceGateway, fmt.Sprintf("error setting interface %q gateway to %q", ifaceName, settings.Gateway)},
|
||||
{setInterfaceGatewayIPv6, fmt.Sprintf("error setting interface %q IPv6 gateway to %q", ifaceName, settings.GatewayIPv6)},
|
||||
}
|
||||
|
@ -78,18 +76,6 @@ func setInterfaceIPv6(iface netlink.Link, settings *Interface) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
func setInterfaceMAC(iface netlink.Link, settings *Interface) (err error) {
|
||||
var hwAddr net.HardwareAddr
|
||||
if hwAddr, err = net.ParseMAC(settings.MacAddress); err == nil {
|
||||
err = netlink.LinkSetHardwareAddr(iface, hwAddr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setInterfaceMTU(iface netlink.Link, settings *Interface) error {
|
||||
return netlink.LinkSetMTU(iface, settings.MTU)
|
||||
}
|
||||
|
||||
func setInterfaceName(iface netlink.Link, settings *Interface) error {
|
||||
return netlink.LinkSetName(iface, settings.DstName)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package bridge
|
||||
|
||||
import "github.com/vishvananda/netlink"
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultBridgeName is the default name for the bridge interface managed
|
||||
|
@ -10,8 +14,10 @@ const (
|
|||
|
||||
// Interface models the bridge network device.
|
||||
type bridgeInterface struct {
|
||||
Config *Configuration
|
||||
Link netlink.Link
|
||||
Config *Configuration
|
||||
Link netlink.Link
|
||||
bridgeIPv4 *net.IPNet
|
||||
bridgeIPv6 *net.IPNet
|
||||
}
|
||||
|
||||
// NewInterface creates a new bridge interface structure. It attempts to find
|
||||
|
|
|
@ -1,13 +1,23 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/libcontainer/utils"
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/docker/libnetwork/ipallocator"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
// ErrEndpointExists is returned if more than one endpoint is added to the network
|
||||
var ErrEndpointExists = errors.New("Endpoint already exists (Only one endpoint allowed)")
|
||||
|
||||
type bridgeNetwork struct {
|
||||
NetworkName string
|
||||
bridge *bridgeInterface
|
||||
EndPoint *libnetwork.Interface
|
||||
}
|
||||
|
||||
func (b *bridgeNetwork) Name() string {
|
||||
|
@ -19,8 +29,99 @@ func (b *bridgeNetwork) Type() string {
|
|||
}
|
||||
|
||||
func (b *bridgeNetwork) Link(name string) ([]*libnetwork.Interface, error) {
|
||||
// TODO
|
||||
return nil, nil
|
||||
|
||||
var ipv6Addr net.IPNet
|
||||
|
||||
if b.EndPoint != nil {
|
||||
return nil, ErrEndpointExists
|
||||
}
|
||||
|
||||
name1, err := generateIfaceName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
name2, err := generateIfaceName()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
veth := &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
|
||||
PeerName: name2}
|
||||
if err := netlink.LinkAdd(veth); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
host, err := netlink.LinkByName(name1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
netlink.LinkDel(host)
|
||||
}
|
||||
}()
|
||||
|
||||
container, err := netlink.LinkByName(name2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
netlink.LinkDel(container)
|
||||
}
|
||||
}()
|
||||
|
||||
if err = netlink.LinkSetMaster(host,
|
||||
&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: b.bridge.Config.BridgeName}}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ip4, err := ipallocator.RequestIP(b.bridge.bridgeIPv4, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv4Addr := net.IPNet{IP: ip4, Mask: b.bridge.bridgeIPv4.Mask}
|
||||
|
||||
if b.bridge.Config.EnableIPv6 {
|
||||
ip6, err := ipallocator.RequestIP(b.bridge.bridgeIPv6, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipv6Addr = net.IPNet{IP: ip6, Mask: b.bridge.bridgeIPv6.Mask}
|
||||
}
|
||||
|
||||
var interfaces []*libnetwork.Interface
|
||||
intf := &libnetwork.Interface{}
|
||||
intf.SrcName = name2
|
||||
intf.DstName = "eth0"
|
||||
intf.Address = ipv4Addr.String()
|
||||
intf.Gateway = b.bridge.bridgeIPv4.IP.String()
|
||||
if b.bridge.Config.EnableIPv6 {
|
||||
intf.AddressIPv6 = ipv6Addr.String()
|
||||
intf.GatewayIPv6 = b.bridge.bridgeIPv6.IP.String()
|
||||
}
|
||||
|
||||
b.EndPoint = intf
|
||||
interfaces = append(interfaces, intf)
|
||||
return interfaces, nil
|
||||
}
|
||||
|
||||
func generateIfaceName() (string, error) {
|
||||
for i := 0; i < 10; i++ {
|
||||
name, err := utils.GenerateRandomName("veth", 7)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if _, err := net.InterfaceByName(name); err != nil {
|
||||
if strings.Contains(err.Error(), "no such") {
|
||||
return name, nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return "", errors.New("Failed to find name for new interface")
|
||||
}
|
||||
|
||||
func (b *bridgeNetwork) Delete() error {
|
||||
|
|
119
libnetwork/drivers/bridge/network_test.go
Normal file
119
libnetwork/drivers/bridge/network_test.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
func TestLinkCreate(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
|
||||
config := &Configuration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableIPv6: true}
|
||||
netw, err := d.CreateNetwork("dummy", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
interfaces, err := netw.Link("ep")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %v", err)
|
||||
}
|
||||
|
||||
if len(interfaces) != 1 {
|
||||
t.Fatalf("Expected exactly one interface. Instead got %d interface(s)", len(interfaces))
|
||||
}
|
||||
|
||||
if interfaces[0].DstName == "" {
|
||||
t.Fatal("Invalid Dstname returned")
|
||||
}
|
||||
|
||||
_, err = netlink.LinkByName(interfaces[0].SrcName)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not find source link %s: %v", interfaces[0].SrcName, err)
|
||||
}
|
||||
|
||||
ip, _, err := net.ParseCIDR(interfaces[0].Address)
|
||||
if err != nil {
|
||||
t.Fatalf("Invalid IPv4 address returned, ip = %s: %v", interfaces[0].Address, err)
|
||||
}
|
||||
|
||||
b := netw.(*bridgeNetwork)
|
||||
if !b.bridge.bridgeIPv4.Contains(ip) {
|
||||
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), b.bridge.bridgeIPv4.String())
|
||||
}
|
||||
|
||||
ip6, _, err := net.ParseCIDR(interfaces[0].AddressIPv6)
|
||||
if err != nil {
|
||||
t.Fatalf("Invalid IPv6 address returned, ip = %s: %v", interfaces[0].AddressIPv6, err)
|
||||
}
|
||||
|
||||
if !b.bridge.bridgeIPv6.Contains(ip6) {
|
||||
t.Fatalf("IP %s is not a valid ip in the subnet %s", ip6.String(), bridgeIPv6.String())
|
||||
}
|
||||
|
||||
if interfaces[0].Gateway != b.bridge.bridgeIPv4.IP.String() {
|
||||
t.Fatalf("Invalid default gateway. Expected %s. Got %s", b.bridge.bridgeIPv4.IP.String(),
|
||||
interfaces[0].Gateway)
|
||||
}
|
||||
|
||||
if interfaces[0].GatewayIPv6 != b.bridge.bridgeIPv6.IP.String() {
|
||||
t.Fatalf("Invalid default gateway for IPv6. Expected %s. Got %s", b.bridge.bridgeIPv6.IP.String(),
|
||||
interfaces[0].GatewayIPv6)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkCreateTwo(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
|
||||
config := &Configuration{
|
||||
BridgeName: DefaultBridgeName,
|
||||
EnableIPv6: true}
|
||||
netw, err := d.CreateNetwork("dummy", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
_, err = netw.Link("ep")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %v", err)
|
||||
}
|
||||
|
||||
_, err = netw.Link("ep1")
|
||||
if err != nil {
|
||||
if err != ErrEndpointExists {
|
||||
t.Fatalf("Failed with a wrong error :%v", err)
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("Expected to fail while trying to add more than one endpoint")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkCreateNoEnableIPv6(t *testing.T) {
|
||||
defer libnetwork.SetupTestNetNS(t)()
|
||||
d := &driver{}
|
||||
|
||||
config := &Configuration{
|
||||
BridgeName: DefaultBridgeName}
|
||||
netw, err := d.CreateNetwork("dummy", config)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create bridge: %v", err)
|
||||
}
|
||||
|
||||
interfaces, err := netw.Link("ep")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create a link: %v", err)
|
||||
}
|
||||
|
||||
if interfaces[0].AddressIPv6 != "" ||
|
||||
interfaces[0].GatewayIPv6 != "" {
|
||||
t.Fatalf("Expected IPv6 address and GatewayIPv6 to be empty when IPv6 enabled. Instead got IPv6 = %s and GatewayIPv6 = %s",
|
||||
interfaces[0].AddressIPv6, interfaces[0].GatewayIPv6)
|
||||
}
|
||||
}
|
|
@ -52,6 +52,8 @@ func setupBridgeIPv4(i *bridgeInterface) error {
|
|||
return fmt.Errorf("Failed to add IPv4 address %s to bridge: %v", bridgeIPv4, err)
|
||||
}
|
||||
|
||||
i.bridgeIPv4 = bridgeIPv4
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -33,5 +33,7 @@ func setupBridgeIPv6(i *bridgeInterface) error {
|
|||
return fmt.Errorf("Failed to add IPv6 address %s to bridge: %v", bridgeIPv6, err)
|
||||
}
|
||||
|
||||
i.bridgeIPv6 = bridgeIPv6
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -44,9 +44,6 @@ type Interface struct {
|
|||
// network namespace.
|
||||
DstName string
|
||||
|
||||
// MAC address for the interface.
|
||||
MacAddress string
|
||||
|
||||
// IPv4 address for the interface.
|
||||
Address string
|
||||
|
||||
|
@ -58,9 +55,6 @@ type Interface struct {
|
|||
|
||||
// IPv6 gateway for the interface.
|
||||
GatewayIPv6 string
|
||||
|
||||
// Network MTU.
|
||||
MTU int
|
||||
}
|
||||
|
||||
// A Network represents a logical connectivity zone that containers may
|
||||
|
|
Loading…
Reference in a new issue