IOAddress
IOAddress::subtract(const IOAddress& a, const IOAddress& b) {
- if (a.isV4() != b.isV4()) {
+ if (a.getFamily() != b.getFamily()) {
isc_throw(BadValue, "Both addresses have to be the same family");
}
if (a.isV4()) {
// Subtracting v4 is easy. We have uint32_t operator.
- return (IOAddress((uint32_t)a - (uint32_t)b));
+ return (IOAddress(static_cast<uint32_t>(a) - static_cast<uint32_t>(b)));
} else {
// v6 is more involved.
// Let's extract the raw data first.
- vector<uint8_t> a_vec = a.toBytes();
- vector<uint8_t> b_vec = b.toBytes();
+ const vector<uint8_t>& a_vec(a.toBytes());
+ const vector<uint8_t>& b_vec(b.toBytes());
// ... and prepare the result
- vector<uint8_t> result(16,0);
+ vector<uint8_t> result(V6ADDRESS_LEN,0);
// Carry is a boolean, but to avoid its frequent casting, let's
// use uint8_t. Also, some would prefer to call it borrow, but I prefer
uint8_t carry = 0;
// Now perform subtraction with borrow.
- for (int i = 15; i >=0; --i) {
- if (a_vec[i] >= (b_vec[i] + carry) ) {
- result[i] = a_vec[i] - b_vec[i] - carry;
- carry = 0;
- } else {
- result[i] = a_vec[i] - b_vec[i] - carry;
- carry = 1;
- }
+ for (int i = a_vec.size(); i >= 0; --i) {
+ result[i] = a_vec[i] - b_vec[i] - carry;
+ carry = (a_vec[i] < b_vec[i] + carry);
}
return (fromBytes(AF_INET6, &result[0]));
}
IOAddress
-IOAddress::increaseAddress(const IOAddress& addr) {
+IOAddress::increase(const IOAddress& addr) {
// Get a buffer holding an address.
const std::vector<uint8_t>& vec = addr.toBytes();
// Get the address length.
// Start increasing the least significant byte
for (int i = len - 1; i >= 0; --i) {
- ++packed[i];
// if we haven't overflowed (0xff -> 0x0), than we are done
- if (packed[i] != 0) {
+ if (++packed[i] != 0) {
break;
}
}
/// 192.0.2.5 - 192.0.2.0 = 0.0.0.5
/// fe80::abcd - fe80:: = ::abcd
///
+ /// It is possible to subtract greater from lesser address, e.g.
+ /// 192.168.56.10 - 192.168.67.20, but please do understand that
+ /// the address space is a finite field in mathematical sense, so
+ /// you may end up with a result that is greater then any of the
+ /// addresses you specified. Also, subtraction is not commutative,
+ /// so a - b != b - a.
+ ///
/// This operation is essential for calculating the number of
/// leases in a pool, where we need to calculate (max - min).
/// @throw BadValue if addresses are of different family
/// This method works for both IPv4 and IPv6 addresses. For example,
/// increase 192.0.2.255 will become 192.0.3.0.
///
+ /// Address space is a finite field in the mathematical sense, so keep
+ /// in mind that the address space "loops". 255.255.255.255 increased
+ /// by one gives 0.0.0.0. The same is true for maximum value of IPv6
+ /// (all 1's) looping to ::.
+ ///
+ /// @todo Determine if we have a use-case for increasing the address
+ /// by more than one. Increase by one is used in AllocEngine. This method
+ /// could take extra parameter that specifies the value by which the
+ /// address should be increased.
+ ///
/// @param addr address to be increased
/// @return address increased by one
static IOAddress
- increaseAddress(const IOAddress& addr);
+ increase(const IOAddress& addr);
/// \brief Converts IPv4 address to uint32_t
///
EXPECT_EQ("192.0.2.13", IOAddress::subtract(addr1, bcast).toText());
EXPECT_EQ("191.255.255.255", IOAddress::subtract(addr3, addr4).toText());
+ // Let's check if we can subtract greater address from smaller.
+ // This will check if we can "loop"
+ EXPECT_EQ("255.255.255.251", IOAddress::subtract(addr3, addr2).toText());
+
IOAddress addr6("fe80::abcd");
IOAddress addr7("fe80::");
IOAddress addr8("fe80::1234");
// Subtracting :: is like subtracting 0.
EXPECT_EQ("2001:db8::face", IOAddress::subtract(addr9, any6).toText());
+ // Let's check if we can subtract greater address from smaller.
+ // This will check if we can "loop"
+ EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:edcc",
+ IOAddress::subtract(addr7, addr8).toText());
+
// Inter-family relations are not allowed.
EXPECT_THROW(IOAddress::subtract(addr1, addr6), isc::BadValue);
EXPECT_THROW(IOAddress::subtract(addr6, addr1), isc::BadValue);
IOAddress any6("::");
IOAddress the_last_one("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
- EXPECT_EQ("192.0.2.13", IOAddress::increaseAddress(addr1).toText());
- EXPECT_EQ("0.0.0.1", IOAddress::increaseAddress(any4).toText());
- EXPECT_EQ("0.0.0.0", IOAddress::increaseAddress(bcast).toText());
- EXPECT_EQ("2001:db8:0:1::", IOAddress::increaseAddress(addr6).toText());
- EXPECT_EQ("::2", IOAddress::increaseAddress(addr11).toText());
- EXPECT_EQ("::1", IOAddress::increaseAddress(any6).toText());
- EXPECT_EQ("::", IOAddress::increaseAddress(the_last_one).toText());
+ EXPECT_EQ("192.0.2.13", IOAddress::increase(addr1).toText());
+ EXPECT_EQ("0.0.0.1", IOAddress::increase(any4).toText());
+ EXPECT_EQ("0.0.0.0", IOAddress::increase(bcast).toText());
+ EXPECT_EQ("2001:db8:0:1::", IOAddress::increase(addr6).toText());
+ EXPECT_EQ("::2", IOAddress::increase(addr11).toText());
+ EXPECT_EQ("::1", IOAddress::increase(any6).toText());
+ EXPECT_EQ("::", IOAddress::increase(the_last_one).toText());
}
uint64_t
addrsInRange(const isc::asiolink::IOAddress& min,
const isc::asiolink::IOAddress& max) {
- if (min.isV4() != max.isV4()) {
+ if (min.getFamily() != max.getFamily()) {
isc_throw(BadValue, "Both addresses have to be the same family");
}
+ if (max < min) {
+ isc_throw(BadValue, min.toText() << " must not be greater than "
+ << max.toText());
+ }
+
if (min.isV4()) {
// Let's explicitly cast last_ and first_ (IOAddress). This conversion is
// automatic, but let's explicitly cast it show that we moved to integer
// domain and addresses are now substractable.
- uint64_t max_numeric = uint32_t(max);
- uint64_t min_numeric = uint32_t(min);
+ uint64_t max_numeric = static_cast<uint32_t>(max);
+ uint64_t min_numeric = static_cast<uint32_t>(min);
// We can simply subtract the values. We need to increase the result
// by one, as both min and max are included in the range. So even if
// Increase it by one (a..a range still contains one address, even though
// a subtracted from a is zero).
- count = IOAddress::increaseAddress(count);
+ count = IOAddress::increase(count);
// We don't have uint128, so for anything greater than 2^64, we'll just
// assume numeric_limits<uint64_t>::max. Let's do it the manual way.
- std::vector<uint8_t> bin = count.toBytes();
+ const std::vector<uint8_t>& bin(count.toBytes());
// If any of the most significant 64 bits is set, we have more than
// 2^64 addresses and can't represent it even on uint64_t.
}
}
-uint64_t prefixesInRange(uint8_t pool_len, uint8_t delegated_len) {
+uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len) {
if (delegated_len < pool_len) {
return (0);
}
// Now count specifies the exponent (e.g. if the difference between the
// delegated and pool length is 4, we have 16 prefixes), so we need
// to calculate 2^(count - 1)
- return (((uint64_t)2) << (count - 1));
+ return ((static_cast<uint64_t>(2)) << (count - 1));
}
}
/// Example: prefixesInRange(48, 64) returns 65536, as there are /48 pool
/// can be split into 65536 prefixes, each /64 large.
///
-/// @param min the first address in range
-/// @param max the last address in range
-/// @return number of addresses in range
-uint64_t prefixesInRange(uint8_t pool_len, uint8_t delegated_len);
+/// @param pool_len length of the pool in bits
+/// @param delegated_len length of the prefixes to be delegated from the pool
+/// @return number of prefixes in range
+uint64_t prefixesInRange(const uint8_t pool_len, const uint8_t delegated_len);
};
};
IOAddress next("::");
if (!prefix) {
- next = IOAddress::increaseAddress(last); // basically addr++
+ next = IOAddress::increase(last); // basically addr++
} else {
Pool6Ptr pool6 = boost::dynamic_pointer_cast<Pool6>(*it);
if (!pool6) {
// cannot be stored in uint32_t.
EXPECT_EQ(uint64_t(std::numeric_limits<uint32_t>::max()) + 1,
addrsInRange(IOAddress("0.0.0.0"), IOAddress("255.255.255.255")));
+
+ // The upper bound cannot be smaller than the lower bound.
+ EXPECT_THROW(addrsInRange(IOAddress("192.0.2.5"), IOAddress("192.0.2.4")),
+ isc::BadValue);
}
// Checks if the calculation for IPv6 addresses in range are correct.
// at max value of uint64_t.
EXPECT_EQ(std::numeric_limits<uint64_t>::max(), addrsInRange(IOAddress("::"),
IOAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")));
+
+ EXPECT_THROW(addrsInRange(IOAddress("fe80::5"), IOAddress("fe80::4")),
+ isc::BadValue);
}
// Checks if prefixInRange returns valid number of prefixes in specified range.
void
checkAddrIncrease(NakedAllocEngine::NakedIterativeAllocator&,
std::string input, std::string exp_output) {
- EXPECT_EQ(exp_output, asiolink::IOAddress::increaseAddress(
+ EXPECT_EQ(exp_output, asiolink::IOAddress::increase(
asiolink::IOAddress(input)).toText());
}