/* * 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 #include #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(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; } 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(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 a; std::copy(bytes, bytes + 16, std::begin(a)); boost::asio::ip::address_v6 v6(a); addr = v6; } else { std::array 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); } }; // namespace VOM /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "mozilla") * End: */