From daff1784037376f4a5caec2f5975f9b5fc23d5a4 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 16 May 2018 04:12:18 -0700 Subject: DHCP Client Dump - use types on the DHCP API so that the same data is sent in comfing messages and in dumps - add the DHCP client dump API - update VOM to refelct API changes - rename VOM class dhcp_config* dhcp_client* - the VOM dhcp_client class maintains the lease data (which it reads on a dump) for clients to read Change-Id: I2a43463937cbd80c01d45798e74b21288d8b8ead Signed-off-by: Neale Ranns --- extras/vom/vom/Makefile.am | 7 +- extras/vom/vom/dhcp_client.cpp | 346 ++++++++++++++++++++++++++++++++++++ extras/vom/vom/dhcp_client.hpp | 310 ++++++++++++++++++++++++++++++++ extras/vom/vom/dhcp_client_cmds.cpp | 237 ++++++++++++++++++++++++ extras/vom/vom/dhcp_client_cmds.hpp | 208 ++++++++++++++++++++++ extras/vom/vom/dhcp_config.cpp | 194 -------------------- extras/vom/vom/dhcp_config.hpp | 234 ------------------------ extras/vom/vom/dhcp_config_cmds.cpp | 178 ------------------- extras/vom/vom/dhcp_config_cmds.hpp | 172 ------------------ extras/vom/vom/l3_binding.cpp | 29 --- extras/vom/vom/l3_binding.hpp | 5 - extras/vom/vom/neighbour_cmds.cpp | 6 +- 12 files changed, 1109 insertions(+), 817 deletions(-) create mode 100644 extras/vom/vom/dhcp_client.cpp create mode 100644 extras/vom/vom/dhcp_client.hpp create mode 100644 extras/vom/vom/dhcp_client_cmds.cpp create mode 100644 extras/vom/vom/dhcp_client_cmds.hpp delete mode 100644 extras/vom/vom/dhcp_config.cpp delete mode 100644 extras/vom/vom/dhcp_config.hpp delete mode 100644 extras/vom/vom/dhcp_config_cmds.cpp delete mode 100644 extras/vom/vom/dhcp_config_cmds.hpp (limited to 'extras') diff --git a/extras/vom/vom/Makefile.am b/extras/vom/vom/Makefile.am index 892f437976e..2abf3463c8f 100644 --- a/extras/vom/vom/Makefile.am +++ b/extras/vom/vom/Makefile.am @@ -98,8 +98,8 @@ libvom_la_SOURCES = \ client_db.cpp \ cmd.cpp \ connection.cpp \ - dhcp_config_cmds.cpp \ - dhcp_config.cpp \ + dhcp_client_cmds.cpp \ + dhcp_client.cpp \ hw_cmds.cpp \ hw.cpp \ inspect.cpp \ @@ -192,8 +192,7 @@ vominclude_HEADERS = \ client_db.hpp \ cmd.hpp \ connection.hpp \ - dhcp_config.hpp \ - dhcp_config_cmds.hpp \ + dhcp_client.hpp \ dump_cmd.hpp \ enum_base.hpp \ event_cmd.hpp \ diff --git a/extras/vom/vom/dhcp_client.cpp b/extras/vom/vom/dhcp_client.cpp new file mode 100644 index 00000000000..fcadfa69ded --- /dev/null +++ b/extras/vom/vom/dhcp_client.cpp @@ -0,0 +1,346 @@ +/* + * 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 "vom/dhcp_client.hpp" +#include "vom/dhcp_client_cmds.hpp" +#include "vom/singular_db_funcs.hpp" + +namespace VOM { +const dhcp_client::state_t dhcp_client::state_t::DISCOVER(0, "discover"); +const dhcp_client::state_t dhcp_client::state_t::REQUEST(1, "request"); +const dhcp_client::state_t dhcp_client::state_t::BOUND(2, "bound"); + +dhcp_client::state_t::state_t(int v, const std::string& s) + : enum_base(v, s) +{ +} + +const dhcp_client::state_t& +dhcp_client::state_t::from_vpp(int n) +{ + if (REQUEST == n) + return (REQUEST); + if (BOUND == n) + return (BOUND); + + return (DISCOVER); +} + +singular_db dhcp_client::m_db; +std::weak_ptr dhcp_client::m_s_event_cmd; +dhcp_client::dhcp_client_listener dhcp_client::m_listener; + +dhcp_client::event_handler dhcp_client::m_evh; + +dhcp_client::dhcp_client(const interface& itf, + const std::string& hostname, + bool set_broadcast_flag, + event_listener* ev) + : m_itf(itf.singular()) + , m_hostname(hostname) + , m_client_id(l2_address_t::ZERO) + , m_set_broadcast_flag(set_broadcast_flag) + , m_binding(0) + , m_evl(ev) + , m_event_cmd(get_event_cmd()) +{ +} + +dhcp_client::dhcp_client(const interface& itf, + const std::string& hostname, + const l2_address_t& client_id, + bool set_broadcast_flag, + event_listener* ev) + : m_itf(itf.singular()) + , m_hostname(hostname) + , m_client_id(client_id) + , m_set_broadcast_flag(set_broadcast_flag) + , m_binding(0) + , m_evl(ev) + , m_event_cmd(get_event_cmd()) +{ +} + +dhcp_client::dhcp_client(const dhcp_client& o) + : m_itf(o.m_itf) + , m_hostname(o.m_hostname) + , m_client_id(o.m_client_id) + , m_set_broadcast_flag(o.m_set_broadcast_flag) + , m_binding(0) + , m_evl(o.m_evl) + , m_event_cmd(o.m_event_cmd) +{ +} + +dhcp_client::~dhcp_client() +{ + sweep(); + + // not in the DB anymore. + m_db.release(m_itf->key(), this); +} + +bool +dhcp_client::operator==(const dhcp_client& l) const +{ + return ((key() == l.key()) && (m_hostname == l.m_hostname) && + (m_client_id == l.m_client_id)); +} + +const dhcp_client::key_t& +dhcp_client::key() const +{ + return (m_itf->key()); +} + +void +dhcp_client::sweep() +{ + if (m_binding) { + HW::enqueue( + new dhcp_client_cmds::unbind_cmd(m_binding, m_itf->handle(), m_hostname)); + } + HW::write(); +} + +void +dhcp_client::dump(std::ostream& os) +{ + db_dump(m_db, os); +} + +void +dhcp_client::replay() +{ + if (m_binding) { + HW::enqueue(new dhcp_client_cmds::bind_cmd(m_binding, m_itf->handle(), + m_hostname, m_client_id)); + } +} + +std::string +dhcp_client::to_string() const +{ + std::ostringstream s; + s << "DHCP-client: " << m_itf->to_string() << " hostname:" << m_hostname + << " client_id:[" << m_client_id << "] " << m_binding.to_string(); + if (m_lease) + s << " " << m_lease->to_string(); + else + s << " no-lease"; + + return (s.str()); +} + +void +dhcp_client::update(const dhcp_client& desired) +{ + /* + * the desired state is always that the interface should be created + */ + if (!m_binding) { + HW::enqueue(new dhcp_client_cmds::bind_cmd(m_binding, m_itf->handle(), + m_hostname, m_client_id)); + } + + if (desired.m_lease) + m_lease = desired.m_lease; + if (m_evl != desired.m_evl) { + m_evl = desired.m_evl; + } +} + +const std::shared_ptr +dhcp_client::lease() const +{ + return (m_lease); +} + +void +dhcp_client::lease(std::shared_ptr lease) +{ + m_lease = lease; +} + +std::shared_ptr +dhcp_client::find_or_add(const dhcp_client& temp) +{ + return (m_db.find_or_add(temp.m_itf->key(), temp)); +} + +std::shared_ptr +dhcp_client::find(const key_t& k) +{ + return (m_db.find(k)); +} + +std::shared_ptr +dhcp_client::singular() const +{ + return find_or_add(*this); +} + +dhcp_client::lease_t::lease_t() + : state(state_t::DISCOVER) + , mac(mac_address_t::ZERO) +{ +} + +dhcp_client::lease_t::lease_t(const state_t& state, + std::shared_ptr itf, + const boost::asio::ip::address& router_address, + const route::prefix_t& host_prefix, + const std::string& hostname, + const mac_address_t& mac) + : state(state) + , itf(itf) + , router_address(router_address) + , host_prefix(host_prefix) + , hostname(hostname) + , mac(mac) +{ +} + +std::string +dhcp_client::lease_t::to_string() const +{ + std::stringstream ss; + + ss << "lease:[" << itf->to_string() << " state: " << state.to_string() + << " host: " << host_prefix.to_string() << " router: " << router_address + << " mac: " << mac.to_string() << "]"; + + return (ss.str()); +} + +dhcp_client::event_listener::event_listener() + : m_status(rc_t::NOOP) +{ +} + +HW::item& +dhcp_client::event_listener::status() +{ + return (m_status); +} + +dhcp_client::event_handler::event_handler() +{ + OM::register_listener(this); + inspect::register_handler({ "dhcp" }, "DHCP clients", this); +} + +void +dhcp_client::event_handler::handle_replay() +{ + m_db.replay(); +} + +void +dhcp_client::event_handler::handle_populate(const client_db::key_t& key) +{ + std::shared_ptr cmd = + std::make_shared(); + + HW::enqueue(cmd); + HW::write(); + + for (auto& record : *cmd) { + auto& payload = record.get_payload(); + + std::shared_ptr itf = + interface::find(payload.client.sw_if_index); + + if (!itf) { + VOM_LOG(log_level_t::ERROR) << "dhcp-client dump:" + << " itf:" << payload.client.sw_if_index; + continue; + } + + const dhcp_client::state_t& s = + dhcp_client::state_t::from_vpp(payload.lease.state); + route::prefix_t pfx(payload.lease.is_ipv6, payload.lease.host_address, + payload.lease.mask_width); + std::string hostname = + reinterpret_cast(payload.lease.hostname); + l2_address_t l2(payload.client.id + 1); + dhcp_client dc(*itf, hostname, l2, payload.client.set_broadcast_flag); + dc.lease(std::make_shared( + s, itf, from_bytes(0, payload.lease.router_address), pfx, hostname, + mac_address_t(payload.lease.host_mac))); + OM::commit(key, dc); + } +} + +dependency_t +dhcp_client::event_handler::order() const +{ + return (dependency_t::BINDING); +} + +void +dhcp_client::event_handler::show(std::ostream& os) +{ + db_dump(m_db, os); +} + +std::shared_ptr +dhcp_client::get_event_cmd() +{ + if (m_s_event_cmd.expired()) { + std::shared_ptr c = + std::make_shared(m_listener); + + m_s_event_cmd = c; + + HW::enqueue(c); + HW::write(); + + return c; + } + + return (m_s_event_cmd.lock()); +} + +void +dhcp_client::handle_dhcp_event(std::shared_ptr lease) +{ + m_lease = lease; + if (m_evl) + m_evl->handle_dhcp_event(m_lease); +} + +void +dhcp_client::dhcp_client_listener::handle_dhcp_event(std::shared_ptr e) +{ + /* + * Find the client the event references + */ + std::shared_ptr client = find(e->itf->key()); + + if (client) { + client->handle_dhcp_event(e); + } +} + +}; // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ diff --git a/extras/vom/vom/dhcp_client.hpp b/extras/vom/vom/dhcp_client.hpp new file mode 100644 index 00000000000..17c626ed0f1 --- /dev/null +++ b/extras/vom/vom/dhcp_client.hpp @@ -0,0 +1,310 @@ +/* + * 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_DHCP_CLIENT_H__ +#define __VOM_DHCP_CLIENT_H__ + +#include "vom/hw.hpp" +#include "vom/inspect.hpp" +#include "vom/interface.hpp" +#include "vom/object_base.hpp" +#include "vom/om.hpp" +#include "vom/prefix.hpp" +#include "vom/singular_db.hpp" + +namespace VOM { +namespace dhcp_client_cmds { +class events_cmd; +}; +/** + * A representation of DHCP client on an interface + */ +class dhcp_client : public object_base +{ +public: + /** + * typedef for the DHCP client key type + */ + typedef interface::key_t key_t; + + struct state_t : enum_base + { + const static state_t DISCOVER; + const static state_t REQUEST; + const static state_t BOUND; + + static const state_t& from_vpp(int i); + + private: + /** + * Private constructor taking the value and the string name + */ + state_t(int v, const std::string& s); + }; + + /** + * A DHCP lease data + */ + struct lease_t + { + lease_t(); + lease_t(const state_t& state, + std::shared_ptr itf, + const boost::asio::ip::address& router_address, + const route::prefix_t& host_prefix, + const std::string& hostname, + const mac_address_t& mac); + + std::string to_string() const; + + const state_t& state; + std::shared_ptr itf; + boost::asio::ip::address router_address; + route::prefix_t host_prefix; + std::string hostname; + mac_address_t mac; + }; + + /** + * A class that listens to DHCP Events + */ + class event_listener + { + public: + /** + * Constructor + */ + event_listener(); + + /** + * listener's virtual function invoked when a DHCP event is + * available to read + */ + virtual void handle_dhcp_event(std::shared_ptr e) = 0; + + /** + * Return the HW::item associated with this command + */ + HW::item& status(); + + protected: + /** + * The HW::item associated with this command + */ + HW::item m_status; + }; + + /** + * Construct a new object matching the desried state + */ + dhcp_client(const interface& itf, + const std::string& hostname, + bool set_broadcast_flag = true, + event_listener* ev = nullptr); + + /** + * Construct a new object matching the desried state + */ + dhcp_client(const interface& itf, + const std::string& hostname, + const l2_address_t& client_id, + bool set_broadcast_flag = true, + event_listener* ev = nullptr); + + /** + * Copy Constructor + */ + dhcp_client(const dhcp_client& o); + + /** + * Destructor + */ + ~dhcp_client(); + + /** + * Comparison operator - for UT + */ + bool operator==(const dhcp_client& d) const; + + /** + * Return the object's key + */ + const key_t& key() const; + + /** + * Return the 'singular' of the DHCP client that matches this object + */ + std::shared_ptr singular() const; + + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Dump all DHCP clients into the stream provided + */ + static void dump(std::ostream& os); + + /** + * Find a DHCP client from its key + */ + static std::shared_ptr find(const key_t& k); + + /** + * return the current lease data + */ + const std::shared_ptr lease() const; + +private: + /** + * Class definition for listeners to OM events + */ + class event_handler : public OM::listener, public inspect::command_handler + { + public: + event_handler(); + virtual ~event_handler() = default; + + /** + * Handle a populate event + */ + void handle_populate(const client_db::key_t& key); + + /** + * Handle a replay event + */ + void handle_replay(); + + /** + * Show the object in the Singular DB + */ + void show(std::ostream& os); + + /** + * Get the sortable Id of the listener + */ + dependency_t order() const; + }; + + /** + * event_handler to register with OM + */ + static event_handler m_evh; + + /** + * Enquue commonds to the VPP command Q for the update + */ + void update(const dhcp_client& obj); + + /** + * Find or add DHCP client to the OM + */ + static std::shared_ptr find_or_add(const dhcp_client& temp); + + /* + * It's the OM class that calls singular() + */ + friend class OM; + + /** + * It's the singular_db class that calls replay() + */ + friend class singular_db; + + /** + * Sweep/reap the object if still stale + */ + void sweep(void); + + /** + * replay the object to create it in hardware + */ + void replay(void); + + void lease(std::shared_ptr l); + + /** + * A reference counting pointer to the interface on which DHCP client + * resides. By holding the reference here, we can guarantee that + * this object will outlive the interface + */ + const std::shared_ptr m_itf; + + /** + * The hostname in the DHCP client + */ + const std::string m_hostname; + + /** + * The option-61 client_id in the DHCP client + */ + const l2_address_t m_client_id; + + /** + * Flag to control the setting the of DHCP discover's broadcast flag + */ + const bool m_set_broadcast_flag; + + /** + * HW configuration for the binding. The bool representing the + * do/don't bind. + */ + HW::item m_binding; + + /** + * A pointer to an event listener for client events + */ + event_listener* m_evl; + + /** + * Current lease state for this client + */ + std::shared_ptr m_lease; + + std::shared_ptr m_event_cmd; + + void handle_dhcp_event(std::shared_ptr e); + + /** + * A map of all Dhcp clients keyed against the interface. + */ + static singular_db m_db; + + static std::weak_ptr m_s_event_cmd; + static std::shared_ptr get_event_cmd(); + + class dhcp_client_listener : public event_listener + { + public: + /** + * listener's virtual function invoked when a DHCP event is + * available to read + */ + void handle_dhcp_event(std::shared_ptr e); + }; + static dhcp_client_listener m_listener; +}; +}; + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ + +#endif diff --git a/extras/vom/vom/dhcp_client_cmds.cpp b/extras/vom/vom/dhcp_client_cmds.cpp new file mode 100644 index 00000000000..181a15f8f96 --- /dev/null +++ b/extras/vom/vom/dhcp_client_cmds.cpp @@ -0,0 +1,237 @@ +/* + * 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 "vom/dhcp_client_cmds.hpp" + +DEFINE_VAPI_MSG_IDS_DHCP_API_JSON; + +namespace VOM { +namespace dhcp_client_cmds { + +bind_cmd::bind_cmd(HW::item& item, + const handle_t& itf, + const std::string& hostname, + const l2_address_t& client_id, + bool set_broadcast_flag) + : rpc_cmd(item) + , m_itf(itf) + , m_hostname(hostname) + , m_client_id(client_id) + , m_set_broadcast_flag(set_broadcast_flag) +{ +} + +bool +bind_cmd::operator==(const bind_cmd& other) const +{ + return ((m_itf == other.m_itf) && (m_hostname == other.m_hostname)); +} + +rc_t +bind_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.is_add = 1; + payload.client.sw_if_index = m_itf.value(); + payload.client.pid = getpid(); + payload.client.want_dhcp_event = 1; + payload.client.set_broadcast_flag = m_set_broadcast_flag; + + memset(payload.client.hostname, 0, sizeof(payload.client.hostname)); + memcpy(payload.client.hostname, m_hostname.c_str(), + std::min(sizeof(payload.client.hostname), m_hostname.length())); + + memset(payload.client.id, 0, sizeof(payload.client.id)); + payload.client.id[0] = 1; + std::copy_n(begin(m_client_id.bytes), + std::min(sizeof(payload.client.id), m_client_id.bytes.size()), + payload.client.id + 1); + + VAPI_CALL(req.execute()); + + m_hw_item.set(wait()); + + return rc_t::OK; +} + +std::string +bind_cmd::to_string() const +{ + std::ostringstream s; + s << "Dhcp-client-bind: " << m_hw_item.to_string() + << " itf:" << m_itf.to_string() << " hostname:" << m_hostname; + + return (s.str()); +} + +unbind_cmd::unbind_cmd(HW::item& item, + const handle_t& itf, + const std::string& hostname) + : rpc_cmd(item) + , m_itf(itf) + , m_hostname(hostname) +{ +} + +bool +unbind_cmd::operator==(const unbind_cmd& other) const +{ + return ((m_itf == other.m_itf) && (m_hostname == other.m_hostname)); +} + +rc_t +unbind_cmd::issue(connection& con) +{ + msg_t req(con.ctx(), std::ref(*this)); + + auto& payload = req.get_request().get_payload(); + payload.is_add = 0; + payload.client.sw_if_index = m_itf.value(); + payload.client.pid = getpid(); + payload.client.want_dhcp_event = 0; + + memcpy(payload.client.hostname, m_hostname.c_str(), + std::min(sizeof(payload.client.hostname), m_hostname.length())); + + VAPI_CALL(req.execute()); + + wait(); + m_hw_item.set(rc_t::NOOP); + + return rc_t::OK; +} + +std::string +unbind_cmd::to_string() const +{ + std::ostringstream s; + s << "Dhcp-client-unbind: " << m_hw_item.to_string() + << " itf:" << m_itf.to_string() << " hostname:" << m_hostname; + + return (s.str()); +} + +events_cmd::events_cmd(dhcp_client::event_listener& el) + : event_cmd(el.status()) + , m_listener(el) +{ +} + +events_cmd::~events_cmd() +{ + VOM_LOG(log_level_t::INFO) << "DHCP events destroyed"; +} + +bool +events_cmd::operator==(const events_cmd& other) const +{ + return (true); +} + +rc_t +events_cmd::issue(connection& con) +{ + /* + * Set the call back to handle DHCP complete envets. + */ + m_reg.reset(new reg_t(con.ctx(), std::ref(*this))); + + /* + * return in-progress so the command stays in the pending list. + */ + return (rc_t::OK); +} + +void +events_cmd::retire(connection& con) +{ +} + +void +events_cmd::notify() +{ + for (auto& msg : *this) { + auto& payload = msg.get_payload(); + + const dhcp_client::state_t& s = + dhcp_client::state_t::from_vpp(payload.lease.state); + route::prefix_t pfx(payload.lease.is_ipv6, payload.lease.host_address, + payload.lease.mask_width); + std::shared_ptr itf = interface::find(payload.lease.sw_if_index); + + if (itf) { + std::shared_ptr ev = + std::make_shared( + s, itf, from_bytes(0, payload.lease.router_address), pfx, + reinterpret_cast(payload.lease.hostname), + mac_address_t(payload.lease.host_mac)); + m_listener.handle_dhcp_event(ev); + + VOM_LOG(log_level_t::INFO) << "DHCP: " << ev->to_string(); + } else { + VOM_LOG(log_level_t::ERROR) << "DHCP: no interface: " + << payload.lease.sw_if_index; + } + } + + flush(); +} + +std::string +events_cmd::to_string() const +{ + return ("dhcp-events"); +} + +dump_cmd::dump_cmd() +{ +} + +bool +dump_cmd::operator==(const dump_cmd& other) const +{ + return (true); +} + +rc_t +dump_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_cmd::to_string() const +{ + return ("dhcp-client-dump"); +} + +}; // namespace dhcp_client_cmds +}; // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ diff --git a/extras/vom/vom/dhcp_client_cmds.hpp b/extras/vom/vom/dhcp_client_cmds.hpp new file mode 100644 index 00000000000..e7db38f4e3b --- /dev/null +++ b/extras/vom/vom/dhcp_client_cmds.hpp @@ -0,0 +1,208 @@ +/* + * 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_DHCP_CLIENT_CMDS_H__ +#define __VOM_DHCP_CLIENT_CMDS_H__ + +#include "vom/dhcp_client.hpp" +#include "vom/dump_cmd.hpp" +#include "vom/event_cmd.hpp" + +#include +#include + +namespace VOM { +namespace dhcp_client_cmds { + +/** + * A command class that binds the DHCP config to the interface + */ +class bind_cmd : public rpc_cmd, rc_t, vapi::Dhcp_client_config> +{ +public: + /** + * Constructor + */ + bind_cmd(HW::item& item, + const handle_t& itf, + const std::string& hostname, + const l2_address_t& client_id, + bool set_braodcast_flag = false); + + /** + * 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_cmd& i) const; + +private: + /** + * Reference to the HW::item of the interface to bind + */ + const handle_t& m_itf; + + /** + * The DHCP client's hostname + */ + const std::string m_hostname; + + /** + * The DHCP client's ID + */ + const l2_address_t m_client_id; + + /** + * Flag to control the setting the of DHCP discover's broadcast flag + */ + const bool m_set_broadcast_flag; +}; + +/** + * A cmd class that Unbinds Dhcp Config from an interface + */ +class unbind_cmd + : public rpc_cmd, rc_t, vapi::Dhcp_client_config> +{ +public: + /** + * Constructor + */ + unbind_cmd(HW::item& item, + const handle_t& itf, + const std::string& hostname); + + /** + * 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_cmd& i) const; + +private: + /** + * Reference to the HW::item of the interface to unbind + */ + const handle_t& m_itf; + + /** + * The DHCP client's hostname + */ + const std::string m_hostname; +}; + +/** + * A functor class represents our desire to recieve interface events + */ +class events_cmd : public event_cmd +{ +public: + /** + * Constructor + */ + events_cmd(dhcp_client::event_listener& el); + ~events_cmd(); + + /** + * Issue the command to VPP/HW - subscribe to DHCP events + */ + rc_t issue(connection& con); + + /** + * Retire the command - unsubscribe + */ + void retire(connection& con); + /** + * convert to string format for debug purposes + */ + std::string to_string() const; + + /** + * Comparison operator - only used for UT + */ + bool operator==(const events_cmd& i) const; + + /** + * called in the VAPI RX thread when data is available. + */ + void notify(); + +private: + void succeeded() {} + /** + * The listner of this command + */ + dhcp_client::event_listener& m_listener; +}; + +/** + * A cmd class that Dumps all the DHCP clients + */ +class dump_cmd : public VOM::dump_cmd +{ +public: + /** + * Constructor + */ + dump_cmd(); + dump_cmd(const dump_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_cmd& i) const; + +private: + /** + * HW reutrn code + */ + HW::item item; +}; + +}; // namespace dhcp_client_cmds +}; // namespace VOM + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "mozilla") + * End: + */ + +#endif diff --git a/extras/vom/vom/dhcp_config.cpp b/extras/vom/vom/dhcp_config.cpp deleted file mode 100644 index 7d97fa15d6e..00000000000 --- a/extras/vom/vom/dhcp_config.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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 "vom/dhcp_config.hpp" -#include "vom/dhcp_config_cmds.hpp" -#include "vom/singular_db_funcs.hpp" - -namespace VOM { -/** - * A DB of all DHCP configs - */ -singular_db dhcp_config::m_db; - -dhcp_config::event_handler dhcp_config::m_evh; - -dhcp_config::dhcp_config(const interface& itf, - const std::string& hostname, - bool set_broadcast_flag) - : m_itf(itf.singular()) - , m_hostname(hostname) - , m_client_id(l2_address_t::ZERO) - , m_set_broadcast_flag(set_broadcast_flag) - , m_binding(0) -{ -} - -dhcp_config::dhcp_config(const interface& itf, - const std::string& hostname, - const l2_address_t& client_id, - bool set_broadcast_flag) - : m_itf(itf.singular()) - , m_hostname(hostname) - , m_client_id(client_id) - , m_set_broadcast_flag(set_broadcast_flag) - , m_binding(0) -{ -} - -dhcp_config::dhcp_config(const dhcp_config& o) - : m_itf(o.m_itf) - , m_hostname(o.m_hostname) - , m_client_id(o.m_client_id) - , m_set_broadcast_flag(o.m_set_broadcast_flag) - , m_binding(0) -{ -} - -dhcp_config::~dhcp_config() -{ - sweep(); - - // not in the DB anymore. - m_db.release(m_itf->key(), this); -} - -bool -dhcp_config::operator==(const dhcp_config& l) const -{ - return ((key() == l.key()) && (m_hostname == l.m_hostname) && - (m_client_id == l.m_client_id)); -} - -const dhcp_config::key_t& -dhcp_config::key() const -{ - return (m_itf->key()); -} - -void -dhcp_config::sweep() -{ - if (m_binding) { - HW::enqueue( - new dhcp_config_cmds::unbind_cmd(m_binding, m_itf->handle(), m_hostname)); - } - HW::write(); -} - -void -dhcp_config::dump(std::ostream& os) -{ - db_dump(m_db, os); -} - -void -dhcp_config::replay() -{ - if (m_binding) { - HW::enqueue(new dhcp_config_cmds::bind_cmd(m_binding, m_itf->handle(), - m_hostname, m_client_id)); - } -} - -std::string -dhcp_config::to_string() const -{ - std::ostringstream s; - s << "Dhcp-config: " << m_itf->to_string() << " hostname:" << m_hostname - << " client_id:[" << m_client_id << "] " << m_binding.to_string(); - - return (s.str()); -} - -void -dhcp_config::update(const dhcp_config& desired) -{ - /* - * the desired state is always that the interface should be created - */ - if (!m_binding) { - HW::enqueue(new dhcp_config_cmds::bind_cmd(m_binding, m_itf->handle(), - m_hostname, m_client_id)); - } -} - -std::shared_ptr -dhcp_config::find_or_add(const dhcp_config& temp) -{ - return (m_db.find_or_add(temp.m_itf->key(), temp)); -} - -std::shared_ptr -dhcp_config::find(const key_t& k) -{ - return (m_db.find(k)); -} - -std::shared_ptr -dhcp_config::singular() const -{ - return find_or_add(*this); -} - -dhcp_config::event_listener::event_listener() - : m_status(rc_t::NOOP) -{ -} - -HW::item& -dhcp_config::event_listener::status() -{ - return (m_status); -} - -dhcp_config::event_handler::event_handler() -{ - OM::register_listener(this); - inspect::register_handler({ "dhcp" }, "DHCP configurations", this); -} - -void -dhcp_config::event_handler::handle_replay() -{ - m_db.replay(); -} - -void -dhcp_config::event_handler::handle_populate(const client_db::key_t& key) -{ - // FIXME -} - -dependency_t -dhcp_config::event_handler::order() const -{ - return (dependency_t::BINDING); -} - -void -dhcp_config::event_handler::show(std::ostream& os) -{ - db_dump(m_db, os); -} -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "mozilla") - * End: - */ diff --git a/extras/vom/vom/dhcp_config.hpp b/extras/vom/vom/dhcp_config.hpp deleted file mode 100644 index 8ea608d809d..00000000000 --- a/extras/vom/vom/dhcp_config.hpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 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_DHCP_CONFIG_H__ -#define __VOM_DHCP_CONFIG_H__ - -#include "vom/hw.hpp" -#include "vom/inspect.hpp" -#include "vom/interface.hpp" -#include "vom/object_base.hpp" -#include "vom/om.hpp" -#include "vom/singular_db.hpp" - -namespace VOM { -namespace dhcp_config_cmds { -class events_cmd; -}; -/** - * A representation of DHCP client configuration on an interface - */ -class dhcp_config : public object_base -{ -public: - /** - * typedef for the DHCP config key type - */ - typedef interface::key_t key_t; - - /** - * Construct a new object matching the desried state - */ - dhcp_config(const interface& itf, - const std::string& hostname, - bool set_broadcast_flag = true); - - /** - * Construct a new object matching the desried state - */ - dhcp_config(const interface& itf, - const std::string& hostname, - const l2_address_t& client_id, - bool set_broadcast_flag = true); - - /** - * Copy Constructor - */ - dhcp_config(const dhcp_config& o); - - /** - * Destructor - */ - ~dhcp_config(); - - /** - * Comparison operator - for UT - */ - bool operator==(const dhcp_config& d) const; - - /** - * Return the object's key - */ - const key_t& key() const; - - /** - * Return the 'singular' of the DHCP config that matches this object - */ - std::shared_ptr singular() const; - - /** - * convert to string format for debug purposes - */ - std::string to_string() const; - - /** - * Dump all DHCP configs into the stream provided - */ - static void dump(std::ostream& os); - - /** - * Find a DHCP config from its key - */ - static std::shared_ptr find(const key_t& k); - - /** - * A class that listens to DHCP Events - */ - class event_listener - { - public: - /** - * Constructor - */ - event_listener(); - - /** - * listener's virtual function invoked when a DHCP event is - * available to read - */ - virtual void handle_dhcp_event(dhcp_config_cmds::events_cmd* cmd) = 0; - - /** - * Return the HW::item associated with this command - */ - HW::item& status(); - - protected: - /** - * The HW::item associated with this command - */ - HW::item m_status; - }; - -private: - /** - * Class definition for listeners to OM events - */ - class event_handler : public OM::listener, public inspect::command_handler - { - public: - event_handler(); - virtual ~event_handler() = default; - - /** - * Handle a populate event - */ - void handle_populate(const client_db::key_t& key); - - /** - * Handle a replay event - */ - void handle_replay(); - - /** - * Show the object in the Singular DB - */ - void show(std::ostream& os); - - /** - * Get the sortable Id of the listener - */ - dependency_t order() const; - }; - - /** - * event_handler to register with OM - */ - static event_handler m_evh; - - /** - * Enquue commonds to the VPP command Q for the update - */ - void update(const dhcp_config& obj); - - /** - * Find or add DHCP config to the OM - */ - static std::shared_ptr find_or_add(const dhcp_config& temp); - - /* - * It's the OM class that calls singular() - */ - friend class OM; - - /** - * It's the singular_db class that calls replay() - */ - friend class singular_db; - - /** - * Sweep/reap the object if still stale - */ - void sweep(void); - - /** - * replay the object to create it in hardware - */ - void replay(void); - - /** - * A reference counting pointer to the interface on which DHCP config - * resides. By holding the reference here, we can guarantee that - * this object will outlive the interface - */ - const std::shared_ptr m_itf; - - /** - * The hostname in the DHCP configuration - */ - const std::string m_hostname; - - /** - * The option-61 client_id in the DHCP configuration - */ - const l2_address_t m_client_id; - - /** - * Flag to control the setting the of DHCP discover's broadcast flag - */ - const bool m_set_broadcast_flag; - - /** - * HW configuration for the binding. The bool representing the - * do/don't bind. - */ - HW::item m_binding; - - /** - * A map of all Dhcp configs keyed against the interface. - */ - static singular_db m_db; -}; -}; - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "mozilla") - * End: - */ - -#endif diff --git a/extras/vom/vom/dhcp_config_cmds.cpp b/extras/vom/vom/dhcp_config_cmds.cpp deleted file mode 100644 index 76ce58b6b92..00000000000 --- a/extras/vom/vom/dhcp_config_cmds.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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 "vom/dhcp_config_cmds.hpp" - -DEFINE_VAPI_MSG_IDS_DHCP_API_JSON; - -namespace VOM { -namespace dhcp_config_cmds { - -bind_cmd::bind_cmd(HW::item& item, - const handle_t& itf, - const std::string& hostname, - const l2_address_t& client_id, - bool set_broadcast_flag) - : rpc_cmd(item) - , m_itf(itf) - , m_hostname(hostname) - , m_client_id(client_id) - , m_set_broadcast_flag(set_broadcast_flag) -{ -} - -bool -bind_cmd::operator==(const bind_cmd& other) const -{ - return ((m_itf == other.m_itf) && (m_hostname == other.m_hostname)); -} - -rc_t -bind_cmd::issue(connection& con) -{ - msg_t req(con.ctx(), std::ref(*this)); - - auto& payload = req.get_request().get_payload(); - payload.sw_if_index = m_itf.value(); - payload.is_add = 1; - payload.pid = getpid(); - payload.want_dhcp_event = 1; - payload.set_broadcast_flag = m_set_broadcast_flag; - - memset(payload.hostname, 0, sizeof(payload.hostname)); - memcpy(payload.hostname, m_hostname.c_str(), - std::min(sizeof(payload.hostname), m_hostname.length())); - - memset(payload.client_id, 0, sizeof(payload.client_id)); - payload.client_id[0] = 1; - std::copy_n(begin(m_client_id.bytes), - std::min(sizeof(payload.client_id), m_client_id.bytes.size()), - payload.client_id + 1); - - VAPI_CALL(req.execute()); - - m_hw_item.set(wait()); - - return rc_t::OK; -} - -std::string -bind_cmd::to_string() const -{ - std::ostringstream s; - s << "Dhcp-config-bind: " << m_hw_item.to_string() - << " itf:" << m_itf.to_string() << " hostname:" << m_hostname; - - return (s.str()); -} - -unbind_cmd::unbind_cmd(HW::item& item, - const handle_t& itf, - const std::string& hostname) - : rpc_cmd(item) - , m_itf(itf) - , m_hostname(hostname) -{ -} - -bool -unbind_cmd::operator==(const unbind_cmd& other) const -{ - return ((m_itf == other.m_itf) && (m_hostname == other.m_hostname)); -} - -rc_t -unbind_cmd::issue(connection& con) -{ - msg_t req(con.ctx(), std::ref(*this)); - - auto& payload = req.get_request().get_payload(); - payload.sw_if_index = m_itf.value(); - payload.is_add = 0; - payload.pid = getpid(); - payload.want_dhcp_event = 0; - - memcpy(payload.hostname, m_hostname.c_str(), - std::min(sizeof(payload.hostname), m_hostname.length())); - - VAPI_CALL(req.execute()); - - wait(); - m_hw_item.set(rc_t::NOOP); - - return rc_t::OK; -} - -std::string -unbind_cmd::to_string() const -{ - std::ostringstream s; - s << "Dhcp-config-unbind: " << m_hw_item.to_string() - << " itf:" << m_itf.to_string() << " hostname:" << m_hostname; - - return (s.str()); -} - -events_cmd::events_cmd(dhcp_config::event_listener& el) - : event_cmd(el.status()) - , m_listener(el) -{ -} - -bool -events_cmd::operator==(const events_cmd& other) const -{ - return (true); -} - -rc_t -events_cmd::issue(connection& con) -{ - /* - * Set the call back to handle DHCP complete envets. - */ - m_reg.reset(new reg_t(con.ctx(), std::ref(*this))); - - /* - * return in-progress so the command stays in the pending list. - */ - return (rc_t::OK); -} - -void -events_cmd::retire(connection& con) -{ -} - -void -events_cmd::notify() -{ - m_listener.handle_dhcp_event(this); -} - -std::string -events_cmd::to_string() const -{ - return ("dhcp-events"); -} -} -}; -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "mozilla") - * End: - */ diff --git a/extras/vom/vom/dhcp_config_cmds.hpp b/extras/vom/vom/dhcp_config_cmds.hpp deleted file mode 100644 index 726ff992577..00000000000 --- a/extras/vom/vom/dhcp_config_cmds.hpp +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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_DHCP_CONFIG_CMDS_H__ -#define __VOM_DHCP_CONFIG_CMDS_H__ - -#include "vom/dhcp_config.hpp" -#include "vom/event_cmd.hpp" - -#include -#include - -namespace VOM { -namespace dhcp_config_cmds { - -/** - * A command class that binds the DHCP config to the interface - */ -class bind_cmd : public rpc_cmd, rc_t, vapi::Dhcp_client_config> -{ -public: - /** - * Constructor - */ - bind_cmd(HW::item& item, - const handle_t& itf, - const std::string& hostname, - const l2_address_t& client_id, - bool set_braodcast_flag = false); - - /** - * 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_cmd& i) const; - -private: - /** - * Reference to the HW::item of the interface to bind - */ - const handle_t& m_itf; - - /** - * The DHCP client's hostname - */ - const std::string m_hostname; - - /** - * The DHCP client's ID - */ - const l2_address_t m_client_id; - - /** - * Flag to control the setting the of DHCP discover's broadcast flag - */ - const bool m_set_broadcast_flag; -}; - -/** - * A cmd class that Unbinds Dhcp Config from an interface - */ -class unbind_cmd - : public rpc_cmd, rc_t, vapi::Dhcp_client_config> -{ -public: - /** - * Constructor - */ - unbind_cmd(HW::item& item, - const handle_t& itf, - const std::string& hostname); - - /** - * 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_cmd& i) const; - -private: - /** - * Reference to the HW::item of the interface to unbind - */ - const handle_t& m_itf; - - /** - * The DHCP client's hostname - */ - const std::string m_hostname; -}; - -/** - * A functor class represents our desire to recieve interface events - */ -class events_cmd : public event_cmd -{ -public: - /** - * Constructor - */ - events_cmd(dhcp_config::event_listener& el); - - /** - * Issue the command to VPP/HW - subscribe to DHCP events - */ - rc_t issue(connection& con); - - /** - * Retire the command - unsubscribe - */ - void retire(connection& con); - /** - * convert to string format for debug purposes - */ - std::string to_string() const; - - /** - * Comparison operator - only used for UT - */ - bool operator==(const events_cmd& i) const; - - /** - * called in the VAPI RX thread when data is available. - */ - void notify(); - -private: - void succeeded() {} - /** - * The listner of this command - */ - dhcp_config::event_listener& m_listener; -}; -}; -}; - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "mozilla") - * End: - */ - -#endif diff --git a/extras/vom/vom/l3_binding.cpp b/extras/vom/vom/l3_binding.cpp index 13bc1ffd575..6b8d36209a7 100644 --- a/extras/vom/vom/l3_binding.cpp +++ b/extras/vom/vom/l3_binding.cpp @@ -158,35 +158,6 @@ operator<<(std::ostream& os, const l3_binding::key_t& key) return (os); } -std::deque> -l3_binding::find(const interface& i) -{ - /* - * Loop throught the entire map looking for matching interface. - * not the most efficient algorithm, but it will do for now. The - * number of L3 configs is low and this is only called during bootup - */ - std::deque> l3s; - - auto it = m_db.begin(); - - while (it != m_db.end()) { - /* - * The key in the DB is a pair of the interface's name and prefix. - * If the keys match, save the L3-config - */ - auto key = it->first; - - if (i.key() == key.first) { - l3s.push_back(it->second.lock()); - } - - ++it; - } - - return (l3s); -} - l3_binding::event_handler::event_handler() { OM::register_listener(this); diff --git a/extras/vom/vom/l3_binding.hpp b/extras/vom/vom/l3_binding.hpp index 0177e56ea2b..a2a46263dbd 100644 --- a/extras/vom/vom/l3_binding.hpp +++ b/extras/vom/vom/l3_binding.hpp @@ -94,11 +94,6 @@ public: */ static void dump(std::ostream& os); - /** - * Find all bindings in the DB for the interface passed - */ - static std::deque> find(const interface& i); - /** * Find a binding from its key */ diff --git a/extras/vom/vom/neighbour_cmds.cpp b/extras/vom/vom/neighbour_cmds.cpp index 2f3c200d5fb..63534f3dd94 100644 --- a/extras/vom/vom/neighbour_cmds.cpp +++ b/extras/vom/vom/neighbour_cmds.cpp @@ -151,7 +151,11 @@ dump_cmd::issue(connection& con) std::string dump_cmd::to_string() const { - return ("neighbour-dump"); + std::ostringstream s; + + s << "neighbour-dump: " << m_itf.to_string() << " " << m_proto.to_string(); + + return (s.str()); } } // namespace neighbour_cmds } // namespace vom -- cgit 1.2.3-korg