func TestLinkContainers(t *testing.T) { // Init driver if err := InitDriver(new(Config)); err != nil { t.Fatal("Failed to initialize network driver") } // Allocate interface if _, err := Allocate("container_id", "", "", ""); err != nil { t.Fatal("Failed to allocate network interface") } bridgeIface = "lo" if _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter, false); err != nil { t.Fatal(err) } if err := LinkContainers("-I", "172.17.0.1", "172.17.0.2", []nat.Port{nat.Port("1234")}, false); err != nil { t.Fatal("LinkContainers failed") } // flush rules if _, err := iptables.Raw([]string{"-F", "DOCKER"}...); err != nil { t.Fatal(err) } }
func TestLinkContainers(t *testing.T) { eng := engine.New() eng.Logging = false // Init driver job := eng.Job("initdriver") if res := InitDriver(job); res != engine.StatusOK { t.Fatal("Failed to initialize network driver") } // Allocate interface job = eng.Job("allocate_interface", "container_id") if res := Allocate(job); res != engine.StatusOK { t.Fatal("Failed to allocate network interface") } job.Args[0] = "-I" job.Setenv("ChildIP", "172.17.0.2") job.Setenv("ParentIP", "172.17.0.1") job.SetenvBool("IgnoreErrors", false) job.SetenvList("Ports", []string{"1234"}) bridgeIface = "lo" _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) if err != nil { t.Fatal(err) } if res := LinkContainers(job); res != engine.StatusOK { t.Fatalf("LinkContainers failed") } // flush rules if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil { t.Fatal(err) } }
func InitDriver(job *engine.Job) engine.Status { var ( network *net.IPNet enableIPTables = job.GetenvBool("EnableIptables") icc = job.GetenvBool("InterContainerCommunication") ipMasq = job.GetenvBool("EnableIpMasq") ipForward = job.GetenvBool("EnableIpForward") bridgeIP = job.Getenv("BridgeIP") fixedCIDR = job.Getenv("FixedCIDR") ) if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" { defaultBindingIP = net.ParseIP(defaultIP) } bridgeIface = job.Getenv("BridgeIface") usingDefaultBridge := false if bridgeIface == "" { usingDefaultBridge = true bridgeIface = DefaultNetworkBridge } addr, err := networkdriver.GetIfaceAddr(bridgeIface) if err != nil { // If we're not using the default bridge, fail without trying to create it if !usingDefaultBridge { return job.Error(err) } // If the bridge interface is not found (or has no address), try to create it and/or add an address if err := configureBridge(bridgeIP); err != nil { return job.Error(err) } addr, err = networkdriver.GetIfaceAddr(bridgeIface) if err != nil { return job.Error(err) } network = addr.(*net.IPNet) } else { network = addr.(*net.IPNet) // validate that the bridge ip matches the ip specified by BridgeIP if bridgeIP != "" { bip, _, err := net.ParseCIDR(bridgeIP) if err != nil { return job.Error(err) } if !network.IP.Equal(bip) { return job.Errorf("bridge ip (%s) does not match existing bridge configuration %s", network.IP, bip) } } } // Configure iptables for link support if enableIPTables { if err := setupIPTables(addr, icc, ipMasq); err != nil { return job.Error(err) } } if ipForward { // Enable IPv4 forwarding if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil { job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err) } } // We can always try removing the iptables if err := iptables.RemoveExistingChain("DOCKER"); err != nil { return job.Error(err) } if enableIPTables { chain, err := iptables.NewChain("DOCKER", bridgeIface) if err != nil { return job.Error(err) } portmapper.SetIptablesChain(chain) } bridgeNetwork = network if fixedCIDR != "" { _, subnet, err := net.ParseCIDR(fixedCIDR) if err != nil { return job.Error(err) } log.Debugf("Subnet: %v", subnet) if err := ipallocator.RegisterSubnet(bridgeNetwork, subnet); err != nil { return job.Error(err) } } // https://github.com/docker/docker/issues/2768 job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeNetwork.IP) for name, f := range map[string]engine.Handler{ "allocate_interface": Allocate, "release_interface": Release, "allocate_port": AllocatePort, "link": LinkContainers, } { if err := job.Eng.Register(name, f); err != nil { return job.Error(err) } } return engine.StatusOK }
func InitDriver(job *engine.Job) error { var ( networkv4 *net.IPNet networkv6 *net.IPNet addrv4 net.Addr addrsv6 []net.Addr enableIPTables = job.GetenvBool("EnableIptables") enableIPv6 = job.GetenvBool("EnableIPv6") icc = job.GetenvBool("InterContainerCommunication") ipMasq = job.GetenvBool("EnableIpMasq") ipForward = job.GetenvBool("EnableIpForward") bridgeIP = job.Getenv("BridgeIP") bridgeIPv6 = "fe80::1/64" fixedCIDR = job.Getenv("FixedCIDR") fixedCIDRv6 = job.Getenv("FixedCIDRv6") ) if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" { defaultBindingIP = net.ParseIP(defaultIP) } bridgeIface = job.Getenv("BridgeIface") usingDefaultBridge := false if bridgeIface == "" { usingDefaultBridge = true bridgeIface = DefaultNetworkBridge } addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface) if err != nil { // No Bridge existent, create one // If we're not using the default bridge, fail without trying to create it if !usingDefaultBridge { return err } // If the iface is not found, try to create it if err := configureBridge(bridgeIP, bridgeIPv6, enableIPv6); err != nil { return err } addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) if err != nil { return err } if fixedCIDRv6 != "" { // Setting route to global IPv6 subnet logrus.Infof("Adding route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface) if err := netlink.AddRoute(fixedCIDRv6, "", "", bridgeIface); err != nil { logrus.Fatalf("Could not add route to IPv6 network %q via device %q", fixedCIDRv6, bridgeIface) } } } else { // Bridge exists already, getting info... // Validate that the bridge ip matches the ip specified by BridgeIP if bridgeIP != "" { networkv4 = addrv4.(*net.IPNet) bip, _, err := net.ParseCIDR(bridgeIP) if err != nil { return err } if !networkv4.IP.Equal(bip) { return fmt.Errorf("Bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip) } } // A bridge might exist but not have any IPv6 addr associated with it yet // (for example, an existing Docker installation that has only been used // with IPv4 and docker0 already is set up) In that case, we can perform // the bridge init for IPv6 here, else we will error out below if --ipv6=true if len(addrsv6) == 0 && enableIPv6 { if err := setupIPv6Bridge(bridgeIPv6); err != nil { return err } // Recheck addresses now that IPv6 is setup on the bridge addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) if err != nil { return err } } // TODO: Check if route to fixedCIDRv6 is set } if enableIPv6 { bip6, _, err := net.ParseCIDR(bridgeIPv6) if err != nil { return err } found := false for _, addrv6 := range addrsv6 { networkv6 = addrv6.(*net.IPNet) if networkv6.IP.Equal(bip6) { found = true break } } if !found { return fmt.Errorf("Bridge IPv6 does not match existing bridge configuration %s", bip6) } } networkv4 = addrv4.(*net.IPNet) if enableIPv6 { if len(addrsv6) == 0 { return errors.New("IPv6 enabled but no IPv6 detected") } bridgeIPv6Addr = networkv6.IP } // Configure iptables for link support if enableIPTables { if err := setupIPTables(addrv4, icc, ipMasq); err != nil { return err } } if ipForward { // Enable IPv4 forwarding if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil { logrus.Warnf("WARNING: unable to enable IPv4 forwarding: %s\n", err) } if fixedCIDRv6 != "" { // Enable IPv6 forwarding if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil { logrus.Warnf("WARNING: unable to enable IPv6 default forwarding: %s\n", err) } if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil { logrus.Warnf("WARNING: unable to enable IPv6 all forwarding: %s\n", err) } } } // We can always try removing the iptables if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil { return err } if enableIPTables { _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat) if err != nil { return err } chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) if err != nil { return err } portmapper.SetIptablesChain(chain) } bridgeIPv4Network = networkv4 if fixedCIDR != "" { _, subnet, err := net.ParseCIDR(fixedCIDR) if err != nil { return err } logrus.Debugf("Subnet: %v", subnet) if err := ipAllocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil { return err } } if fixedCIDRv6 != "" { _, subnet, err := net.ParseCIDR(fixedCIDRv6) if err != nil { return err } logrus.Debugf("Subnet: %v", subnet) if err := ipAllocator.RegisterSubnet(subnet, subnet); err != nil { return err } globalIPv6Network = subnet } // Block BridgeIP in IP allocator ipAllocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP) // https://github.com/docker/docker/issues/2768 job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeIPv4Network.IP) for name, f := range map[string]engine.Handler{ "allocate_interface": Allocate, "release_interface": Release, "allocate_port": AllocatePort, "link": LinkContainers, } { if err := job.Eng.Register(name, f); err != nil { return err } } return nil }
func InitDriver(config *Config) error { var ( networkv4 *net.IPNet networkv6 *net.IPNet addrv4 net.Addr addrsv6 []net.Addr bridgeIPv6 = "fe80::1/64" ) initPortMapper() if config.DefaultIp != nil { defaultBindingIP = config.DefaultIp } bridgeIface = config.Iface usingDefaultBridge := false if bridgeIface == "" { usingDefaultBridge = true bridgeIface = DefaultNetworkBridge } addrv4, addrsv6, err := networkdriver.GetIfaceAddr(bridgeIface) if err != nil { // No Bridge existent, create one // If we're not using the default bridge, fail without trying to create it if !usingDefaultBridge { return err } logrus.Info("Bridge interface not found, trying to create it") // If the iface is not found, try to create it if err := configureBridge(config.IP, bridgeIPv6, config.EnableIPv6); err != nil { logrus.Errorf("Could not configure Bridge: %s", err) return err } addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) if err != nil { return err } if config.FixedCIDRv6 != "" { // Setting route to global IPv6 subnet logrus.Infof("Adding route to IPv6 network %q via device %q", config.FixedCIDRv6, bridgeIface) if err := netlink.AddRoute(config.FixedCIDRv6, "", "", bridgeIface); err != nil { logrus.Fatalf("Could not add route to IPv6 network %q via device %q", config.FixedCIDRv6, bridgeIface) } } } else { // Bridge exists already, getting info... // Validate that the bridge ip matches the ip specified by BridgeIP if config.IP != "" { networkv4 = addrv4.(*net.IPNet) bip, _, err := net.ParseCIDR(config.IP) if err != nil { return err } if !networkv4.IP.Equal(bip) { return fmt.Errorf("Bridge ip (%s) does not match existing bridge configuration %s", networkv4.IP, bip) } } // A bridge might exist but not have any IPv6 addr associated with it yet // (for example, an existing Docker installation that has only been used // with IPv4 and docker0 already is set up) In that case, we can perform // the bridge init for IPv6 here, else we will error out below if --ipv6=true if len(addrsv6) == 0 && config.EnableIPv6 { if err := setupIPv6Bridge(bridgeIPv6); err != nil { return err } // Recheck addresses now that IPv6 is setup on the bridge addrv4, addrsv6, err = networkdriver.GetIfaceAddr(bridgeIface) if err != nil { return err } } // TODO: Check if route to config.FixedCIDRv6 is set } if config.EnableIPv6 { bip6, _, err := net.ParseCIDR(bridgeIPv6) if err != nil { return err } found := false for _, addrv6 := range addrsv6 { networkv6 = addrv6.(*net.IPNet) if networkv6.IP.Equal(bip6) { found = true break } } if !found { return fmt.Errorf("Bridge IPv6 does not match existing bridge configuration %s", bip6) } } networkv4 = addrv4.(*net.IPNet) if config.EnableIPv6 { if len(addrsv6) == 0 { return errors.New("IPv6 enabled but no IPv6 detected") } bridgeIPv6Addr = networkv6.IP } // Configure iptables for link support if config.EnableIptables { if err := setupIPTables(addrv4, config.InterContainerCommunication, config.EnableIpMasq); err != nil { logrus.Errorf("Error configuing iptables: %s", err) return err } } if config.EnableIpForward { // Enable IPv4 forwarding if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil { logrus.Warnf("WARNING: unable to enable IPv4 forwarding: %s\n", err) } if config.FixedCIDRv6 != "" { // Enable IPv6 forwarding if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/default/forwarding", []byte{'1', '\n'}, 0644); err != nil { logrus.Warnf("WARNING: unable to enable IPv6 default forwarding: %s\n", err) } if err := ioutil.WriteFile("/proc/sys/net/ipv6/conf/all/forwarding", []byte{'1', '\n'}, 0644); err != nil { logrus.Warnf("WARNING: unable to enable IPv6 all forwarding: %s\n", err) } } } // We can always try removing the iptables if err := iptables.RemoveExistingChain("DOCKER", iptables.Nat); err != nil { return err } if config.EnableIptables { _, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Nat) if err != nil { return err } chain, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter) if err != nil { return err } portMapper.SetIptablesChain(chain) } bridgeIPv4Network = networkv4 if config.FixedCIDR != "" { _, subnet, err := net.ParseCIDR(config.FixedCIDR) if err != nil { return err } logrus.Debugf("Subnet: %v", subnet) if err := ipAllocator.RegisterSubnet(bridgeIPv4Network, subnet); err != nil { logrus.Errorf("Error registering subnet for IPv4 bridge network: %s", err) return err } } if config.FixedCIDRv6 != "" { _, subnet, err := net.ParseCIDR(config.FixedCIDRv6) if err != nil { return err } logrus.Debugf("Subnet: %v", subnet) if err := ipAllocator.RegisterSubnet(subnet, subnet); err != nil { logrus.Errorf("Error registering subnet for IPv6 bridge network: %s", err) return err } globalIPv6Network = subnet } // Block BridgeIP in IP allocator ipAllocator.RequestIP(bridgeIPv4Network, bridgeIPv4Network.IP) return nil }