From 041fa507c085010d55d18088321faa64d345bb88 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 20 Dec 2017 08:49:51 -0800 Subject: VOM: NAT updates Change-Id: I112afaa1f2ccd2ee62a436c73802afaea9b44779 Signed-off-by: Neale Ranns --- src/vpp-api/vom/nat_binding.cpp | 76 +++++++-- src/vpp-api/vom/nat_binding.hpp | 17 ++ src/vpp-api/vom/nat_binding_cmds.cpp | 129 +++++++++++++- src/vpp-api/vom/nat_binding_cmds.hpp | 316 +++++++++++++++++++++++++---------- src/vpp-api/vom/nat_static.cpp | 100 +++++------ src/vpp-api/vom/nat_static.hpp | 12 +- src/vpp-api/vom/nat_static_cmds.cpp | 13 +- src/vpp-api/vom/nat_static_cmds.hpp | 5 +- src/vpp-api/vom/prefix.cpp | 7 + src/vpp-api/vom/prefix.hpp | 5 + src/vpp-api/vom/types.cpp | 7 + src/vpp-api/vom/types.hpp | 5 + 12 files changed, 518 insertions(+), 174 deletions(-) diff --git a/src/vpp-api/vom/nat_binding.cpp b/src/vpp-api/vom/nat_binding.cpp index ce73ae44b54..a2e71b3a085 100644 --- a/src/vpp-api/vom/nat_binding.cpp +++ b/src/vpp-api/vom/nat_binding.cpp @@ -29,6 +29,13 @@ nat_binding::zone_t::zone_t(int v, const std::string s) : enum_base(v, s) { } +const nat_binding::zone_t& +nat_binding::zone_t::from_vpp(u8 is_inside) +{ + if (is_inside) + return zone_t::INSIDE; + return zone_t::OUTSIDE; +} /** * Construct a new object matching the desried state @@ -57,7 +64,19 @@ nat_binding::nat_binding(const nat_binding& o) nat_binding::~nat_binding() { sweep(); - m_db.release(make_tuple(m_itf->key(), m_dir, m_proto), this); + m_db.release(key(), this); +} + +const nat_binding::key_t +nat_binding::key() const +{ + return (make_tuple(m_itf->key(), m_dir, m_proto)); +} + +bool +nat_binding::operator==(const nat_binding& n) const +{ + return ((key() == n.key()) && (m_zone == n.m_zone)); } void @@ -68,7 +87,8 @@ nat_binding::sweep() HW::enqueue(new nat_binding_cmds::unbind_44_input_cmd( m_binding, m_itf->handle(), m_zone)); } else { - assert(!"Unimplemented"); + HW::enqueue(new nat_binding_cmds::unbind_44_output_cmd( + m_binding, m_itf->handle(), m_zone)); } } HW::write(); @@ -82,7 +102,8 @@ nat_binding::replay() HW::enqueue(new nat_binding_cmds::bind_44_input_cmd( m_binding, m_itf->handle(), m_zone)); } else { - assert(!"Unimplemented"); + HW::enqueue(new nat_binding_cmds::bind_44_output_cmd( + m_binding, m_itf->handle(), m_zone)); } } } @@ -98,7 +119,8 @@ nat_binding::update(const nat_binding& desired) HW::enqueue(new nat_binding_cmds::bind_44_input_cmd( m_binding, m_itf->handle(), m_zone)); } else { - assert(!"Unimplemented"); + HW::enqueue(new nat_binding_cmds::bind_44_input_cmd( + m_binding, m_itf->handle(), m_zone)); } } } @@ -107,8 +129,9 @@ std::string nat_binding::to_string() const { std::ostringstream s; - s << "nat-binding:[" << m_itf->to_string() << " " << m_dir.to_string() << " " - << m_proto.to_string() << " " << m_zone.to_string() << "]"; + s << "nat-binding:[" << m_itf->to_string() + << " direction:" << m_dir.to_string() << " proto:" << m_proto.to_string() + << " zone:" << m_zone.to_string() << "]"; return (s.str()); } @@ -116,8 +139,13 @@ nat_binding::to_string() const std::shared_ptr nat_binding::find_or_add(const nat_binding& temp) { - return (m_db.find_or_add( - make_tuple(temp.m_itf->key(), temp.m_dir, temp.m_proto), temp)); + return (m_db.find_or_add(temp.key(), temp)); +} + +std::shared_ptr +nat_binding::find(const key_t& key) +{ + return (m_db.find(key)); } std::shared_ptr @@ -156,9 +184,35 @@ nat_binding::event_handler::handle_replay() void nat_binding::event_handler::handle_populate(const client_db::key_t& key) { - /** - * This is done while populating the interfaces - */ + std::shared_ptr icmd = + std::make_shared(); + + HW::enqueue(icmd); + HW::write(); + + for (auto& record : *icmd) { + auto& payload = record.get_payload(); + + std::shared_ptr itf = interface::find(payload.sw_if_index); + nat_binding nb(*itf, direction_t::INPUT, l3_proto_t::IPV4, + zone_t::from_vpp(payload.is_inside)); + OM::commit(key, nb); + } + + std::shared_ptr ocmd = + std::make_shared(); + + HW::enqueue(ocmd); + HW::write(); + + for (auto& record : *ocmd) { + auto& payload = record.get_payload(); + + std::shared_ptr itf = interface::find(payload.sw_if_index); + nat_binding nb(*itf, direction_t::OUTPUT, l3_proto_t::IPV4, + zone_t::from_vpp(payload.is_inside)); + OM::commit(key, nb); + } } dependency_t diff --git a/src/vpp-api/vom/nat_binding.hpp b/src/vpp-api/vom/nat_binding.hpp index 77612502680..a99d23af601 100644 --- a/src/vpp-api/vom/nat_binding.hpp +++ b/src/vpp-api/vom/nat_binding.hpp @@ -54,6 +54,8 @@ public: * Deny Zone */ const static zone_t OUTSIDE; + + const static zone_t& from_vpp(u8 is_inside); }; /** @@ -85,6 +87,16 @@ public: */ ~nat_binding(); + /** + * Comparison operator - for UT + */ + bool operator==(const nat_binding& n) const; + + /** + * Return the binding's key + */ + const key_t key() const; + /** * Return the 'singular instance' of the L2 config that matches this * object @@ -96,6 +108,11 @@ public: */ std::string to_string() const; + /** + * Static function to find the bridge_domain in the model + */ + static std::shared_ptr find(const key_t& key); + /** * Dump all nat_bindings into the stream provided */ diff --git a/src/vpp-api/vom/nat_binding_cmds.cpp b/src/vpp-api/vom/nat_binding_cmds.cpp index 106ec5edac9..66b2827abc2 100644 --- a/src/vpp-api/vom/nat_binding_cmds.cpp +++ b/src/vpp-api/vom/nat_binding_cmds.cpp @@ -101,22 +101,106 @@ unbind_44_input_cmd::to_string() const return (s.str()); } -dump_44_cmd::dump_44_cmd() +bind_44_output_cmd::bind_44_output_cmd(HW::item& item, + const handle_t& itf, + const nat_binding::zone_t& zone) + : rpc_cmd(item) + , m_itf(itf) + , m_zone(zone) +{ +} + +bool +bind_44_output_cmd::operator==(const bind_44_output_cmd& other) const +{ + return ((m_itf == other.m_itf) && (m_zone == other.m_zone)); +} + +rc_t +bind_44_output_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.is_add = 1; + payload.is_inside = (nat_binding::zone_t::INSIDE == m_zone ? 1 : 0); + payload.sw_if_index = m_itf.value(); + + VAPI_CALL(req.execute()); + + m_hw_item.set(wait()); + + return rc_t::OK; +} + +std::string +bind_44_output_cmd::to_string() const { + std::ostringstream s; + s << "nat-44-output-binding-create: " << m_hw_item.to_string() + << " itf:" << m_itf << " " << m_zone.to_string(); + + return (s.str()); } -dump_44_cmd::dump_44_cmd(const dump_44_cmd& d) +unbind_44_output_cmd::unbind_44_output_cmd(HW::item& item, + const handle_t& itf, + const nat_binding::zone_t& zone) + : rpc_cmd(item) + , m_itf(itf) + , m_zone(zone) { } bool -dump_44_cmd::operator==(const dump_44_cmd& other) const +unbind_44_output_cmd::operator==(const unbind_44_output_cmd& other) const +{ + return ((m_itf == other.m_itf) && (m_zone == other.m_zone)); +} + +rc_t +unbind_44_output_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.is_add = 0; + payload.is_inside = (nat_binding::zone_t::INSIDE == m_zone ? 1 : 0); + payload.sw_if_index = m_itf.value(); + + VAPI_CALL(req.execute()); + + m_hw_item.set(wait()); + + return rc_t::OK; +} + +std::string +unbind_44_output_cmd::to_string() const +{ + std::ostringstream s; + s << "nat-44-output-binding-create: " << m_hw_item.to_string() + << " itf:" << m_itf << " " << m_zone.to_string(); + + return (s.str()); +} + +dump_input_44_cmd::dump_input_44_cmd() +{ +} + +dump_input_44_cmd::dump_input_44_cmd(const dump_input_44_cmd& d) +{ +} + +bool +dump_input_44_cmd::operator==(const dump_input_44_cmd& other) const { return (true); } rc_t -dump_44_cmd::issue(connection& con) +dump_input_44_cmd::issue(connection& con) { m_dump.reset(new msg_t(con.ctx(), std::ref(*this))); @@ -128,13 +212,46 @@ dump_44_cmd::issue(connection& con) } std::string -dump_44_cmd::to_string() const +dump_input_44_cmd::to_string() const { - return ("nat-binding-dump"); + return ("nat-input-binding-dump"); } + +dump_output_44_cmd::dump_output_44_cmd() +{ } + +dump_output_44_cmd::dump_output_44_cmd(const dump_output_44_cmd& d) +{ +} + +bool +dump_output_44_cmd::operator==(const dump_output_44_cmd& other) const +{ + return (true); } +rc_t +dump_output_44_cmd::issue(connection& con) +{ + m_dump.reset(new msg_t(con.ctx(), std::ref(*this))); + + VAPI_CALL(m_dump->execute()); + + wait(); + + return rc_t::OK; +} + +std::string +dump_output_44_cmd::to_string() const +{ + return ("nat-output-binding-dump"); +} + +}; // namespace nat_binding_cmds +}; // namespace VOM + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vpp-api/vom/nat_binding_cmds.hpp b/src/vpp-api/vom/nat_binding_cmds.hpp index ed9048a9da3..bb9404872eb 100644 --- a/src/vpp-api/vom/nat_binding_cmds.hpp +++ b/src/vpp-api/vom/nat_binding_cmds.hpp @@ -1,131 +1,269 @@ +/* + * 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. + */ + #ifndef __VOM_NAT_BINDING_CMDS_H__ #define __VOM_NAT_BINDING_CMDS_H__ +#include "vom/dump_cmd.hpp" #include "vom/nat_binding.hpp" #include "vom/rpc_cmd.hpp" -#include "vom/dump_cmd.hpp" #include namespace VOM { namespace nat_binding_cmds { /** - * A functor class that binds L2 configuration to an interface + * A functor class that binds a NAT configuration to an input interface */ class bind_44_input_cmd - : public rpc_cmd, - rc_t, - vapi::Nat44_interface_add_del_feature> + : public rpc_cmd, rc_t, vapi::Nat44_interface_add_del_feature> +{ +public: + /** + * Constructor + */ + bind_44_input_cmd(HW::item& item, + const handle_t& itf, + const nat_binding::zone_t& zone); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const bind_44_input_cmd& i) const; + +private: + /** + * The interface to bind + */ + const handle_t m_itf; + + /** + * The zone the interface is in + */ + const nat_binding::zone_t m_zone; +}; + +/** + * A cmd class that unbinds a NAT configuration from an input interface + */ +class unbind_44_input_cmd + : public rpc_cmd, rc_t, vapi::Nat44_interface_add_del_feature> { public: - /** - * Constructor - */ - bind_44_input_cmd(HW::item& item, + /** + * Constructor + */ + unbind_44_input_cmd(HW::item& item, const handle_t& itf, const nat_binding::zone_t& zone); - /** - * Issue the command to VPP/HW - */ - rc_t issue(connection& con); - /** - * convert to string format for debug purposes - */ - std::string to_string() const; + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; - /** - * Comparison operator - only used for UT - */ - bool operator==(const bind_44_input_cmd& i) const; + /** + * Comparison operator - only used for UT + */ + bool operator==(const unbind_44_input_cmd& i) const; private: - /** - * The interface to bind - */ - const handle_t m_itf; - - /** - * The zone the interface is in - */ - const nat_binding::zone_t m_zone; + /** + * The interface to bind + */ + const handle_t m_itf; + + /** + * The zone the interface is in + */ + const nat_binding::zone_t m_zone; }; /** - * A cmd class that Unbinds L2 configuration from an interface + * A functor class that binds a NAT configuration to an output interface */ -class unbind_44_input_cmd - : public rpc_cmd, - rc_t, - vapi::Nat44_interface_add_del_feature> +class bind_44_output_cmd + : public rpc_cmd, + rc_t, + vapi::Nat44_interface_add_del_output_feature> { public: - /** - * Constructor - */ - unbind_44_input_cmd(HW::item& item, - const handle_t& itf, - const nat_binding::zone_t& zone); - - /** - * Issue the command to VPP/HW - */ - rc_t issue(connection& con); - /** - * convert to string format for debug purposes - */ - std::string to_string() const; - - /** - * Comparison operator - only used for UT - */ - bool operator==(const unbind_44_input_cmd& i) const; + /** + * Constructor + */ + bind_44_output_cmd(HW::item& item, + const handle_t& itf, + const nat_binding::zone_t& zone); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const bind_44_output_cmd& i) const; private: - /** - * The interface to bind - */ - const handle_t m_itf; - - /** - * The zone the interface is in - */ - const nat_binding::zone_t m_zone; + /** + * The interface to bind + */ + const handle_t m_itf; + + /** + * The zone the interface is in + */ + const nat_binding::zone_t m_zone; }; /** - * A cmd class that Dumps all the nat_statics + * A cmd class that unbinds a NAT configuration from an output interface */ -class dump_44_cmd : public dump_cmd +class unbind_44_output_cmd + : public rpc_cmd, + rc_t, + vapi::Nat44_interface_add_del_output_feature> { public: - /** - * Constructor - */ - dump_44_cmd(); - dump_44_cmd(const dump_44_cmd& d); - - /** - * Issue the command to VPP/HW - */ - rc_t issue(connection& con); - /** - * convert to string format for debug purposes - */ - std::string to_string() const; - - /** - * Comparison operator - only used for UT - */ - bool operator==(const dump_44_cmd& i) const; + /** + * Constructor + */ + unbind_44_output_cmd(HW::item& item, + const handle_t& itf, + const nat_binding::zone_t& zone); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const unbind_44_output_cmd& i) const; private: - /** - * HW reutrn code - */ - HW::item item; + /** + * The interface to bind + */ + const handle_t m_itf; + + /** + * The zone the interface is in + */ + const nat_binding::zone_t m_zone; }; + +/** + * A cmd class that Dumps all the nat_statics + */ +class dump_input_44_cmd : public dump_cmd +{ +public: + /** + * Constructor + */ + dump_input_44_cmd(); + dump_input_44_cmd(const dump_input_44_cmd& d); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const dump_input_44_cmd& i) const; + +private: + /** + * HW reutrn code + */ + HW::item item; }; + +/** + * A cmd class that Dumps all the nat_statics + */ +class dump_output_44_cmd + : public dump_cmd +{ +public: + /** + * Constructor + */ + dump_output_44_cmd(); + dump_output_44_cmd(const dump_output_44_cmd& d); + + /** + * Issue the command to VPP/HW + */ + rc_t issue(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const dump_output_44_cmd& i) const; + +private: + /** + * HW reutrn code + */ + HW::item item; }; +}; // namespace nat_binding_cmds +}; // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ + #endif diff --git a/src/vpp-api/vom/nat_static.cpp b/src/vpp-api/vom/nat_static.cpp index 619cc3b6602..a90b0bcfac9 100644 --- a/src/vpp-api/vom/nat_static.cpp +++ b/src/vpp-api/vom/nat_static.cpp @@ -52,7 +52,19 @@ nat_static::~nat_static() sweep(); // not in the DB anymore. - m_db.release(std::make_pair(m_rd->key(), m_outside), this); + m_db.release(key(), this); +} + +const nat_static::key_t +nat_static::key() const +{ + return (std::make_pair(m_rd->key(), m_outside)); +} + +bool +nat_static::operator==(const nat_static& n) const +{ + return ((key() == n.key()) && (m_inside == n.m_inside)); } void @@ -97,8 +109,8 @@ nat_static::to_string() const { std::ostringstream s; s << "nat-static:[" - << "table:" << m_rd->to_string() << " inside: " << m_inside.to_string() - << " outside " << m_outside.to_string() << "]"; + << "table:" << m_rd->to_string() << " inside:" << m_inside.to_string() + << " outside:" << m_outside.to_string() << "]"; return (s.str()); } @@ -106,8 +118,13 @@ nat_static::to_string() const std::shared_ptr nat_static::find_or_add(const nat_static& temp) { - return ( - m_db.find_or_add(std::make_pair(temp.m_rd->key(), temp.m_outside), temp)); + return (m_db.find_or_add(temp.key(), temp)); +} + +std::shared_ptr +nat_static::find(const key_t& key) +{ + return (m_db.find(key)); } std::shared_ptr @@ -142,61 +159,34 @@ nat_static::event_handler::handle_replay() m_db.replay(); } -/* void nat_static::populate_i(const client_db::key_t &key, */ -/* std::shared_ptr itf, */ -/* const l3_proto_t &proto) */ -/* { */ -/* /\* */ -/* * dump VPP current states */ -/* *\/ */ -/* std::shared_ptr cmd = */ -/* std::make_shared(nat_static::dump_cmd(itf->handle(), - * proto)); */ - -/* HW::enqueue(cmd); */ -/* HW::write(); */ - -/* for (auto & record : *cmd) */ -/* { */ -/* /\* */ -/* * construct a nat_static from each recieved record. */ -/* *\/ */ -/* auto &payload = record.get_payload(); */ - -/* mac_address_t mac(payload.mac_address); */ -/* boost::asio::ip::address ip_addr = from_bytes(payload.is_ipv6, */ -/* payload.ip_address); - */ -/* nat_static n(*itf, mac, ip_addr); */ - -/* VOM_LOG(log_level_t::DEBUG) << "nat_static-dump: " */ -/* << itf->to_string() */ -/* << mac.to_string() */ -/* << ip_addr.to_string(); */ - -/* /\* */ -/* * Write each of the discovered interfaces into the OM, */ -/* * but disable the HW Command q whilst we do, so that no */ -/* * commands are sent to VPP */ -/* *\/ */ -/* OM::commit(key, n); */ -/* } */ -/* } */ - void nat_static::event_handler::handle_populate(const client_db::key_t& key) { - /* auto it = interface::cbegin(); */ + /* + * dump VPP current states + */ + std::shared_ptr cmd = + std::make_shared(); - /* while (it != interface::cend()) */ - /* { */ - /* nat_static::populate_i(key, it->second.lock(), l3_proto_t::IPV4); - */ - /* nat_static::populate_i(key, it->second.lock(), l3_proto_t::IPV6); - */ + HW::enqueue(cmd); + HW::write(); + + for (auto& record : *cmd) { + + auto& payload = record.get_payload(); - /* ++it; */ - /* } */ + boost::asio::ip::address inside = from_bytes(0, payload.local_ip_address); + boost::asio::ip::address outside = + from_bytes(0, payload.external_ip_address); + nat_static n(route_domain(payload.vrf_id), inside, outside.to_v4()); + + /* + * Write each of the discovered mappings into the OM, + * but disable the HW Command q whilst we do, so that no + * commands are sent to VPP + */ + OM::commit(key, n); + } } dependency_t diff --git a/src/vpp-api/vom/nat_static.hpp b/src/vpp-api/vom/nat_static.hpp index 1560968a6ed..4c2dab15325 100644 --- a/src/vpp-api/vom/nat_static.hpp +++ b/src/vpp-api/vom/nat_static.hpp @@ -59,6 +59,16 @@ public: */ ~nat_static(); + /** + * Comparison operator - for UT + */ + bool operator==(const nat_static& n) const; + + /** + * Return the object's key + */ + const key_t key() const; + /** * Return the matching 'singular instance' */ @@ -67,7 +77,7 @@ public: /** * Find the instnace of the bridge_domain domain in the OM */ - static std::shared_ptr find(const nat_static& temp); + static std::shared_ptr find(const key_t& key); /** * Dump all bridge_domain-doamin into the stream provided diff --git a/src/vpp-api/vom/nat_static_cmds.cpp b/src/vpp-api/vom/nat_static_cmds.cpp index 2abe0d2b658..facc7c6db8b 100644 --- a/src/vpp-api/vom/nat_static_cmds.cpp +++ b/src/vpp-api/vom/nat_static_cmds.cpp @@ -123,14 +123,6 @@ delete_44_cmd::to_string() const return (s.str()); } -dump_44_cmd::dump_44_cmd() -{ -} - -dump_44_cmd::dump_44_cmd(const dump_44_cmd& d) -{ -} - bool dump_44_cmd::operator==(const dump_44_cmd& other) const { @@ -154,8 +146,9 @@ dump_44_cmd::to_string() const { return ("nat-static-dump"); } -} // namespace nat_static_cmds -} // namespace VOM + +}; // namespace nat_static_cmds +}; // namespace VOM /* * fd.io coding-style-patch-verification: ON diff --git a/src/vpp-api/vom/nat_static_cmds.hpp b/src/vpp-api/vom/nat_static_cmds.hpp index 1db2571a558..a4adcef19b5 100644 --- a/src/vpp-api/vom/nat_static_cmds.hpp +++ b/src/vpp-api/vom/nat_static_cmds.hpp @@ -105,8 +105,8 @@ public: /** * Constructor */ - dump_44_cmd(); - dump_44_cmd(const dump_44_cmd& d); + dump_44_cmd() = default; + ~dump_44_cmd() = default; /** * Issue the command to VPP/HW @@ -128,6 +128,7 @@ private: */ HW::item item; }; + }; // namespace nat_static_cmds }; // namespace vom diff --git a/src/vpp-api/vom/prefix.cpp b/src/vpp-api/vom/prefix.cpp index 269c28f1f54..e754999b6d1 100644 --- a/src/vpp-api/vom/prefix.cpp +++ b/src/vpp-api/vom/prefix.cpp @@ -53,6 +53,13 @@ l3_proto_t::from_address(const boost::asio::ip::address& addr) return 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 */ diff --git a/src/vpp-api/vom/prefix.hpp b/src/vpp-api/vom/prefix.hpp index e395e1760ca..25b188ff86c 100644 --- a/src/vpp-api/vom/prefix.hpp +++ b/src/vpp-api/vom/prefix.hpp @@ -48,6 +48,11 @@ private: l3_proto_t(int v, const std::string& s); }; +/** + * Ostream output for l3_proto_t + */ +std::ostream& operator<<(std::ostream& os, const l3_proto_t& l3p); + /** * A next-hop protocol describes the protocol of a peer to which packets * are sent after matching a route. diff --git a/src/vpp-api/vom/types.cpp b/src/vpp-api/vom/types.cpp index cdced0ffb72..9df53146948 100644 --- a/src/vpp-api/vom/types.cpp +++ b/src/vpp-api/vom/types.cpp @@ -261,8 +261,15 @@ direction_t::direction_t(int v, const std::string s) : enum_base(v, s) { } +std::ostream& +operator<<(std::ostream& os, const direction_t& dir) +{ + os << dir.to_string(); + return os; } +}; // namespace VOM + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vpp-api/vom/types.hpp b/src/vpp-api/vom/types.hpp index 839b29a9702..61a25e71cb8 100644 --- a/src/vpp-api/vom/types.hpp +++ b/src/vpp-api/vom/types.hpp @@ -153,6 +153,11 @@ struct direction_t : public enum_base const static direction_t OUTPUT; }; +/** + * Output ostream for direction_t + */ +std::ostream& operator<<(std::ostream& os, const direction_t& dir); + /** * A type declaration of an interface handle in VPP */ -- cgit 1.2.3-korg