Exemple #1
0
func (c *Context) newBridgeScope(id uid.UID, name string, subnet *net.IPNet, gateway net.IP, dns []net.IP, pools []string) (newScope *Scope, err error) {
	defer trace.End(trace.Begin(""))
	bnPG, ok := c.config.PortGroups[c.config.BridgeNetwork]
	if !ok || bnPG == nil {
		return nil, fmt.Errorf("bridge network not set")
	}

	if ip.IsUnspecifiedSubnet(subnet) {
		// get the next available subnet from the default bridge pool
		var err error
		subnet, err = c.defaultBridgePool.NextIP4Net(c.defaultBridgeMask)
		if err != nil {
			return nil, err
		}
	}

	s, err := c.newScopeCommon(id, name, constants.BridgeScopeType, subnet, gateway, dns, pools, bnPG)
	if err != nil {
		return nil, err
	}

	// add the gateway address to the bridge interface
	if err = c.config.BridgeLink.AddrAdd(net.IPNet{IP: s.Gateway(), Mask: s.Subnet().Mask}); err != nil {
		if errno, ok := err.(syscall.Errno); !ok || errno != syscall.EEXIST {
			log.Warnf("failed to add gateway address %s to bridge interface: %s", s.Gateway(), err)
		}
	}

	return s, nil
}
Exemple #2
0
func (c *Context) newExternalScope(id uid.UID, name string, subnet *net.IPNet, gateway net.IP, dns []net.IP, ipam *IPAM) (*Scope, error) {
	// ipam cannot be specified without gateway and subnet
	if ipam != nil && len(ipam.pools) > 0 {
		if ip.IsUnspecifiedSubnet(subnet) || gateway.IsUnspecified() {
			return nil, fmt.Errorf("ipam cannot be specified without gateway and subnet for external network")
		}
	}

	if !ip.IsUnspecifiedSubnet(subnet) {
		// cannot overlap with the default bridge pool
		if c.defaultBridgePool.Network.Contains(subnet.IP) ||
			c.defaultBridgePool.Network.Contains(highestIP4(subnet)) {
			return nil, fmt.Errorf("external network cannot overlap with default bridge network")
		}
	}

	n := Config.ContainerNetworks[name]
	if n == nil {
		return nil, fmt.Errorf("no network info for external scope %s", name)
	}

	return c.newScopeCommon(id, name, ExternalScopeType, subnet, gateway, dns, ipam, n.PortGroup)
}
Exemple #3
0
func (c *Context) newExternalScope(id uid.UID, name string, subnet *net.IPNet, gateway net.IP, dns []net.IP, pools []string) (*Scope, error) {
	defer trace.End(trace.Begin(""))
	// ipam cannot be specified without gateway and subnet
	if len(pools) > 0 {
		if ip.IsUnspecifiedSubnet(subnet) || gateway.IsUnspecified() {
			return nil, fmt.Errorf("ipam cannot be specified without gateway and subnet for external network")
		}
	}

	if !ip.IsUnspecifiedSubnet(subnet) {
		// cannot overlap with the default bridge pool
		if c.defaultBridgePool.Network.Contains(subnet.IP) ||
			c.defaultBridgePool.Network.Contains(highestIP4(subnet)) {
			return nil, fmt.Errorf("external network cannot overlap with default bridge network")
		}
	}

	pg := c.config.PortGroups[name]
	if pg == nil {
		return nil, fmt.Errorf("no network info for external scope %s", name)
	}

	return c.newScopeCommon(id, name, constants.ExternalScopeType, subnet, gateway, dns, pools, pg)
}
Exemple #4
0
func reserveGateway(gateway net.IP, subnet *net.IPNet, spaces []*AddressSpace) (net.IP, error) {
	defer trace.End(trace.Begin(""))
	if ip.IsUnspecifiedSubnet(subnet) {
		return nil, fmt.Errorf("cannot reserve gateway for nil subnet")
	}

	if !ip.IsUnspecifiedIP(gateway) {
		// verify gateway is routable address
		if !ip.IsRoutableIP(gateway, subnet) {
			return nil, fmt.Errorf("gateway address %s is not routable on network %s", gateway, subnet)
		}

		// optionally reserve it in one of the pools
		for _, p := range spaces {
			if err := p.ReserveIP4(gateway); err == nil {
				break
			}
		}

		return gateway, nil
	}

	// gateway is not specified, pick one from the available pools
	if len(spaces) > 0 {
		var err error
		if gateway, err = spaces[0].ReserveNextIP4(); err != nil {
			return nil, err
		}

		if !ip.IsRoutableIP(gateway, subnet) {
			return nil, fmt.Errorf("gateway address %s is not routable on network %s", gateway, subnet)
		}

		return gateway, nil
	}

	return nil, fmt.Errorf("could not reserve gateway address for network %s", subnet)
}
Exemple #5
0
func (s *Scope) Refresh(h *exec.Handle) error {
	s.Lock()
	defer s.Unlock()

	if !s.isDynamic() {
		return nil
	}

	ne := h.ExecConfig.Networks[s.name]
	if ip.IsUnspecifiedSubnet(&ne.Network.Gateway) {
		return fmt.Errorf("updating container %s: gateway not present for scope %s", h.ExecConfig.ID, s.name)
	}

	gw, snet, err := net.ParseCIDR(ne.Network.Gateway.String())
	if err != nil {
		return err
	}

	s.gateway = gw
	s.subnet = new(net.IPNet)
	*s.subnet = *snet

	return nil
}
Exemple #6
0
func (c *Context) addScope(s *Scope) error {
	defer trace.End(trace.Begin(""))

	if _, ok := c.scopes[s.name]; ok {
		return DuplicateResourceError{}
	}

	var err error
	var defaultPool bool
	var allzeros, allones net.IP
	var space *AddressSpace
	spaces := s.spaces
	subnet := s.subnet
	gateway := s.gateway

	// cleanup
	defer func() {
		if err == nil || space == nil || !defaultPool {
			return
		}

		for _, p := range spaces {
			// release DNS IPs
			for _, d := range s.dns {
				p.ReleaseIP4(d)
			}

			// release gateway
			if !ip.IsUnspecifiedIP(gateway) {
				p.ReleaseIP4(gateway)
			}

			// release all-ones and all-zeros addresses
			if !ip.IsUnspecifiedIP(allzeros) {
				p.ReleaseIP4(allzeros)
			}
			if !ip.IsUnspecifiedIP(allones) {
				p.ReleaseIP4(allones)
			}
		}

		c.defaultBridgePool.ReleaseIP4Range(space)
	}()

	// subnet may not be specified, e.g. for "external" networks
	if !ip.IsUnspecifiedSubnet(subnet) {
		// allocate the subnet
		space, defaultPool, err = c.reserveSubnet(subnet)
		if err != nil {
			return err
		}

		subnet = space.Network

		spaces, err = reservePools(space, spaces)
		if err != nil {
			return err
		}

		// reserve all-ones and all-zeros addresses, which are not routable and so
		// should not be handed out
		allones = ip.AllOnesAddr(subnet)
		allzeros = ip.AllZerosAddr(subnet)
		for _, p := range spaces {
			p.ReserveIP4(allones)
			p.ReserveIP4(allzeros)

			// reserve DNS IPs
			for _, d := range s.dns {
				if d.Equal(gateway) {
					continue // gateway will be reserved later
				}

				p.ReserveIP4(d)
			}
		}

		if gateway, err = reserveGateway(gateway, subnet, spaces); err != nil {
			return err
		}

		s.gateway = gateway
		s.spaces = spaces
		s.subnet = subnet
	}

	c.scopes[s.name] = s

	return nil
}
Exemple #7
0
func (v *Validator) network(ctx context.Context, input *data.Data, conf *config.VirtualContainerHostConfigSpec) {
	defer trace.End(trace.Begin(""))

	// External net
	// external network is default for appliance
	err := v.addNetworkHelper(ctx, conf, input.ExternalNetworkName, "external", "external", true)
	if err != nil {
		v.NoteIssue(fmt.Errorf("Error checking network for --external-network: %s", err))
		v.suggestNetwork("--external-network", true)
	}
	// Bridge network should be different than all other networks
	v.checkNetworkConflict(input.BridgeNetworkName, input.ExternalNetworkName, "external")

	// Client net
	if input.ClientNetworkName == "" {
		input.ClientNetworkName = input.ExternalNetworkName
	}
	err = v.addNetworkHelper(ctx, conf, input.ClientNetworkName, "client", "client", false)
	if err != nil {
		v.NoteIssue(fmt.Errorf("Error checking network for --client-network: %s", err))
		v.suggestNetwork("--client-network", true)
	}
	v.checkNetworkConflict(input.BridgeNetworkName, input.ClientNetworkName, "client")

	// Management net
	if input.ManagementNetworkName == "" {
		input.ManagementNetworkName = input.ClientNetworkName
	}
	err = v.addNetworkHelper(ctx, conf, input.ManagementNetworkName, "", "management", false)
	if err != nil {
		v.NoteIssue(fmt.Errorf("Error checking network for --management-network: %s", err))
		v.suggestNetwork("--management-network", true)
	}
	v.checkNetworkConflict(input.BridgeNetworkName, input.ManagementNetworkName, "management")

	// Bridge net -
	//   vCenter: must exist and must be a DPG
	//   ESX: doesn't need to exist - we will create with default value
	//
	// for now we're hardcoded to "bridge" for the container host name
	conf.BridgeNetwork = "bridge"
	endpointMoref, err := v.dpgHelper(ctx, input.BridgeNetworkName)

	var bridgeID, netMoid string
	if err != nil {
		bridgeID = ""
		netMoid = ""
	} else {
		bridgeID = endpointMoref.String()
		netMoid = endpointMoref.String()
	}

	checkBridgeVDS := true
	if err != nil {
		if _, ok := err.(*find.NotFoundError); !ok || v.IsVC() {
			v.NoteIssue(fmt.Errorf("An existing distributed port group must be specified for bridge network on vCenter: %s", err))
			v.suggestNetwork("--bridge-network", false)
			checkBridgeVDS = false // prevent duplicate error output
		}

		// this allows the dispatcher to create the network with corresponding name
		// if BridgeNetworkName doesn't already exist then we set the ContainerNetwork
		// ID to the name, but leaving the NetworkEndpoint moref as ""
		netMoid = input.BridgeNetworkName
	}

	bridgeNet := &executor.NetworkEndpoint{
		Common: executor.Common{
			Name: "bridge",
			ID:   bridgeID,
		},
		Static: &net.IPNet{IP: net.IPv4zero}, // static but managed externally
		Network: executor.ContainerNetwork{
			Common: executor.Common{
				Name: "bridge",
				ID:   netMoid,
			},
		},
	}
	// we need to have the bridge network identified as an available container network
	conf.AddContainerNetwork(&bridgeNet.Network)
	// we also need to have the appliance attached to the bridge network to allow
	// port forwarding
	conf.AddNetwork(bridgeNet)

	err = v.checkVDSMembership(ctx, endpointMoref, input.BridgeNetworkName)
	if err != nil && checkBridgeVDS {
		v.NoteIssue(fmt.Errorf("Unable to check hosts in vDS for %q: %s", input.BridgeNetworkName, err))
	}

	// add mapped networks (from --container-network)
	//   these should be a distributed port groups in vCenter
	suggestedMapped := false // only suggest mapped nets once
	for name, net := range input.MappedNetworks {
		checkMappedVDS := true
		// "bridge" is reserved
		if name == "bridge" {
			v.NoteIssue(fmt.Errorf("Cannot use reserved name \"bridge\" for container network"))
			continue
		}

		gw := input.MappedNetworksGateways[name]
		pools := input.MappedNetworksIPRanges[name]
		dns := input.MappedNetworksDNS[name]
		if len(pools) != 0 && ip.IsUnspecifiedSubnet(&gw) {
			v.NoteIssue(fmt.Errorf("IP range specified without gateway for container network %q", name))
			continue
		}

		if !ip.IsUnspecifiedSubnet(&gw) && !ip.IsRoutableIP(gw.IP, &gw) {
			v.NoteIssue(fmt.Errorf("Gateway %s is not a routable address", gw.IP))
			continue
		}

		err = nil
		// verify ip ranges are within subnet,
		// and don't overlap with each other
		for i, r := range pools {
			if !gw.Contains(r.FirstIP) || !gw.Contains(r.LastIP) {
				err = fmt.Errorf("IP range %q is not in subnet %q", r, gw)
				break
			}

			for _, r2 := range pools[i+1:] {
				if r2.Overlaps(r) {
					err = fmt.Errorf("Overlapping ip ranges: %q %q", r2, r)
					break
				}
			}

			if err != nil {
				break
			}
		}

		if err != nil {
			v.NoteIssue(err)
			continue
		}

		moref, err := v.dpgHelper(ctx, net)
		if err != nil {
			v.NoteIssue(fmt.Errorf("Error adding container network %q: %s", name, err))
			checkMappedVDS = false
			if !suggestedMapped {
				v.suggestNetwork("--container-network", true)
				suggestedMapped = true
			}
		}
		mappedNet := &executor.ContainerNetwork{
			Common: executor.Common{
				Name: name,
				ID:   moref.String(),
			},
			Gateway:     gw,
			Nameservers: dns,
			Pools:       pools,
		}
		if input.BridgeNetworkName == net {
			v.NoteIssue(errors.Errorf("the bridge network must not be shared with another network role - %q also mapped as container network %q", input.BridgeNetworkName, name))
		}

		err = v.checkVDSMembership(ctx, moref, net)
		if err != nil && checkMappedVDS {
			v.NoteIssue(fmt.Errorf("Unable to check hosts in vDS for %q: %s", net, err))
		}

		conf.AddContainerNetwork(mappedNet)
	}
}
Exemple #8
0
func (c *Context) newScopeCommon(id uid.UID, name, scopeType string, subnet *net.IPNet, gateway net.IP, dns []net.IP, ipam *IPAM, network object.NetworkReference) (*Scope, error) {

	var err error
	var space *AddressSpace
	var defaultPool bool
	var allzeros, allones net.IP

	// cleanup
	defer func() {
		if err == nil || space == nil || !defaultPool {
			return
		}

		for _, p := range ipam.spaces {
			// release DNS IPs
			for _, d := range dns {
				p.ReleaseIP4(d)
			}

			// release gateway
			if !ip.IsUnspecifiedIP(gateway) {
				p.ReleaseIP4(gateway)
			}

			// release all-ones and all-zeros addresses
			if !ip.IsUnspecifiedIP(allzeros) {
				p.ReleaseIP4(allzeros)
			}
			if !ip.IsUnspecifiedIP(allones) {
				p.ReleaseIP4(allones)
			}
		}

		c.defaultBridgePool.ReleaseIP4Range(space)
	}()

	// subnet may not be specified, e.g. for "external" networks
	if !ip.IsUnspecifiedSubnet(subnet) {
		// allocate the subnet
		space, defaultPool, err = c.reserveSubnet(subnet)
		if err != nil {
			return nil, err
		}

		subnet = space.Network

		ipam.spaces, err = reservePools(space, ipam)
		if err != nil {
			return nil, err
		}

		// reserve all-ones and all-zeros addresses, which are not routable and so
		// should not be handed out
		allones = ip.AllOnesAddr(subnet)
		allzeros = ip.AllZerosAddr(subnet)
		for _, p := range ipam.spaces {
			p.ReserveIP4(allones)
			p.ReserveIP4(allzeros)

			// reserve DNS IPs
			for _, d := range dns {
				if d.Equal(gateway) {
					continue // gateway will be reserved later
				}

				p.ReserveIP4(d)
			}
		}

		if gateway, err = reserveGateway(gateway, subnet, ipam); err != nil {
			return nil, err
		}

	}

	newScope := &Scope{
		id:         id,
		name:       name,
		subnet:     *subnet,
		gateway:    gateway,
		ipam:       ipam,
		containers: make(map[uid.UID]*Container),
		scopeType:  scopeType,
		space:      space,
		dns:        dns,
		builtin:    false,
		network:    network,
	}

	c.scopes[name] = newScope

	return newScope, nil
}
Exemple #9
0
func TestMapExternalNetworks(t *testing.T) {
	ctx, err := NewContext(net.IPNet{IP: net.IPv4(172, 16, 0, 0), Mask: net.CIDRMask(12, 32)}, net.CIDRMask(16, 32))
	if err != nil {
		t.Fatalf("NewContext() => (nil, %s), want (ctx, nil)", err)
	}

	// check if external networks were loaded
	for n, nn := range Config.ContainerNetworks {
		scopes, err := ctx.Scopes(&n)
		if err != nil || len(scopes) != 1 {
			t.Fatalf("external network %s was not loaded", n)
		}

		s := scopes[0]
		pools := s.IPAM().Pools()
		if !ip.IsUnspecifiedIP(nn.Gateway.IP) {
			subnet := &net.IPNet{IP: nn.Gateway.IP.Mask(nn.Gateway.Mask), Mask: nn.Gateway.Mask}
			if ip.IsUnspecifiedSubnet(s.Subnet()) || !s.Subnet().IP.Equal(subnet.IP) || !bytes.Equal(s.Subnet().Mask, subnet.Mask) {
				t.Fatalf("external network %s was loaded with wrong subnet, got: %s, want: %s", n, s.Subnet(), subnet)
			}

			if ip.IsUnspecifiedIP(s.Gateway()) || !s.Gateway().Equal(nn.Gateway.IP) {
				t.Fatalf("external network %s was loaded with wrong gateway, got: %s, want: %s", n, s.Gateway(), nn.Gateway.IP)
			}

			if len(nn.Pools) == 0 {
				// only one pool corresponding to the subnet
				if len(pools) != 1 || pools[0] != subnet.String() {
					t.Fatalf("external network %s was loaded with wrong pool, got: %+v, want %+v", n, pools, []*net.IPNet{subnet})
				}
			}
		}

		for _, d := range nn.Nameservers {
			found := false
			for _, d2 := range s.DNS() {
				if d2.Equal(d) {
					found = true
					break
				}
			}

			if !found {
				t.Fatalf("external network %s was loaded with wrong nameservers, got: %+v, want: %+v", n, s.DNS(), nn.Nameservers)
			}
		}

		for _, p := range nn.Pools {
			found := false
			for _, p2 := range pools {
				if p2 == p.String() {
					found = true
					break
				}
			}

			if !found {
				t.Fatalf("external network %s was loaded with wrong pools, got: %+v, want: %+v", n, s.IPAM().Pools(), nn.Pools)
			}
		}
	}
}