// CreateNetwork creates a network with the given name, driver and other optional parameters func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, netOption map[string]string, labels map[string]string, internal bool, enableIPv6 bool) (libnetwork.Network, error) { c := daemon.netController if driver == "" { driver = c.Config().Daemon.DefaultDriver } v4Conf, v6Conf, err := getIpamConfig(ipam.Config) if err != nil { return nil, err } nwOptions := []libnetwork.NetworkOption{ libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options), libnetwork.NetworkOptionEnableIPv6(enableIPv6), libnetwork.NetworkOptionDriverOpts(netOption), libnetwork.NetworkOptionLabels(labels), } if internal { nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork()) } n, err := c.NewNetwork(driver, name, nwOptions...) if err != nil { return nil, err } daemon.LogNetworkEvent(n, "create") return n, nil }
// CreateNetwork creates a network with the given name, driver and other optional parameters func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) { if runconfig.IsPreDefinedNetwork(create.Name) { err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name) return nil, errors.NewErrorWithStatusCode(err, http.StatusForbidden) } var warning string nw, err := daemon.GetNetworkByName(create.Name) if err != nil { if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok { return nil, err } } if nw != nil { if create.CheckDuplicate { return nil, libnetwork.NetworkNameError(create.Name) } warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) } c := daemon.netController driver := create.Driver if driver == "" { driver = c.Config().Daemon.DefaultDriver } ipam := create.IPAM v4Conf, v6Conf, err := getIpamConfig(ipam.Config) if err != nil { return nil, err } nwOptions := []libnetwork.NetworkOption{ libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options), libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6), libnetwork.NetworkOptionDriverOpts(create.Options), libnetwork.NetworkOptionLabels(create.Labels), } if create.Internal { nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork()) } n, err := c.NewNetwork(driver, create.Name, nwOptions...) if err != nil { return nil, err } daemon.LogNetworkEvent(n, "create") return &types.NetworkCreateResponse{ ID: n.ID(), Warning: warning, }, nil }
// Testing IPV6 from MAC address func TestBridgeIpv6FromMac(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() } netOption := options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testipv6mac", "EnableICC": true, "EnableIPMasquerade": true, }, } ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}} ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}} network, err := controller.NewNetwork(bridgeNetType, "testipv6mac", "", libnetwork.NetworkOptionGeneric(netOption), libnetwork.NetworkOptionEnableIPv6(true), libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4ConfList, ipamV6ConfList, nil), libnetwork.NetworkOptionDeferIPv6Alloc(true)) if err != nil { t.Fatal(err) } mac := net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff} epOption := options.Generic{netlabel.MacAddress: mac} ep, err := network.CreateEndpoint("testep", libnetwork.EndpointOptionGeneric(epOption)) if err != nil { t.Fatal(err) } iface := ep.Info().Iface() if !bytes.Equal(iface.MacAddress(), mac) { t.Fatalf("Unexpected mac address: %v", iface.MacAddress()) } ip, expIP, _ := net.ParseCIDR("fe90::aabb:ccdd:eeff/64") expIP.IP = ip if !types.CompareIPNet(expIP, iface.AddressIPv6()) { t.Fatalf("Expected %v. Got: %v", expIP, iface.AddressIPv6()) } if err := ep.Delete(false); err != nil { t.Fatal(err) } if err := network.Delete(); err != nil { t.Fatal(err) } }
/*************************** NetworkController interface ****************************/ func procCreateNetwork(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) { var create networkCreate err := json.Unmarshal(body, &create) if err != nil { return nil, &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest} } processCreateDefaults(c, &create) options := []libnetwork.NetworkOption{} if val, ok := create.NetworkOpts[netlabel.Internal]; ok { internal, err := strconv.ParseBool(val) if err != nil { return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} } if internal { options = append(options, libnetwork.NetworkOptionInternalNetwork()) } } if val, ok := create.NetworkOpts[netlabel.EnableIPv6]; ok { enableIPv6, err := strconv.ParseBool(val) if err != nil { return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest} } options = append(options, libnetwork.NetworkOptionEnableIPv6(enableIPv6)) } if len(create.DriverOpts) > 0 { options = append(options, libnetwork.NetworkOptionDriverOpts(create.DriverOpts)) } if len(create.IPv4Conf) > 0 { ipamV4Conf := &libnetwork.IpamConf{ PreferredPool: create.IPv4Conf[0].PreferredPool, SubPool: create.IPv4Conf[0].SubPool, } options = append(options, libnetwork.NetworkOptionIpam("default", "", []*libnetwork.IpamConf{ipamV4Conf}, nil, nil)) } nw, err := c.NewNetwork(create.NetworkType, create.Name, create.ID, options...) if err != nil { return nil, convertNetworkError(err) } return nw.ID(), &createdResponse }
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error { bridgeName := bridge.DefaultBridgeName if config.bridgeConfig.Iface != "" { bridgeName = config.bridgeConfig.Iface } netOption := map[string]string{ bridge.BridgeName: bridgeName, bridge.DefaultBridge: strconv.FormatBool(true), netlabel.DriverMTU: strconv.Itoa(config.Mtu), bridge.EnableIPMasquerade: strconv.FormatBool(config.bridgeConfig.EnableIPMasq), bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication), } // --ip processing if config.bridgeConfig.DefaultIP != nil { netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String() } var ( ipamV4Conf *libnetwork.IpamConf ipamV6Conf *libnetwork.IpamConf ) ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName) if err != nil { return errors.Wrap(err, "list bridge addresses failed") } nw := nwList[0] if len(nwList) > 1 && config.bridgeConfig.FixedCIDR != "" { _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) if err != nil { return errors.Wrap(err, "parse CIDR failed") } // Iterate through in case there are multiple addresses for the bridge for _, entry := range nwList { if fCIDR.Contains(entry.IP) { nw = entry break } } } ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String() hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask) if hip.IsGlobalUnicast() { ipamV4Conf.Gateway = nw.IP.String() } if config.bridgeConfig.IP != "" { ipamV4Conf.PreferredPool = config.bridgeConfig.IP ip, _, err := net.ParseCIDR(config.bridgeConfig.IP) if err != nil { return err } ipamV4Conf.Gateway = ip.String() } else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" { logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool) } if config.bridgeConfig.FixedCIDR != "" { _, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR) if err != nil { return err } ipamV4Conf.SubPool = fCIDR.String() } if config.bridgeConfig.DefaultGatewayIPv4 != nil { ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String() } var deferIPv6Alloc bool if config.bridgeConfig.FixedCIDRv6 != "" { _, fCIDRv6, err := net.ParseCIDR(config.bridgeConfig.FixedCIDRv6) if err != nil { return err } // In case user has specified the daemon flag --fixed-cidr-v6 and the passed network has // at least 48 host bits, we need to guarantee the current behavior where the containers' // IPv6 addresses will be constructed based on the containers' interface MAC address. // We do so by telling libnetwork to defer the IPv6 address allocation for the endpoints // on this network until after the driver has created the endpoint and returned the // constructed address. Libnetwork will then reserve this address with the ipam driver. ones, _ := fCIDRv6.Mask.Size() deferIPv6Alloc = ones <= 80 if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} } ipamV6Conf.PreferredPool = fCIDRv6.String() // In case the --fixed-cidr-v6 is specified and the current docker0 bridge IPv6 // address belongs to the same network, we need to inform libnetwork about it, so // that it can be reserved with IPAM and it will not be given away to somebody else for _, nw6 := range nw6List { if fCIDRv6.Contains(nw6.IP) { ipamV6Conf.Gateway = nw6.IP.String() break } } } if config.bridgeConfig.DefaultGatewayIPv6 != nil { if ipamV6Conf == nil { ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)} } ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.bridgeConfig.DefaultGatewayIPv6.String() } v4Conf := []*libnetwork.IpamConf{ipamV4Conf} v6Conf := []*libnetwork.IpamConf{} if ipamV6Conf != nil { v6Conf = append(v6Conf, ipamV6Conf) } // Initialize default network on "bridge" with the same name _, err = controller.NewNetwork("bridge", "bridge", "", libnetwork.NetworkOptionEnableIPv6(config.bridgeConfig.EnableIPv6), libnetwork.NetworkOptionDriverOpts(netOption), libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil), libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc)) if err != nil { return fmt.Errorf("Error creating default \"bridge\" network: %v", err) } return nil }
func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) { // If there is a pending ingress network creation wait here // since ingress network creation can happen via node download // from manager or task download. if isIngressNetwork(create.Name) { defer ingressWait()() } if runconfig.IsPreDefinedNetwork(create.Name) && !agent { err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name) return nil, errors.NewRequestForbiddenError(err) } var warning string nw, err := daemon.GetNetworkByName(create.Name) if err != nil { if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok { return nil, err } } if nw != nil { if create.CheckDuplicate { return nil, libnetwork.NetworkNameError(create.Name) } warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID()) } c := daemon.netController driver := create.Driver if driver == "" { driver = c.Config().Daemon.DefaultDriver } nwOptions := []libnetwork.NetworkOption{ libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6), libnetwork.NetworkOptionDriverOpts(create.Options), libnetwork.NetworkOptionLabels(create.Labels), } if create.IPAM != nil { ipam := create.IPAM v4Conf, v6Conf, err := getIpamConfig(ipam.Config) if err != nil { return nil, err } nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options)) } if create.Internal { nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork()) } if agent { nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic()) nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false)) } if isIngressNetwork(create.Name) { nwOptions = append(nwOptions, libnetwork.NetworkOptionIngress()) } n, err := c.NewNetwork(driver, create.Name, id, nwOptions...) if err != nil { return nil, err } daemon.LogNetworkEvent(n, "create") return &types.NetworkCreateResponse{ ID: n.ID(), Warning: warning, }, nil }
func TestEndpointJoin(t *testing.T) { if !testutils.IsRunningInContainer() { defer testutils.SetupTestOSContext(t)() } // Create network 1 and add 2 endpoint: ep11, ep12 netOption := options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork1", "EnableICC": true, "EnableIPMasquerade": true, }, } ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "fe90::/64", Gateway: "fe90::22"}} n1, err := controller.NewNetwork(bridgeNetType, "testnetwork1", "", libnetwork.NetworkOptionGeneric(netOption), libnetwork.NetworkOptionEnableIPv6(true), libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", nil, ipamV6ConfList, nil), libnetwork.NetworkOptionDeferIPv6Alloc(true)) if err != nil { t.Fatal(err) } defer func() { if err := n1.Delete(); err != nil { t.Fatal(err) } }() ep1, err := n1.CreateEndpoint("ep1") if err != nil { t.Fatal(err) } defer func() { if err := ep1.Delete(false); err != nil { t.Fatal(err) } }() // Validate if ep.Info() only gives me IP address info and not names and gateway during CreateEndpoint() info := ep1.Info() iface := info.Iface() if iface.Address() != nil && iface.Address().IP.To4() == nil { t.Fatalf("Invalid IP address returned: %v", iface.Address()) } if iface.AddressIPv6() != nil && iface.AddressIPv6().IP == nil { t.Fatalf("Invalid IPv6 address returned: %v", iface.Address()) } if len(info.Gateway()) != 0 { t.Fatalf("Expected empty gateway for an empty endpoint. Instead found a gateway: %v", info.Gateway()) } if len(info.GatewayIPv6()) != 0 { t.Fatalf("Expected empty gateway for an empty ipv6 endpoint. Instead found a gateway: %v", info.GatewayIPv6()) } if info.Sandbox() != nil { t.Fatalf("Expected an empty sandbox key for an empty endpoint. Instead found a non-empty sandbox key: %s", info.Sandbox().Key()) } // test invalid joins err = ep1.Join(nil) if err == nil { t.Fatalf("Expected to fail join with nil Sandbox") } if _, ok := err.(types.BadRequestError); !ok { t.Fatalf("Unexpected error type returned: %T", err) } fsbx := &fakeSandbox{} if err = ep1.Join(fsbx); err == nil { t.Fatalf("Expected to fail join with invalid Sandbox") } if _, ok := err.(types.BadRequestError); !ok { t.Fatalf("Unexpected error type returned: %T", err) } sb, err := controller.NewSandbox(containerID, libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io"), libnetwork.OptionExtraHost("web", "192.168.0.1")) if err != nil { t.Fatal(err) } defer func() { if err := sb.Delete(); err != nil { t.Fatal(err) } }() err = ep1.Join(sb) if err != nil { t.Fatal(err) } defer func() { err = ep1.Leave(sb) if err != nil { t.Fatal(err) } }() // Validate if ep.Info() only gives valid gateway and sandbox key after has container has joined. info = ep1.Info() if len(info.Gateway()) == 0 { t.Fatalf("Expected a valid gateway for a joined endpoint. Instead found an invalid gateway: %v", info.Gateway()) } if len(info.GatewayIPv6()) == 0 { t.Fatalf("Expected a valid ipv6 gateway for a joined endpoint. Instead found an invalid gateway: %v", info.GatewayIPv6()) } if info.Sandbox() == nil { t.Fatalf("Expected an non-empty sandbox key for a joined endpoint. Instead found a empty sandbox key") } // Check endpoint provided container information if ep1.Info().Sandbox().Key() != sb.Key() { t.Fatalf("Endpoint Info returned unexpected sandbox key: %s", sb.Key()) } // Attempt retrieval of endpoint interfaces statistics stats, err := sb.Statistics() if err != nil { t.Fatal(err) } if _, ok := stats["eth0"]; !ok { t.Fatalf("Did not find eth0 statistics") } // Now test the container joining another network n2, err := createTestNetwork(bridgeNetType, "testnetwork2", options.Generic{ netlabel.GenericData: options.Generic{ "BridgeName": "testnetwork2", }, }, nil, nil) if err != nil { t.Fatal(err) } defer func() { if err := n2.Delete(); err != nil { t.Fatal(err) } }() ep2, err := n2.CreateEndpoint("ep2") if err != nil { t.Fatal(err) } defer func() { if err := ep2.Delete(false); err != nil { t.Fatal(err) } }() err = ep2.Join(sb) if err != nil { t.Fatal(err) } defer func() { err = ep2.Leave(sb) if err != nil { t.Fatal(err) } }() if ep1.Info().Sandbox().Key() != ep2.Info().Sandbox().Key() { t.Fatalf("ep1 and ep2 returned different container sandbox key") } checkSandbox(t, info) }