mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	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}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										97
									
								
								network.go
									
										
									
									
									
								
							
							
						
						
									
										97
									
								
								network.go
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -12,8 +12,10 @@ import (
 | 
			
		|||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var NetworkBridgeIface string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	networkBridgeIface = "lxcbr0"
 | 
			
		||||
	DefaultNetworkBridge = "lxcbr0"
 | 
			
		||||
	portRangeStart       = 49153
 | 
			
		||||
	portRangeEnd         = 65535
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue