blob: 24fb57b34d2d670d08951a603ed92bc06da8a3eb [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()
{
return (*this == IPV6);
}
bool
l3_proto_t::is_ipv4()
{
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;
}
/*
* 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;
}
/**
* 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, 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_v4
route::prefix_t::mask() const
{
uint32_t a;
a = ~((1 << mask_width()) - 1);
boost::asio::ip::address_v4 addr(a);
return (addr);
}
boost::asio::ip::address_v4
route::prefix_t::low() const
{
boost::asio::ip::address_v4 low;
low = address().to_v4() & mask();
return (low);
}
boost::asio::ip::address_v4
route::prefix_t::high() const
{
boost::asio::ip::address_v4 high;
high = address().to_v4() | ~mask();
return (high);
}
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "mozilla")
* End:
*/