Skip to content

Commit

Permalink
Merge pull request #1 from icecrime/bridge_refactoring
Browse files Browse the repository at this point in the history
Bridge refactoring - Step 1
  • Loading branch information
Arnaud Porterie committed Feb 23, 2015
2 parents 7ae486c + a5549ad commit 7f8fd9f
Show file tree
Hide file tree
Showing 13 changed files with 441 additions and 20 deletions.
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

0 comments on commit 7f8fd9f

Please sign in to comment.