Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 63 additions & 15 deletions bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,76 @@ import (
"github.com/docker/libnetwork"
)

const networkType = "bridgednetwork"
const (
NetworkType = "simplebridge"
VethPrefix = "veth"
)

type bridgeConfiguration struct {
Subnet net.IPNet
type Configuration struct {
BridgeName string
AddressIPv4 *net.IPNet
FixedCIDR *net.IPNet
FixedCIDRv6 *net.IPNet
EnableIPv6 bool
EnableIPTables bool
EnableIPForwarding bool
}

func init() {
libnetwork.RegisterNetworkType(networkType, Create, &bridgeConfiguration{})
libnetwork.RegisterNetworkType(NetworkType, Create, &Configuration{})
}

func Create(config *bridgeConfiguration) (libnetwork.Network, error) {
return &bridgeNetwork{Config: *config}, nil
}
func Create(config *Configuration) (libnetwork.Network, error) {
bridgeIntfc := NewInterface(config)
bridgeSetup := NewBridgeSetup(bridgeIntfc)

type bridgeNetwork struct {
Config bridgeConfiguration
}
// If the bridge interface doesn't exist, we need to start the setup steps
// by creating a new device and assigning it an IPv4 address.
bridgeAlreadyExists := bridgeIntfc.Exists()
if !bridgeAlreadyExists {
bridgeSetup.QueueStep(SetupDevice)
bridgeSetup.QueueStep(SetupBridgeIPv4)
}

func (b *bridgeNetwork) Type() string {
return networkType
}
// Conditionnally queue setup steps depending on configuration values.
for _, step := range []struct {
Condition bool
Fn SetupStep
}{
// Enable IPv6 on the bridge if required. We do this even for a
// previously existing bridge, as it may be here from a previous
// installation where IPv6 wasn't supported yet and needs to be
// assigned an IPv6 link-local address.
{config.EnableIPv6, SetupBridgeIPv6},

// We ensure that the bridge has the expectedIPv4 and IPv6 addresses in
// the case of a previously existing device.
{bridgeAlreadyExists, SetupVerifyConfiguredAddresses},

// Setup the bridge to allocate containers IPv4 addresses in the
// specified subnet.
{config.FixedCIDR != nil, SetupFixedCIDRv4},

// Setup the bridge to allocate containers global IPv6 addresses in the
// specified subnet.
{config.FixedCIDRv6 != nil, SetupFixedCIDRv6},

// Setup IPTables.
{config.EnableIPTables, SetupIPTables},

// Setup IP forwarding.
{config.EnableIPForwarding, SetupIPForwarding},
} {
if step.Condition {
bridgeSetup.QueueStep(step.Fn)
}
}

// Apply the prepared list of steps, and abort at the first error.
bridgeSetup.QueueStep(SetupDeviceUp)
if err := bridgeSetup.Apply(); err != nil {
return nil, err
}

func (b *bridgeNetwork) Link(name string) ([]*libnetwork.Interface, error) {
return nil, nil
return &bridgeNetwork{*config}, nil
}
48 changes: 48 additions & 0 deletions bridge/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package bridge

import "github.com/vishvananda/netlink"

const (
DefaultBridgeName = "docker0"
)

type Interface struct {
Config *Configuration
Link netlink.Link
}

func NewInterface(config *Configuration) *Interface {
i := &Interface{
Config: config,
}

// Initialize the bridge name to the default if unspecified.
if i.Config.BridgeName == "" {
i.Config.BridgeName = DefaultBridgeName
}

// Attempt to find an existing bridge named with the specified name.
i.Link, _ = netlink.LinkByName(i.Config.BridgeName)
return i
}

// Exists indicates if the existing bridge interface exists on the system.
func (i *Interface) Exists() bool {
return i.Link != nil
}

// Addresses returns a single IPv4 address and all IPv6 addresses for the
// bridge interface.
func (i *Interface) Addresses() (netlink.Addr, []netlink.Addr, error) {
v4addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V4)
if err != nil {
return netlink.Addr{}, nil, err
}

v6addr, err := netlink.AddrList(i.Link, netlink.FAMILY_V6)
if err != nil {
return netlink.Addr{}, nil, err
}

return v4addr[0], v6addr, nil
}
15 changes: 15 additions & 0 deletions bridge/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package bridge

import "github.com/docker/libnetwork"

type bridgeNetwork struct {
Config Configuration
}

func (b *bridgeNetwork) Type() string {
return NetworkType
}

func (b *bridgeNetwork) Link(name string) ([]*libnetwork.Interface, error) {
return nil, nil
}
35 changes: 35 additions & 0 deletions bridge/setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package bridge

type SetupStep func(*Interface) error

type BridgeSetup struct {
bridge *Interface
steps []SetupStep
}

func NewBridgeSetup(i *Interface) *BridgeSetup {
return &BridgeSetup{bridge: i}
}

func (b *BridgeSetup) Apply() error {
for _, fn := range b.steps {
if err := fn(b.bridge); err != nil {
return err
}
}
return nil
}

func (b *BridgeSetup) QueueStep(step SetupStep) {
b.steps = append(b.steps, step)
}

//---------------------------------------------------------------------------//

func SetupIPTables(i *Interface) error {
return nil
}

func SetupIPForwarding(i *Interface) error {
return nil
}
53 changes: 53 additions & 0 deletions bridge/setup_device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package bridge

import (
"fmt"
"math/rand"
"net"

log "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/vishvananda/netlink"
)

// SetupDevice create a new bridge interface/
func SetupDevice(i *Interface) error {
// We only attempt to create the bridge when the requested device name is
// the default one.
if i.Config.BridgeName != DefaultBridgeName {
return fmt.Errorf("bridge device with non default name %q must be created manually", i.Config.BridgeName)
}

// Set the Interface netlink.Bridge.
i.Link = &netlink.Bridge{
LinkAttrs: netlink.LinkAttrs{
Name: i.Config.BridgeName,
},
}

// Only set the bridge's MAC address if the kernel version is > 3.3, as it
// was not supported before that.
kv, err := kernel.GetKernelVersion()
if err == nil && (kv.Kernel >= 3 && kv.Major >= 3) {
i.Link.Attrs().HardwareAddr = generateRandomMAC()
log.Debugf("Setting bridge mac address to %s", i.Link.Attrs().HardwareAddr)
}

// Call out to netlink to create the device.
return netlink.LinkAdd(i.Link)
}

// SetupDeviceUp ups the given bridge interface.
func SetupDeviceUp(i *Interface) error {
return netlink.LinkSetUp(i.Link)
}

func generateRandomMAC() net.HardwareAddr {
hw := make(net.HardwareAddr, 6)
for i := 0; i < 6; i++ {
hw[i] = byte(rand.Intn(255))
}
hw[0] &^= 0x1 // clear multicast bit
hw[0] |= 0x2 // set local assignment bit (IEEE802)
return hw
}
16 changes: 16 additions & 0 deletions bridge/setup_fixedcidrv4.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package bridge

import (
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/networkdriver/ipallocator"
)

func SetupFixedCIDRv4(i *Interface) error {
addrv4, _, err := i.Addresses()
if err != nil {
return err
}

log.Debugf("Using IPv4 subnet: %v", i.Config.FixedCIDR)
return ipallocator.RegisterSubnet(addrv4.IPNet, i.Config.FixedCIDR)
}
11 changes: 11 additions & 0 deletions bridge/setup_fixedcidrv6.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package bridge

import (
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/networkdriver/ipallocator"
)

func SetupFixedCIDRv6(i *Interface) error {
log.Debugf("Using IPv6 subnet: %v", i.Config.FixedCIDRv6)
return ipallocator.RegisterSubnet(i.Config.FixedCIDRv6, i.Config.FixedCIDRv6)
}
Loading