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