github.com/codemac/docker@v1.2.1-0.20150518222241-6a18412d5b9c/daemon/networkdriver/bridge/driver.go (about) 1 package bridge 2 3 import ( 4 "encoding/hex" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "net" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "strconv" 13 "strings" 14 "sync" 15 16 "github.com/Sirupsen/logrus" 17 "github.com/docker/docker/daemon/network" 18 "github.com/docker/docker/daemon/networkdriver" 19 "github.com/docker/docker/daemon/networkdriver/ipallocator" 20 "github.com/docker/docker/daemon/networkdriver/portmapper" 21 "github.com/docker/docker/nat" 22 "github.com/docker/docker/pkg/iptables" 23 "github.com/docker/docker/pkg/parsers/kernel" 24 "github.com/docker/docker/pkg/resolvconf" 25 "github.com/docker/libcontainer/netlink" 26 ) 27 28 const ( 29 DefaultNetworkBridge = "docker0" 30 MaxAllocatedPortAttempts = 10 31 ) 32 33 // Network interface represents the networking stack of a container 34 type networkInterface struct { 35 IP net.IP 36 IPv6 net.IP 37 PortMappings []net.Addr // There are mappings to the host interfaces 38 } 39 40 type ifaces struct { 41 c map[string]*networkInterface 42 sync.Mutex 43 } 44 45 func (i *ifaces) Set(key string, n *networkInterface) { 46 i.Lock() 47 i.c[key] = n 48 i.Unlock() 49 } 50 51 func (i *ifaces) Get(key string) *networkInterface { 52 i.Lock() 53 res := i.c[key] 54 i.Unlock() 55 return res 56 } 57 58 var ( 59 addrs = []string{ 60 // Here we don't follow the convention of using the 1st IP of the range for the gateway. 61 // This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges. 62 // In theory this shouldn't matter - in practice there's bound to be a few scripts relying 63 // on the internal addressing or other things like that. 64 // They shouldn't, but hey, let's not break them unless we really have to. 65 "172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23 66 "10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive 67 "10.1.42.1/16", 68 "10.42.42.1/16", 69 "172.16.42.1/24", 70 "172.16.43.1/24", 71 "172.16.44.1/24", 72 "10.0.42.1/24", 73 "10.0.43.1/24", 74 "192.168.42.1/24", 75 "192.168.43.1/24", 76 "192.168.44.1/24", 77 } 78 79 bridgeIface string 80 bridgeIPv4Network *net.IPNet 81 gatewayIPv4 net.IP 82 bridgeIPv6Addr net.IP 83 globalIPv6Network *net.IPNet 84 gatewayIPv6 net.IP 85 portMapper *portmapper.PortMapper 86 once sync.Once 87 hairpinMode bool 88 89 defaultBindingIP = net.ParseIP("0.0.0.0") 90 currentInterfaces = ifaces{c: make(map[string]*networkInterface)} 91 ipAllocator = ipallocator.New() 92 ) 93 94 func initPortMapper() { 95 once.Do(func() { 96 portMapper = portmapper.New() 97 }) 98 } 99 100 type Config struct { 101 EnableIPv6 bool 102 EnableIptables bool 103 EnableIpForward bool 104 EnableIpMasq bool 105 EnableUserlandProxy bool 106 DefaultIp net.IP 107 Iface string 108 IP string 109 FixedCIDR string 110 FixedCIDRv6 string 111 DefaultGatewayIPv4 string 112 DefaultGatewayIPv6 string 113 InterContainerCommunication bool 114 } 115 116 func InitDriver(config *Config) error { 117 var ( 118 networkv4 *net.IPNet 119 networkv6 *net.IPNet 120 addrv4 net.Addr 121 addrsv6 []net.Addr 122 bridgeIPv6 = "fe80::1/64" 123 ) 124 125 // try to modprobe bridge first 126 // see gh#12177 127 if out, err := exec.Command("modprobe", "-va", "bridge", "nf_nat", "br_netfilter").Output(); err != nil { 128 logrus.Warnf("Running modprobe bridge nf_nat failed with message: %s, error: %v", out, err) 129 } 130 131 initPortMapper() 132 133 if config.DefaultIp != nil { 134 defaultBindingIP = config.DefaultIp 135 } 136 137 hairpinMode = !config.EnableUserlandProxy 138 139 bridgeIface = config.Iface 140 usingDefaultBridge := false 141 if bridgeIface == "" { 142 usingDefaultBridge = true 143 bridgeIface = DefaultNetworkBridge 144 } 145 146 addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface) 147 148 if err != nil { 149 // No Bridge existent, create one 150 // If we're not using the default bridge, fail without trying to create it 151 if !usingDefaultBridge { 152 return err 153 } 154 155 logrus.Info("Bridge interface not found, trying to create it") 156 157 // If the iface is not found, try to create it 158 if err := configureBridge(config.IP, bridgeIPv6, config.EnableIPv6); err != nil { 159 logrus.Errorf("Could not configure Bridge: %s", err) 160 return err 161 } 162 163 addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) 164 if err != nil { 165 return err 166 } 167 168 if config.FixedCIDRv6 != "" { 169 // Setting route to global IPv6 subnet 170 logrus.Infof("Adding route to IPv6 network %q via device %q", config.FixedCIDRv6, bridgeIface) 171 if err := netlink.AddRoute(config.FixedCIDRv6, "", "", bridgeIface); err != nil { 172 logrus.Fatalf("Could not add route to IPv6 network %q via device %q", config.FixedCIDRv6, bridgeIface) 173 } 174 } 175 } else { 176 // Bridge exists already, getting info... 177 // Validate that the bridge ip matches the ip specified by BridgeIP 178 if config.IP != "" { 179 networkv4 = addrv4.(*net.IPNet) 180 bip, _, err := net.ParseCIDR(config.IP) 181 if err != nil { 182 return err 183 } 184 if !networkv4.IP.Equal(bip) { 185 return fmt.Errorf("Bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip) 186 } 187 } 188 189 // A bridge might exist but not have any IPv6 addr associated with it yet 190 // (for example, an existing Docker installation that has only been used 191 // with IPv4 and docker0 already is set up) In that case, we can perform 192 // the bridge init for IPv6 here, else we will error out below if --ipv6=true 193 if len(addrsv6) == 0 && config.EnableIPv6 { 194 if err := setupIPv6Bridge(bridgeIPv6); err != nil { 195 return err 196 } 197 // Recheck addresses now that IPv6 is setup on the bridge 198 addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) 199 if err != nil { 200 return err 201 } 202 } 203 204 // TODO: Check if route to config.FixedCIDRv6 is set 205 } 206 207 if config.EnableIPv6 { 208 bip6, _, err := net.ParseCIDR(bridgeIPv6) 209 if err != nil { 210 return err 211 } 212 found := false 213 for _, addrv6 := range addrsv6 { 214 networkv6 = addrv6.(*net.IPNet) 215 if networkv6.IP.Equal(bip6) { 216 found = true 217 break 218 } 219 } 220 if !found { 221 return fmt.Errorf("Bridge IPv6 does not match existing bridge configuration %s", bip6) 222 } 223 } 224 225 networkv4 = addrv4.(*net.IPNet) 226 227 if config.EnableIPv6 { 228 if len(addrsv6) == 0 { 229 return errors.New("IPv6 enabled but no IPv6 detected") 230 } 231 bridgeIPv6Addr = networkv6.IP 232 } 233 234 if config.EnableIptables { 235 if err := iptables.FirewalldInit(); err != nil { 236 logrus.Debugf("Error initializing firewalld: %v", err) 237 } 238 } 239 240 // Configure iptables for link support 241 if config.EnableIptables { 242 if err := setupIPTables(addrv4, config.InterContainerCommunication, config.EnableIpMasq); err != nil { 243 logrus.Errorf("Error configuring iptables: %s", err) 244 return err 245 } 246 // call this on Firewalld reload 247 iptables.OnReloaded(func() { setupIPTables(addrv4, config.InterContainerCommunication, config.EnableIpMasq) }) 248 } 249 250 if config.EnableIpForward { 251 // Enable IPv4 forwarding 252 if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil { 253 logrus.Warnf("Unable to enable IPv4 forwarding: %v", err) 254 } 255 256 if config.FixedCIDRv6 != "" { 257 // Enable IPv6 forwarding 258 if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil { 259 logrus.Warnf("Unable to enable IPv6 default forwarding: %v", err) 260 } 261 if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil { 262 logrus.Warnf("Unable to enable IPv6 all forwarding: %v", err) 263 } 264 } 265 } 266 267 if hairpinMode { 268 // Enable loopback adresses routing 269 sysPath := filepath.Join("/proc/sys/net/ipv4/conf", bridgeIface, "route_localnet") 270 if err := ioutil.WriteFile(sysPath, []byte{'1', '\n'}, 0644); err != nil { 271 logrus.Warnf("Unable to enable local routing for hairpin mode: %v", err) 272 } 273 } 274 275 // We can always try removing the iptables 276 if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil { 277 return err 278 } 279 280 if config.EnableIptables { 281 _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat, hairpinMode) 282 if err != nil { 283 return err 284 } 285 // call this on Firewalld reload 286 iptables.OnReloaded(func() { iptables.NewChain("DOCKER", bridgeIface, iptables.Nat, hairpinMode) }) 287 chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter, hairpinMode) 288 if err != nil { 289 return err 290 } 291 // call this on Firewalld reload 292 iptables.OnReloaded(func() { iptables.NewChain("DOCKER", bridgeIface, iptables.Filter, hairpinMode) }) 293 294 portMapper.SetIptablesChain(chain) 295 } 296 297 bridgeIPv4Network = networkv4 298 if config.FixedCIDR != "" { 299 _, subnet, err := net.ParseCIDR(config.FixedCIDR) 300 if err != nil { 301 return err 302 } 303 logrus.Debugf("Subnet: %v", subnet) 304 if err := ipAllocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil { 305 logrus.Errorf("Error registering subnet for IPv4 bridge network: %s", err) 306 return err 307 } 308 } 309 310 if gateway, err := requestDefaultGateway(config.DefaultGatewayIPv4, bridgeIPv4Network); err != nil { 311 return err 312 } else { 313 gatewayIPv4 = gateway 314 } 315 316 if config.FixedCIDRv6 != "" { 317 _, subnet, err := net.ParseCIDR(config.FixedCIDRv6) 318 if err != nil { 319 return err 320 } 321 logrus.Debugf("Subnet: %v", subnet) 322 if err := ipAllocator.RegisterSubnet(subnet, subnet); err != nil { 323 logrus.Errorf("Error registering subnet for IPv6 bridge network: %s", err) 324 return err 325 } 326 globalIPv6Network = subnet 327 328 if gateway, err := requestDefaultGateway(config.DefaultGatewayIPv6, globalIPv6Network); err != nil { 329 return err 330 } else { 331 gatewayIPv6 = gateway 332 } 333 } 334 335 // Block BridgeIP in IP allocator 336 ipAllocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP) 337 338 if config.EnableIptables { 339 iptables.OnReloaded(portMapper.ReMapAll) // call this on Firewalld reload 340 } 341 342 return nil 343 } 344 345 func setupIPTables(addr net.Addr, icc, ipmasq bool) error { 346 // Enable NAT 347 348 if ipmasq { 349 natArgs := []string{"-s", addr.String(), "!", "-o", bridgeIface, "-j", "MASQUERADE"} 350 351 if !iptables.Exists(iptables.Nat, "POSTROUTING", natArgs...) { 352 if output, err := iptables.Raw(append([]string{ 353 "-t", string(iptables.Nat), "-I", "POSTROUTING"}, natArgs...)...); err != nil { 354 return fmt.Errorf("Unable to enable network bridge NAT: %s", err) 355 } else if len(output) != 0 { 356 return iptables.ChainError{Chain: "POSTROUTING", Output: output} 357 } 358 } 359 } 360 361 var ( 362 args = []string{"-i", bridgeIface, "-o", bridgeIface, "-j"} 363 acceptArgs = append(args, "ACCEPT") 364 dropArgs = append(args, "DROP") 365 ) 366 367 if !icc { 368 iptables.Raw(append([]string{"-D", "FORWARD"}, acceptArgs...)...) 369 370 if !iptables.Exists(iptables.Filter, "FORWARD", dropArgs...) { 371 logrus.Debugf("Disable inter-container communication") 372 if output, err := iptables.Raw(append([]string{"-A", "FORWARD"}, dropArgs...)...); err != nil { 373 return fmt.Errorf("Unable to prevent intercontainer communication: %s", err) 374 } else if len(output) != 0 { 375 return fmt.Errorf("Error disabling intercontainer communication: %s", output) 376 } 377 } 378 } else { 379 iptables.Raw(append([]string{"-D", "FORWARD"}, dropArgs...)...) 380 381 if !iptables.Exists(iptables.Filter, "FORWARD", acceptArgs...) { 382 logrus.Debugf("Enable inter-container communication") 383 if output, err := iptables.Raw(append([]string{"-A", "FORWARD"}, acceptArgs...)...); err != nil { 384 return fmt.Errorf("Unable to allow intercontainer communication: %s", err) 385 } else if len(output) != 0 { 386 return fmt.Errorf("Error enabling intercontainer communication: %s", output) 387 } 388 } 389 } 390 391 // In hairpin mode, masquerade traffic from localhost 392 if hairpinMode { 393 masqueradeArgs := []string{"-t", "nat", "-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "MASQUERADE"} 394 if !iptables.Exists(iptables.Filter, "POSTROUTING", masqueradeArgs...) { 395 if output, err := iptables.Raw(append([]string{"-I", "POSTROUTING"}, masqueradeArgs...)...); err != nil { 396 return fmt.Errorf("Unable to masquerade local traffic: %s", err) 397 } else if len(output) != 0 { 398 return fmt.Errorf("Error iptables masquerade local traffic: %s", output) 399 } 400 } 401 } 402 403 // Accept all non-intercontainer outgoing packets 404 outgoingArgs := []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"} 405 if !iptables.Exists(iptables.Filter, "FORWARD", outgoingArgs...) { 406 if output, err := iptables.Raw(append([]string{"-I", "FORWARD"}, outgoingArgs...)...); err != nil { 407 return fmt.Errorf("Unable to allow outgoing packets: %s", err) 408 } else if len(output) != 0 { 409 return iptables.ChainError{Chain: "FORWARD outgoing", Output: output} 410 } 411 } 412 413 // Accept incoming packets for existing connections 414 existingArgs := []string{"-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"} 415 416 if !iptables.Exists(iptables.Filter, "FORWARD", existingArgs...) { 417 if output, err := iptables.Raw(append([]string{"-I", "FORWARD"}, existingArgs...)...); err != nil { 418 return fmt.Errorf("Unable to allow incoming packets: %s", err) 419 } else if len(output) != 0 { 420 return iptables.ChainError{Chain: "FORWARD incoming", Output: output} 421 } 422 } 423 return nil 424 } 425 426 func RequestPort(ip net.IP, proto string, port int) (int, error) { 427 initPortMapper() 428 return portMapper.Allocator.RequestPort(ip, proto, port) 429 } 430 431 // configureBridge attempts to create and configure a network bridge interface named `bridgeIface` on the host 432 // If bridgeIP is empty, it will try to find a non-conflicting IP from the Docker-specified private ranges 433 // If the bridge `bridgeIface` already exists, it will only perform the IP address association with the existing 434 // bridge (fixes issue #8444) 435 // If an address which doesn't conflict with existing interfaces can't be found, an error is returned. 436 func configureBridge(bridgeIP string, bridgeIPv6 string, enableIPv6 bool) error { 437 nameservers := []string{} 438 resolvConf, _ := resolvconf.Get() 439 // We don't check for an error here, because we don't really care 440 // if we can't read /etc/resolv.conf. So instead we skip the append 441 // if resolvConf is nil. It either doesn't exist, or we can't read it 442 // for some reason. 443 if resolvConf != nil { 444 nameservers = append(nameservers, resolvconf.GetNameserversAsCIDR(resolvConf)...) 445 } 446 447 var ifaceAddr string 448 if len(bridgeIP) != 0 { 449 _, _, err := net.ParseCIDR(bridgeIP) 450 if err != nil { 451 return err 452 } 453 ifaceAddr = bridgeIP 454 } else { 455 for _, addr := range addrs { 456 _, dockerNetwork, err := net.ParseCIDR(addr) 457 if err != nil { 458 return err 459 } 460 if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil { 461 if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil { 462 ifaceAddr = addr 463 break 464 } else { 465 logrus.Debugf("%s %s", addr, err) 466 } 467 } 468 } 469 } 470 471 if ifaceAddr == "" { 472 return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", bridgeIface, bridgeIface) 473 } 474 logrus.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr) 475 476 if err := createBridgeIface(bridgeIface); err != nil { 477 // The bridge may already exist, therefore we can ignore an "exists" error 478 if !os.IsExist(err) { 479 return err 480 } 481 } 482 483 iface, err := net.InterfaceByName(bridgeIface) 484 if err != nil { 485 return err 486 } 487 488 ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr) 489 if err != nil { 490 return err 491 } 492 493 if err := netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil { 494 return fmt.Errorf("Unable to add private network: %s", err) 495 } 496 497 if enableIPv6 { 498 if err := setupIPv6Bridge(bridgeIPv6); err != nil { 499 return err 500 } 501 } 502 503 if err := netlink.NetworkLinkUp(iface); err != nil { 504 return fmt.Errorf("Unable to start network bridge: %s", err) 505 } 506 return nil 507 } 508 509 func setupIPv6Bridge(bridgeIPv6 string) error { 510 511 iface, err := net.InterfaceByName(bridgeIface) 512 if err != nil { 513 return err 514 } 515 // Enable IPv6 on the bridge 516 procFile := "/proc/sys/net/ipv6/conf/" + iface.Name + "/disable_ipv6" 517 if err := ioutil.WriteFile(procFile, []byte{'0', '\n'}, 0644); err != nil { 518 return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err) 519 } 520 521 ipAddr6, ipNet6, err := net.ParseCIDR(bridgeIPv6) 522 if err != nil { 523 return fmt.Errorf("Unable to parse bridge IPv6 address: %q, error: %v", bridgeIPv6, err) 524 } 525 526 if err := netlink.NetworkLinkAddIp(iface, ipAddr6, ipNet6); err != nil { 527 return fmt.Errorf("Unable to add private IPv6 network: %v", err) 528 } 529 530 return nil 531 } 532 533 func requestDefaultGateway(requestedGateway string, network *net.IPNet) (gateway net.IP, err error) { 534 if requestedGateway != "" { 535 gateway = net.ParseIP(requestedGateway) 536 537 if gateway == nil { 538 return nil, fmt.Errorf("Bad parameter: invalid gateway ip %s", requestedGateway) 539 } 540 541 if !network.Contains(gateway) { 542 return nil, fmt.Errorf("Gateway ip %s must be part of the network %s", requestedGateway, network.String()) 543 } 544 545 ipAllocator.RequestIP(network, gateway) 546 } 547 548 return gateway, nil 549 } 550 551 func createBridgeIface(name string) error { 552 kv, err := kernel.GetKernelVersion() 553 // Only set the bridge's mac address if the kernel version is > 3.3 554 // before that it was not supported 555 setBridgeMacAddr := err == nil && (kv.Kernel >= 3 && kv.Major >= 3) 556 logrus.Debugf("setting bridge mac address = %v", setBridgeMacAddr) 557 return netlink.CreateBridge(name, setBridgeMacAddr) 558 } 559 560 // Generate a IEEE802 compliant MAC address from the given IP address. 561 // 562 // The generator is guaranteed to be consistent: the same IP will always yield the same 563 // MAC address. This is to avoid ARP cache issues. 564 func generateMacAddr(ip net.IP) net.HardwareAddr { 565 hw := make(net.HardwareAddr, 6) 566 567 // The first byte of the MAC address has to comply with these rules: 568 // 1. Unicast: Set the least-significant bit to 0. 569 // 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1. 570 // 3. As "small" as possible: The veth address has to be "smaller" than the bridge address. 571 hw[0] = 0x02 572 573 // The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI). 574 // Since this address is locally administered, we can do whatever we want as long as 575 // it doesn't conflict with other addresses. 576 hw[1] = 0x42 577 578 // Insert the IP address into the last 32 bits of the MAC address. 579 // This is a simple way to guarantee the address will be consistent and unique. 580 copy(hw[2:], ip.To4()) 581 582 return hw 583 } 584 585 func linkLocalIPv6FromMac(mac string) (string, error) { 586 hx := strings.Replace(mac, ":", "", -1) 587 hw, err := hex.DecodeString(hx) 588 if err != nil { 589 return "", errors.New("Could not parse MAC address " + mac) 590 } 591 592 hw[0] ^= 0x2 593 594 return fmt.Sprintf("fe80::%x%x:%xff:fe%x:%x%x/64", hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]), nil 595 } 596 597 // Allocate a network interface 598 func Allocate(id, requestedMac, requestedIP, requestedIPv6 string) (*network.Settings, error) { 599 var ( 600 ip net.IP 601 mac net.HardwareAddr 602 err error 603 globalIPv6 net.IP 604 defaultGWIPv4 net.IP 605 defaultGWIPv6 net.IP 606 ) 607 608 ip, err = ipAllocator.RequestIP(bridgeIPv4Network, net.ParseIP(requestedIP)) 609 if err != nil { 610 return nil, err 611 } 612 613 // If no explicit mac address was given, generate one from the IP address. 614 if mac, err = net.ParseMAC(requestedMac); err != nil { 615 mac = generateMacAddr(ip) 616 } 617 618 if globalIPv6Network != nil { 619 // If globalIPv6Network Size is at least a /80 subnet generate IPv6 address from MAC address 620 netmaskOnes, _ := globalIPv6Network.Mask.Size() 621 ipv6 := net.ParseIP(requestedIPv6) 622 if ipv6 == nil && netmaskOnes <= 80 { 623 ipv6 = make(net.IP, len(globalIPv6Network.IP)) 624 copy(ipv6, globalIPv6Network.IP) 625 for i, h := range mac { 626 ipv6[i+10] = h 627 } 628 } 629 630 globalIPv6, err = ipAllocator.RequestIP(globalIPv6Network, ipv6) 631 if err != nil { 632 logrus.Errorf("Allocator: RequestIP v6: %v", err) 633 return nil, err 634 } 635 logrus.Infof("Allocated IPv6 %s", globalIPv6) 636 } 637 638 maskSize, _ := bridgeIPv4Network.Mask.Size() 639 640 if gatewayIPv4 != nil { 641 defaultGWIPv4 = gatewayIPv4 642 } else { 643 defaultGWIPv4 = bridgeIPv4Network.IP 644 } 645 646 if gatewayIPv6 != nil { 647 defaultGWIPv6 = gatewayIPv6 648 } else { 649 defaultGWIPv6 = bridgeIPv6Addr 650 } 651 652 // If linklocal IPv6 653 localIPv6Net, err := linkLocalIPv6FromMac(mac.String()) 654 if err != nil { 655 return nil, err 656 } 657 localIPv6, _, _ := net.ParseCIDR(localIPv6Net) 658 659 networkSettings := &network.Settings{ 660 IPAddress: ip.String(), 661 Gateway: defaultGWIPv4.String(), 662 MacAddress: mac.String(), 663 Bridge: bridgeIface, 664 IPPrefixLen: maskSize, 665 LinkLocalIPv6Address: localIPv6.String(), 666 HairpinMode: hairpinMode, 667 } 668 669 if globalIPv6Network != nil { 670 networkSettings.GlobalIPv6Address = globalIPv6.String() 671 maskV6Size, _ := globalIPv6Network.Mask.Size() 672 networkSettings.GlobalIPv6PrefixLen = maskV6Size 673 networkSettings.IPv6Gateway = defaultGWIPv6.String() 674 } 675 676 currentInterfaces.Set(id, &networkInterface{ 677 IP: ip, 678 IPv6: globalIPv6, 679 }) 680 681 return networkSettings, nil 682 } 683 684 // Release an interface for a select ip 685 func Release(id string) { 686 var containerInterface = currentInterfaces.Get(id) 687 688 if containerInterface == nil { 689 logrus.Warnf("No network information to release for %s", id) 690 return 691 } 692 693 for _, nat := range containerInterface.PortMappings { 694 if err := portMapper.Unmap(nat); err != nil { 695 logrus.Infof("Unable to unmap port %s: %s", nat, err) 696 } 697 } 698 699 if err := ipAllocator.ReleaseIP(bridgeIPv4Network, containerInterface.IP); err != nil { 700 logrus.Infof("Unable to release IPv4 %s", err) 701 } 702 if globalIPv6Network != nil { 703 if err := ipAllocator.ReleaseIP(globalIPv6Network, containerInterface.IPv6); err != nil { 704 logrus.Infof("Unable to release IPv6 %s", err) 705 } 706 } 707 } 708 709 // Allocate an external port and map it to the interface 710 func AllocatePort(id string, port nat.Port, binding nat.PortBinding) (nat.PortBinding, error) { 711 var ( 712 ip = defaultBindingIP 713 proto = port.Proto() 714 containerPort = port.Int() 715 network = currentInterfaces.Get(id) 716 ) 717 718 if binding.HostIp != "" { 719 ip = net.ParseIP(binding.HostIp) 720 if ip == nil { 721 return nat.PortBinding{}, fmt.Errorf("Bad parameter: invalid host ip %s", binding.HostIp) 722 } 723 } 724 725 // host ip, proto, and host port 726 var container net.Addr 727 switch proto { 728 case "tcp": 729 container = &net.TCPAddr{IP: network.IP, Port: containerPort} 730 case "udp": 731 container = &net.UDPAddr{IP: network.IP, Port: containerPort} 732 default: 733 return nat.PortBinding{}, fmt.Errorf("unsupported address type %s", proto) 734 } 735 736 // 737 // Try up to 10 times to get a port that's not already allocated. 738 // 739 // In the event of failure to bind, return the error that portmapper.Map 740 // yields. 741 // 742 743 var ( 744 host net.Addr 745 err error 746 ) 747 hostPort, err := nat.ParsePort(binding.HostPort) 748 if err != nil { 749 return nat.PortBinding{}, err 750 } 751 for i := 0; i < MaxAllocatedPortAttempts; i++ { 752 if host, err = portMapper.Map(container, ip, hostPort, !hairpinMode); err == nil { 753 break 754 } 755 // There is no point in immediately retrying to map an explicitly 756 // chosen port. 757 if hostPort != 0 { 758 logrus.Warnf("Failed to allocate and map port %d: %s", hostPort, err) 759 break 760 } 761 logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1) 762 } 763 764 if err != nil { 765 return nat.PortBinding{}, err 766 } 767 768 network.PortMappings = append(network.PortMappings, host) 769 770 switch netAddr := host.(type) { 771 case *net.TCPAddr: 772 return nat.PortBinding{HostIp: netAddr.IP.String(), HostPort: strconv.Itoa(netAddr.Port)}, nil 773 case *net.UDPAddr: 774 return nat.PortBinding{HostIp: netAddr.IP.String(), HostPort: strconv.Itoa(netAddr.Port)}, nil 775 default: 776 return nat.PortBinding{}, fmt.Errorf("unsupported address type %T", netAddr) 777 } 778 } 779 780 //TODO: should it return something more than just an error? 781 func LinkContainers(action, parentIP, childIP string, ports []nat.Port, ignoreErrors bool) error { 782 var nfAction iptables.Action 783 784 switch action { 785 case "-A": 786 nfAction = iptables.Append 787 case "-I": 788 nfAction = iptables.Insert 789 case "-D": 790 nfAction = iptables.Delete 791 default: 792 return fmt.Errorf("Invalid action '%s' specified", action) 793 } 794 795 ip1 := net.ParseIP(parentIP) 796 if ip1 == nil { 797 return fmt.Errorf("Parent IP '%s' is invalid", parentIP) 798 } 799 ip2 := net.ParseIP(childIP) 800 if ip2 == nil { 801 return fmt.Errorf("Child IP '%s' is invalid", childIP) 802 } 803 804 chain := iptables.Chain{Name: "DOCKER", Bridge: bridgeIface} 805 for _, port := range ports { 806 if err := chain.Link(nfAction, ip1, ip2, port.Int(), port.Proto()); !ignoreErrors && err != nil { 807 return err 808 } 809 } 810 return nil 811 }