Пример #1
0
func (*AddressSuite) TestIPv4ToDecimal(c *gc.C) {
	zeroIP, err := network.IPv4ToDecimal(net.ParseIP("0.0.0.0"))
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(zeroIP, gc.Equals, uint32(0))

	nilIP := net.ParseIP("bad format")
	_, err = network.IPv4ToDecimal(nilIP)
	c.Assert(err, gc.ErrorMatches, `"<nil>" is not a valid IPv4 address`)

	_, err = network.IPv4ToDecimal(net.ParseIP("2001:db8::1"))
	c.Assert(err, gc.ErrorMatches, `"2001:db8::1" is not a valid IPv4 address`)

	nonZeroIP, err := network.IPv4ToDecimal(net.ParseIP("192.168.1.1"))
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(nonZeroIP, gc.Equals, uint32(3232235777))
}
Пример #2
0
// attemptToPickNewAddress will try to pick a new address. It can fail
// with AlreadyExists due to a race condition between fetching the
// list of addresses already in use and allocating a new one. If the
// subnet is not alive, it will also fail. It is called in a loop by
// PickNewAddress until it gets one or there are no more available!
func (s *Subnet) attemptToPickNewAddress() (*IPAddress, error) {
	if s.doc.Life != Alive {
		return nil, errors.Errorf("cannot pick address: subnet %q is not alive", s)
	}
	high := s.doc.AllocatableIPHigh
	low := s.doc.AllocatableIPLow
	if low == "" || high == "" {
		return nil, errors.Errorf("no allocatable IP addresses for subnet %q", s)
	}

	// convert low and high to decimals as the bounds
	lowDecimal, err := network.IPv4ToDecimal(net.ParseIP(low))
	if err != nil {
		// these addresses are validated so should never happen
		return nil, errors.Annotatef(err, "invalid AllocatableIPLow %q for subnet %q", low, s)
	}
	highDecimal, err := network.IPv4ToDecimal(net.ParseIP(high))
	if err != nil {
		// these addresses are validated so should never happen
		return nil, errors.Annotatef(err, "invalid AllocatableIPHigh %q for subnet %q", high, s)
	}

	// find all addresses for this subnet and convert them to decimals
	addresses, closer := s.st.getCollection(ipaddressesC)
	defer closer()

	id := s.ID()
	var doc struct {
		Value string
	}
	allocated := make(map[uint32]bool)
	iter := addresses.Find(bson.D{{"subnetid", id}}).Iter()
	for iter.Next(&doc) {
		// skip invalid values. Can't happen anyway as we validate.
		value, err := network.IPv4ToDecimal(net.ParseIP(doc.Value))
		if err != nil {
			continue
		}
		allocated[value] = true
	}
	if err := iter.Close(); err != nil {
		return nil, errors.Annotatef(err, "cannot read addresses of subnet %q", s)
	}

	// Check that the number of addresses in use is less than the
	// difference between low and high - i.e. we haven't exhausted all
	// possible addresses.
	if len(allocated) >= int(highDecimal-lowDecimal)+1 {
		return nil, errors.Errorf("allocatable IP addresses exhausted for subnet %q", s)
	}

	// pick a new random decimal between the low and high bounds that
	// doesn't match an existing one
	newDecimal := pickAddress(lowDecimal, highDecimal, allocated)

	// convert it back to a dotted-quad
	newIP := network.DecimalToIPv4(newDecimal)
	newAddr := network.NewAddress(newIP.String())

	// and create a new IPAddress from it and return it
	return s.st.AddIPAddress(newAddr, s.ID())
}