common/ipprefix.h (182 lines of code) (raw):
#ifndef __IPPREFIX__
#define __IPPREFIX__
#include <assert.h>
#include <stdexcept>
#include <arpa/inet.h>
#include "ipaddress.h"
namespace swss {
class IpPrefix
{
public:
IpPrefix() = default;
IpPrefix(const std::string &ipPrefixStr);
IpPrefix(uint32_t addr, int mask);
IpPrefix(const ip_addr_t &ip, int mask);
inline bool isV4() const
{
return m_ip.isV4();
}
inline IpAddress getIp() const
{
return m_ip;
}
inline IpAddress getBroadcastIp() const
{
switch (m_ip.getIp().family)
{
case AF_INET:
{
return IpAddress((m_ip.getV4Addr()) | ~(getMask().getV4Addr()));
}
case AF_INET6:
{
ip_addr_t ipa;
ipa.family = AF_INET6;
const uint8_t *prefix = m_ip.getV6Addr();
IpAddress ip6mask = getMask();
const uint8_t *mask = ip6mask.getV6Addr();
for (int i = 0; i < 16; ++i)
{
ipa.ip_addr.ipv6_addr[i] = (uint8_t)(prefix[i] | ~mask[i]);
}
return IpAddress(ipa);
}
default:
{
throw std::logic_error("Invalid family");
}
}
}
inline IpAddress getMask() const
{
switch (m_ip.getIp().family)
{
case AF_INET:
{
return IpAddress(htonl((uint32_t)((0xFFFFFFFFLL << (32 - m_mask)) & 0xFFFFFFFFLL)));
}
case AF_INET6:
{
ip_addr_t ipa;
ipa.family = AF_INET6;
assert(m_mask >= 0 && m_mask <= 128);
int mid = m_mask >> 3;
int bits = m_mask & 0x7;
memset(ipa.ip_addr.ipv6_addr, 0xFF, mid);
if (mid < 16)
{
assert(mid >= 0 && mid < 16);
ipa.ip_addr.ipv6_addr[mid] = (uint8_t)(0xFF << (8 - bits));
memset(ipa.ip_addr.ipv6_addr + mid + 1, 0, 16 - mid - 1);
}
return IpAddress(ipa);
}
default:
{
throw std::logic_error("Invalid family");
}
}
}
inline int getMaskLength() const
{
return m_mask;
}
inline bool isDefaultRoute() const
{
return (m_mask == 0);
}
inline bool isFullMask() const
{
if (m_ip.isV4())
return (m_mask == 32);
else
return (m_mask == 128);
}
inline bool isAddressInSubnet(const IpAddress& addr) const
{
if (m_ip.getIp().family != addr.getIp().family)
{
return false;
}
switch (m_ip.getIp().family)
{
case AF_INET:
{
uint32_t mask = getMask().getV4Addr();
return (m_ip.getV4Addr() & mask) == (addr.getV4Addr() & mask);
}
case AF_INET6:
{
const uint8_t *prefix = m_ip.getV6Addr();
IpAddress ip6mask = getMask();
const uint8_t *mask = ip6mask.getV6Addr();
const uint8_t *ip = addr.getV6Addr();
for (int i = 0; i < 16; ++i)
{
if ((prefix[i] & mask[i]) != (ip[i] & mask[i]))
{
return false;
}
}
return true;
}
default:
{
throw std::logic_error("Invalid family");
}
}
}
inline IpPrefix getSubnet() const
{
switch (m_ip.getIp().family)
{
case AF_INET:
{
uint32_t ipaddr = m_ip.getV4Addr();
uint32_t mask = getMask().getV4Addr();
ipaddr &= mask;
return IpPrefix(ipaddr, m_mask);
}
case AF_INET6:
{
const uint8_t *ipaddr = m_ip.getV6Addr();
uint8_t subnet[INET6_ADDRSTRLEN] = {0};
memcpy(subnet, ipaddr, 16);
IpAddress ip6mask = getMask();
const uint8_t *mask = ip6mask.getV6Addr();
for (int i = 0; i < 16; ++i)
{
subnet[i] &= mask[i];
}
char buf[INET6_ADDRSTRLEN];
std::string ipStr(inet_ntop(AF_INET6,
&subnet,
buf,
INET6_ADDRSTRLEN));
return IpPrefix(ipStr + "/" + std::to_string(m_mask));
}
default:
{
throw std::logic_error("Invalid family");
}
}
}
inline bool operator<(const IpPrefix &o) const
{
if (m_mask != o.m_mask)
return m_mask < o.m_mask;
else
return m_ip < o.m_ip;
}
inline bool operator==(const IpPrefix &o) const
{
return m_ip == o.m_ip && m_mask == o.m_mask;
}
std::string to_string() const;
private:
bool isValid();
IpAddress m_ip;
int m_mask;
};
}
#endif