/* * 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; } /* * 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_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: */