blob: b9910d3f2fc3c85fc069e7f650387ff988305100 [file] [log] [blame]
/*
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <boost/algorithm/string.hpp>
#include <sstream>
#include "vom/prefix.hpp"
namespace VOM {
/*
* Keep this in sync with VPP's fib_protocol_t
*/
const l3_proto_t l3_proto_t::IPV4(0, "ipv4");
const l3_proto_t l3_proto_t::IPV6(1, "ipv6");
const l3_proto_t l3_proto_t::MPLS(2, "mpls");
l3_proto_t::l3_proto_t(int v, const std::string& s)
: enum_base<l3_proto_t>(v, s)
{
}
bool
l3_proto_t::is_ipv6() const
{
return (*this == IPV6);
}
bool
l3_proto_t::is_ipv4() const
{
return (*this == IPV4);
}
const l3_proto_t&
l3_proto_t::from_address(const boost::asio::ip::address& addr)
{
if (addr.is_v6()) {
return IPV6;
}
return IPV4;
}
const nh_proto_t&
l3_proto_t::to_nh_proto() const
{
if (*this == IPV4)
return nh_proto_t::IPV4;
else if (*this == IPV6)
return nh_proto_t::IPV6;
else if (*this == MPLS)
return nh_proto_t::MPLS;
return nh_proto_t::IPV4;
}
std::ostream&
operator<<(std::ostream& os, const l3_proto_t& l3p)
{
os << l3p.to_string();
return os;
}
/*
* Keep this in sync with VPP's dpo_proto_t
*/
const nh_proto_t nh_proto_t::IPV4(0, "ipv4");
const nh_proto_t nh_proto_t::IPV6(1, "ipv6");
const nh_proto_t nh_proto_t::MPLS(2, "mpls");
const nh_proto_t nh_proto_t::ETHERNET(3, "ethernet");
nh_proto_t::nh_proto_t(int v, const std::string& s)
: enum_base<nh_proto_t>(v, s)
{
}
const nh_proto_t&
nh_proto_t::from_address(const boost::asio::ip::address& addr)
{
if (addr.is_v6()) {
return IPV6;
}
return IPV4;
}
const ip_dscp_t ip_dscp_t::DSCP_CS0(0, "CS0");
const ip_dscp_t ip_dscp_t::DSCP_CS1(8, "CS1");
const ip_dscp_t ip_dscp_t::DSCP_CS2(16, "CS2");
const ip_dscp_t ip_dscp_t::DSCP_CS3(24, "CS3");
const ip_dscp_t ip_dscp_t::DSCP_CS4(32, "CS4");
const ip_dscp_t ip_dscp_t::DSCP_CS5(40, "CS5");
const ip_dscp_t ip_dscp_t::DSCP_CS6(48, "CS6");
const ip_dscp_t ip_dscp_t::DSCP_CS7(50, "CS7");
const ip_dscp_t ip_dscp_t::DSCP_AF11(10, "AF11");
const ip_dscp_t ip_dscp_t::DSCP_AF12(12, "AF12");
const ip_dscp_t ip_dscp_t::DSCP_AF13(14, "AF13");
const ip_dscp_t ip_dscp_t::DSCP_AF21(18, "AF21");
const ip_dscp_t ip_dscp_t::DSCP_AF22(20, "AF22");
const ip_dscp_t ip_dscp_t::DSCP_AF23(22, "AF23");
const ip_dscp_t ip_dscp_t::DSCP_AF31(26, "AF31");
const ip_dscp_t ip_dscp_t::DSCP_AF32(28, "AF32");
const ip_dscp_t ip_dscp_t::DSCP_AF33(30, "AF33");
const ip_dscp_t ip_dscp_t::DSCP_AF41(34, "AF41");
const ip_dscp_t ip_dscp_t::DSCP_AF42(36, "AF42");
const ip_dscp_t ip_dscp_t::DSCP_AF43(38, "AF43");
const ip_dscp_t ip_dscp_t::DSCP_EF(46, "EF");
ip_dscp_t::ip_dscp_t(int v, const std::string& s)
: enum_base<ip_dscp_t>(v, s)
{
}
ip_dscp_t::ip_dscp_t(int v)
: enum_base<ip_dscp_t>(v, std::to_string(v))
{
}
/**
* The all Zeros prefix
*/
const route::prefix_t route::prefix_t::ZERO("0.0.0.0", 0);
const route::prefix_t route::prefix_t::ZEROv6("::", 0);
route::prefix_t::prefix_t(const boost::asio::ip::address& addr, uint8_t len)
: m_addr(addr)
, m_len(len)
{
}
route::prefix_t::prefix_t(const boost::asio::ip::address& addr)
: m_addr(addr)
, m_len(VOM::mask_width(addr))
{
}
route::prefix_t::prefix_t(const std::string& s, uint8_t len)
: m_addr(boost::asio::ip::address::from_string(s))
, m_len(len)
{
}
route::prefix_t::prefix_t(const prefix_t& o)
: m_addr(o.m_addr)
, m_len(o.m_len)
{
}
route::prefix_t::prefix_t()
: m_addr()
, m_len(0)
{
}
route::prefix_t::~prefix_t()
{
}
route::prefix_t&
route::prefix_t::operator=(const route::prefix_t& o)
{
m_addr = o.m_addr;
m_len = o.m_len;
return (*this);
}
const boost::asio::ip::address&
route::prefix_t::address() const
{
return (m_addr);
}
uint8_t
route::prefix_t::mask_width() const
{
return (m_len);
}
bool
route::prefix_t::operator<(const route::prefix_t& o) const
{
if (m_len == o.m_len) {
return (m_addr < o.m_addr);
} else {
return (m_len < o.m_len);
}
}
bool
route::prefix_t::operator==(const route::prefix_t& o) const
{
return (m_len == o.m_len && m_addr == o.m_addr);
}
bool
route::prefix_t::operator!=(const route::prefix_t& o) const
{
return (!(*this == o));
}
std::string
route::prefix_t::to_string() const
{
std::ostringstream s;
s << m_addr.to_string() << "/" << std::to_string(m_len);
return (s.str());
}
boost::asio::ip::address
from_bytes(uint8_t is_ip6, const uint8_t* bytes)
{
boost::asio::ip::address addr;
if (is_ip6) {
std::array<uint8_t, 16> a;
std::copy(bytes, bytes + 16, std::begin(a));
boost::asio::ip::address_v6 v6(a);
addr = v6;
} else {
std::array<uint8_t, 4> a;
std::copy(bytes, bytes + 4, std::begin(a));
boost::asio::ip::address_v4 v4(a);
addr = v4;
}
return (addr);
}
route::prefix_t::prefix_t(uint8_t is_ip6, uint8_t* addr, uint8_t len)
: m_addr(from_bytes(is_ip6, addr))
, m_len(len)
{
}
void
to_bytes(const boost::asio::ip::address_v6& addr, uint8_t* array)
{
memcpy(array, addr.to_bytes().data(), 16);
}
void
to_bytes(const boost::asio::ip::address_v4& addr, uint8_t* array)
{
memcpy(array, addr.to_bytes().data(), 4);
}
void
to_bytes(const boost::asio::ip::address& addr, uint8_t* is_ip6, uint8_t* array)
{
if (addr.is_v6()) {
*is_ip6 = 1;
to_bytes(addr.to_v6(), array);
} else {
*is_ip6 = 0;
to_bytes(addr.to_v4(), array);
}
}
uint32_t
mask_width(const boost::asio::ip::address& addr)
{
if (addr.is_v6()) {
return 128;
}
return 32;
}
void
route::prefix_t::to_vpp(uint8_t* is_ip6, uint8_t* addr, uint8_t* len) const
{
*len = m_len;
to_bytes(m_addr, is_ip6, addr);
}
l3_proto_t
route::prefix_t::l3_proto() const
{
if (m_addr.is_v6()) {
return (l3_proto_t::IPV6);
} else {
return (l3_proto_t::IPV4);
}
return (l3_proto_t::IPV4);
}
std::ostream&
operator<<(std::ostream& os, const route::prefix_t& pfx)
{
os << pfx.to_string();
return (os);
}
boost::asio::ip::address_v4
operator|(const boost::asio::ip::address_v4& addr1,
const boost::asio::ip::address_v4& addr2)
{
uint32_t a;
a = addr1.to_ulong() | addr2.to_ulong();
boost::asio::ip::address_v4 addr(a);
return (addr);
}
boost::asio::ip::address_v4 operator&(const boost::asio::ip::address_v4& addr1,
const boost::asio::ip::address_v4& addr2)
{
uint32_t a;
a = addr1.to_ulong() & addr2.to_ulong();
boost::asio::ip::address_v4 addr(a);
return (addr);
}
boost::asio::ip::address_v4 operator~(const boost::asio::ip::address_v4& addr1)
{
uint32_t a;
a = ~addr1.to_ulong();
boost::asio::ip::address_v4 addr(a);
return (addr);
}
boost::asio::ip::address_v6
operator|(const boost::asio::ip::address_v6& addr1,
const boost::asio::ip::address_v6& addr2)
{
boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();
for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
ii < b1.max_size(); ii++) {
b1[ii] |= b2[ii];
}
boost::asio::ip::address_v6 addr(b1);
return (addr);
}
boost::asio::ip::address_v6 operator&(const boost::asio::ip::address_v6& addr1,
const boost::asio::ip::address_v6& addr2)
{
boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
boost::asio::ip::address_v6::bytes_type b2 = addr2.to_bytes();
for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
ii < b1.max_size(); ii++) {
b1[ii] &= b2[ii];
}
boost::asio::ip::address_v6 addr(b1);
return (addr);
}
boost::asio::ip::address_v6 operator~(const boost::asio::ip::address_v6& addr1)
{
boost::asio::ip::address_v6::bytes_type b1 = addr1.to_bytes();
for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
ii < b1.max_size(); ii++) {
b1[ii] = ~b1[ii];
}
boost::asio::ip::address_v6 addr(b1);
return (addr);
}
boost::asio::ip::address
operator|(const boost::asio::ip::address& addr1,
const boost::asio::ip::address& addr2)
{
if (addr1.is_v6())
return (addr1.to_v6() | addr2.to_v6());
else
return (addr1.to_v4() | addr2.to_v4());
}
boost::asio::ip::address operator&(const boost::asio::ip::address& addr1,
const boost::asio::ip::address& addr2)
{
if (addr1.is_v6())
return (addr1.to_v6() & addr2.to_v6());
else
return (addr1.to_v4() & addr2.to_v4());
}
boost::asio::ip::address operator~(const boost::asio::ip::address& addr1)
{
if (addr1.is_v6())
return ~(addr1.to_v6());
else
return ~(addr1.to_v4());
}
boost::asio::ip::address
route::prefix_t::mask() const
{
if (m_addr.is_v6()) {
boost::asio::ip::address_v6::bytes_type b =
boost::asio::ip::address_v6::any().to_bytes();
uint8_t n_bits = mask_width();
for (boost::asio::ip::address_v6::bytes_type::size_type ii = 0;
ii < b.max_size(); ii++) {
for (int8_t bit = 7; bit >= 0 && n_bits; bit--) {
b[ii] |= (1 << bit);
n_bits--;
}
if (!n_bits)
break;
}
return (boost::asio::ip::address_v6(b));
} else {
uint32_t a;
a = ~((1 << (32 - mask_width())) - 1);
return (boost::asio::ip::address_v4(a));
}
}
route::prefix_t
route::prefix_t::low() const
{
prefix_t pfx(*this);
pfx.m_addr = pfx.m_addr & pfx.mask();
return (pfx);
}
route::prefix_t
route::prefix_t::high() const
{
prefix_t pfx(*this);
pfx.m_addr = pfx.m_addr | ~pfx.mask();
return (pfx);
}
/**
* The all Zeros prefix
*/
const route::mprefix_t route::mprefix_t::ZERO;
const route::mprefix_t route::mprefix_t::ZEROv6;
route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr, uint8_t len)
: m_gaddr(gaddr)
, m_saddr()
, m_len(len)
{
}
route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr)
: m_gaddr(gaddr)
, m_saddr()
, m_len(VOM::mask_width(gaddr))
{
}
route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
const boost::asio::ip::address& gaddr)
: m_gaddr(gaddr)
, m_saddr(saddr)
, m_len(2 * VOM::mask_width(gaddr))
{
}
route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
const boost::asio::ip::address& gaddr,
uint16_t len)
: m_gaddr(gaddr)
, m_saddr(saddr)
, m_len(len)
{
}
route::mprefix_t::mprefix_t(const mprefix_t& o)
: m_gaddr(o.m_gaddr)
, m_saddr(o.m_saddr)
, m_len(o.m_len)
{
}
route::mprefix_t::mprefix_t()
: m_gaddr()
, m_saddr()
, m_len(0)
{
}
route::mprefix_t::~mprefix_t()
{
}
const boost::asio::ip::address&
route::mprefix_t::grp_address() const
{
return (m_gaddr);
}
const boost::asio::ip::address&
route::mprefix_t::src_address() const
{
return (m_saddr);
}
uint8_t
route::mprefix_t::mask_width() const
{
return (m_len);
}
l3_proto_t
route::mprefix_t::l3_proto() const
{
if (m_gaddr.is_v6()) {
return (l3_proto_t::IPV6);
} else {
return (l3_proto_t::IPV4);
}
return (l3_proto_t::IPV4);
}
route::mprefix_t&
route::mprefix_t::operator=(const route::mprefix_t& o)
{
m_gaddr = o.m_gaddr;
m_saddr = o.m_saddr;
m_len = o.m_len;
return (*this);
}
bool
route::mprefix_t::operator<(const route::mprefix_t& o) const
{
if (m_len == o.m_len) {
if (m_saddr == o.m_saddr)
return (m_gaddr < o.m_gaddr);
else
return (m_saddr < o.m_saddr);
} else {
return (m_len < o.m_len);
}
}
bool
route::mprefix_t::operator==(const route::mprefix_t& o) const
{
return (m_len == o.m_len && m_gaddr == o.m_gaddr && m_saddr == o.m_saddr);
}
bool
route::mprefix_t::operator!=(const route::mprefix_t& o) const
{
return (!(*this == o));
}
std::string
route::mprefix_t::to_string() const
{
std::ostringstream s;
s << "(" << m_saddr.to_string() << "," << m_gaddr.to_string() << "/"
<< std::to_string(m_len) << ")";
return (s.str());
}
}; // namespace VOM
/*
* fd.io coding-style-patch-verification: OFF
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/