Merge remote-tracking branch 'origin/219-default-bridge-2'
This commit is contained in:
commit
793c1ad990
6 changed files with 145 additions and 6 deletions
|
@ -135,6 +135,7 @@ type NetworkSettings struct {
|
|||
IpAddress string
|
||||
IpPrefixLen int
|
||||
Gateway string
|
||||
Bridge string
|
||||
PortMapping map[string]string
|
||||
}
|
||||
|
||||
|
@ -491,6 +492,7 @@ func (container *Container) allocateNetwork() error {
|
|||
}
|
||||
}
|
||||
container.network = iface
|
||||
container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface
|
||||
container.NetworkSettings.IpAddress = iface.IPNet.IP.String()
|
||||
container.NetworkSettings.IpPrefixLen, _ = iface.IPNet.Mask.Size()
|
||||
container.NetworkSettings.Gateway = iface.Gateway.String()
|
||||
|
|
|
@ -22,7 +22,13 @@ func main() {
|
|||
// FIXME: Switch d and D ? (to be more sshd like)
|
||||
flDaemon := flag.Bool("d", false, "Daemon mode")
|
||||
flDebug := flag.Bool("D", false, "Debug mode")
|
||||
bridgeName := flag.String("br", "", "")
|
||||
flag.Parse()
|
||||
if *bridgeName != "" {
|
||||
docker.NetworkBridgeIface = *bridgeName
|
||||
} else {
|
||||
docker.NetworkBridgeIface = docker.DefaultNetworkBridge
|
||||
}
|
||||
if *flDebug {
|
||||
os.Setenv("DEBUG", "1")
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ lxc.utsname = {{.Id}}
|
|||
# network configuration
|
||||
lxc.network.type = veth
|
||||
lxc.network.flags = up
|
||||
lxc.network.link = lxcbr0
|
||||
lxc.network.link = {{.NetworkSettings.Bridge}}
|
||||
lxc.network.name = eth0
|
||||
lxc.network.mtu = 1500
|
||||
lxc.network.ipv4 = {{.NetworkSettings.IpAddress}}/{{.NetworkSettings.IpPrefixLen}}
|
||||
|
|
101
network.go
101
network.go
|
@ -12,10 +12,12 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
var NetworkBridgeIface string
|
||||
|
||||
const (
|
||||
networkBridgeIface = "lxcbr0"
|
||||
portRangeStart = 49153
|
||||
portRangeEnd = 65535
|
||||
DefaultNetworkBridge = "lxcbr0"
|
||||
portRangeStart = 49153
|
||||
portRangeEnd = 65535
|
||||
)
|
||||
|
||||
// Calculates the first and last IP addresses in an IPNet
|
||||
|
@ -29,6 +31,19 @@ func networkRange(network *net.IPNet) (net.IP, net.IP) {
|
|||
return firstIP, lastIP
|
||||
}
|
||||
|
||||
// Detects overlap between one IPNet and another
|
||||
func networkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
|
||||
firstIP, _ := networkRange(netX)
|
||||
if netY.Contains(firstIP) {
|
||||
return true
|
||||
}
|
||||
firstIP, _ = networkRange(netY)
|
||||
if netX.Contains(firstIP) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Converts a 4 bytes IP into a 32 bit integer
|
||||
func ipToInt(ip net.IP) int32 {
|
||||
return int32(binary.BigEndian.Uint32(ip.To4()))
|
||||
|
@ -51,6 +66,19 @@ func networkSize(mask net.IPMask) int32 {
|
|||
return int32(binary.BigEndian.Uint32(m)) + 1
|
||||
}
|
||||
|
||||
//Wrapper around the ip command
|
||||
func ip(args ...string) (string, error) {
|
||||
path, err := exec.LookPath("ip")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("command not found: ip")
|
||||
}
|
||||
output, err := exec.Command(path, args...).CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ip failed: ip %v", strings.Join(args, " "))
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
// Wrapper around the iptables command
|
||||
func iptables(args ...string) error {
|
||||
path, err := exec.LookPath("iptables")
|
||||
|
@ -63,6 +91,64 @@ func iptables(args ...string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkRouteOverlaps(dockerNetwork *net.IPNet) error {
|
||||
output, err := ip("route")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Debugf("Routes:\n\n%s", output)
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
if strings.Trim(line, "\r\n\t ") == "" || strings.Contains(line, "default") {
|
||||
continue
|
||||
}
|
||||
if _, network, err := net.ParseCIDR(strings.Split(line, " ")[0]); err != nil {
|
||||
return fmt.Errorf("Unexpected ip route output: %s (%s)", err, line)
|
||||
} else if networkOverlaps(dockerNetwork, network) {
|
||||
return fmt.Errorf("Network %s is already routed: '%s'", dockerNetwork.String(), line)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateBridgeIface(ifaceName string) error {
|
||||
addrs := []string{"172.16.42.1/24", "10.0.42.1/24", "192.168.42.1/24"}
|
||||
|
||||
var ifaceAddr string
|
||||
for _, addr := range addrs {
|
||||
_, dockerNetwork, err := net.ParseCIDR(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkRouteOverlaps(dockerNetwork); err == nil {
|
||||
ifaceAddr = addr
|
||||
break
|
||||
} else {
|
||||
Debugf("%s: %s", addr, err)
|
||||
}
|
||||
}
|
||||
if ifaceAddr == "" {
|
||||
return fmt.Errorf("Impossible to create a bridge. Please create a bridge manually and restart docker with -br <bridgeName>")
|
||||
} else {
|
||||
Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr)
|
||||
}
|
||||
|
||||
if output, err := ip("link", "add", ifaceName, "type", "bridge"); err != nil {
|
||||
return fmt.Errorf("Error creating bridge: %s (output: %s)", err, output)
|
||||
}
|
||||
|
||||
if output, err := ip("addr", "add", ifaceAddr, "dev", ifaceName); err != nil {
|
||||
return fmt.Errorf("Unable to add private network: %s (%s)", err, output)
|
||||
}
|
||||
if output, err := ip("link", "set", ifaceName, "up"); err != nil {
|
||||
return fmt.Errorf("Unable to start network bridge: %s (%s)", err, output)
|
||||
}
|
||||
if err := iptables("-t", "nat", "-A", "POSTROUTING", "-s", ifaceAddr,
|
||||
"!", "-d", ifaceAddr, "-j", "MASQUERADE"); err != nil {
|
||||
return fmt.Errorf("Unable to enable network bridge NAT: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return the IPv4 address of a network interface
|
||||
func getIfaceAddr(name string) (net.Addr, error) {
|
||||
iface, err := net.InterfaceByName(name)
|
||||
|
@ -406,7 +492,14 @@ func (manager *NetworkManager) Allocate() (*NetworkInterface, error) {
|
|||
func newNetworkManager(bridgeIface string) (*NetworkManager, error) {
|
||||
addr, err := getIfaceAddr(bridgeIface)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't find bridge interface %s (%s).\nPlease create it with 'ip link add lxcbr0 type bridge; ip addr add ADDRESS/MASK dev lxcbr0'", bridgeIface, err)
|
||||
// If the iface is not found, try to create it
|
||||
if err := CreateBridgeIface(bridgeIface); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addr, err = getIfaceAddr(bridgeIface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
network := addr.(*net.IPNet)
|
||||
|
||||
|
|
|
@ -253,3 +253,38 @@ func assertIPEquals(t *testing.T, ip1, ip2 net.IP) {
|
|||
t.Fatalf("Expected IP %s, got %s", ip1, ip2)
|
||||
}
|
||||
}
|
||||
|
||||
func AssertOverlap(CIDRx string, CIDRy string, t *testing.T) {
|
||||
_, netX, _ := net.ParseCIDR(CIDRx)
|
||||
_, netY, _ := net.ParseCIDR(CIDRy)
|
||||
if !networkOverlaps(netX, netY) {
|
||||
t.Errorf("%v and %v should overlap", netX, netY)
|
||||
}
|
||||
}
|
||||
|
||||
func AssertNoOverlap(CIDRx string, CIDRy string, t *testing.T) {
|
||||
_, netX, _ := net.ParseCIDR(CIDRx)
|
||||
_, netY, _ := net.ParseCIDR(CIDRy)
|
||||
if networkOverlaps(netX, netY) {
|
||||
t.Errorf("%v and %v should not overlap", netX, netY)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkOverlaps(t *testing.T) {
|
||||
//netY starts at same IP and ends within netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.1/25", t)
|
||||
//netY starts within netX and ends at same IP
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.128/25", t)
|
||||
//netY starts and ends within netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.64/25", t)
|
||||
//netY starts at same IP and ends outside of netX
|
||||
AssertOverlap("172.16.0.1/24", "172.16.0.1/23", t)
|
||||
//netY starts before and ends at same IP of netX
|
||||
AssertOverlap("172.16.1.1/24", "172.16.0.1/23", t)
|
||||
//netY starts before and ends outside of netX
|
||||
AssertOverlap("172.16.1.1/24", "172.16.0.1/23", t)
|
||||
//netY starts and ends before netX
|
||||
AssertNoOverlap("172.16.1.1/25", "172.16.0.1/24", t)
|
||||
//netX starts and ends before netY
|
||||
AssertNoOverlap("172.16.1.1/25", "172.16.2.1/24", t)
|
||||
}
|
||||
|
|
|
@ -267,7 +267,10 @@ func NewRuntimeFromDirectory(root string) (*Runtime, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
|
||||
}
|
||||
netManager, err := newNetworkManager(networkBridgeIface)
|
||||
if NetworkBridgeIface == "" {
|
||||
NetworkBridgeIface = DefaultNetworkBridge
|
||||
}
|
||||
netManager, err := newNetworkManager(NetworkBridgeIface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue