diff options
author | Damjan Marion <damarion@cisco.com> | 2018-04-25 19:11:15 +0200 |
---|---|---|
committer | Neale Ranns <nranns@cisco.com> | 2018-04-27 11:35:07 +0000 |
commit | 164e5f8c63652028ecb9c3570e1ea8618b163071 (patch) | |
tree | 7423f5abbc61b761df9a679c7974f17613736020 /src/vpp-api/vom/om.hpp | |
parent | aa682a39b76ee043f65313f23e134bf18fe7a47e (diff) |
Move VOM to extras/vom
Change-Id: Iea174f03dfba3bd06024db0f0cc373532300dcae
Signed-off-by: Damjan Marion <damarion@cisco.com>
Diffstat (limited to 'src/vpp-api/vom/om.hpp')
-rw-r--r-- | src/vpp-api/vom/om.hpp | 356 |
1 files changed, 0 insertions, 356 deletions
diff --git a/src/vpp-api/vom/om.hpp b/src/vpp-api/vom/om.hpp deleted file mode 100644 index e68d5ea0017..00000000000 --- a/src/vpp-api/vom/om.hpp +++ /dev/null @@ -1,356 +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_OM_H__ -#define __VOM_OM_H__ - -#include <algorithm> -#include <memory> -#include <set> - -#include "vom/client_db.hpp" -#include "vom/hw.hpp" - -/** - -The VPP Object Model (VOM) library. - -Before we begin, a glossary of terms: - - Agent or client: A user mode process that links to and uses the VOM library - to programme VPP - - VPP: A running instance of VPP - - High Availability (HA): Scenarios where the client and/or VPP restart with - minimal service interruption. - - CReate, Update, Delete (CRUD): An API style where the producer issues - notifications to changes to objects - -The VOM is a C++ library that models entities in VPP as C++ classes. The - relationships between VOM objects and VPP entities is not always 1:1. Some - effort has been made to construct a higher level, more abstract API to VPP - programming*. -The client programming model is simple (or at least I intended it to be..). The -client deals in ‘desired’ state, that is, it expresses the objects it wants to -exists (in VPP) and the properties that the object should have, i.e**; - Interface af1(“my-af-packet-1”, AFPACKET, admin::UP); -Then the client ‘writes’ this object into the ‘model’ - OM::write(“clients-thing-1”, af1); - -“clients-thing-1” is a description of the entity within the client’s domain that -‘owns’ (or has locked or has a reference to) the VOM object. There can be many -owners of each VOM object. It will be the last owner’s update that will be -programmed in VPP. This model means that the client is not burdened with -maintaining which of its objects have created which VOM objects. If the client -is itself driven by a CRUD API, then create notifications are implemented as - above. Update notifications add two extra statements; - OM::mark(“clients-thing-1”); - … do writes …. - OM::sweep(“clients-thing-1”); -These ‘mark’ and ‘sweep’ statements are indications to OM that firstly, indicate -that all the objects owned by “clients-thing-1” are now stale, i.e that the -client may no longer need them. If one of the subsequent writes should update a -stale object, then it is no longer stale. The sweep statement will ‘remove’ all -the remaining stale objects. In this model, the client does not need to maintain -the mapping of VOM objects to its own objects – it can simply express what it -needs now. -The delete notification is simply: - OM::remove(“clients-thing-1”); -Which will remove all the objects in VOM that are owned by “clients-thing-1”. -Where ‘remove’ in this sense means unlock and unreference, the VOM object, and -VPP state, will only be truly removed once there are no more owners. This is -equivalent to a mark & sweep with no intermediate writes. - -To provide this client side model the VOM is a stateful library, meaning that -for each entity it creates in VPP, VOM maintains its own representation of that -object. VOM can therefore be memory hungry. The desired state is expressed by -the client, the ‘actual’ state is maintained by VOM. VOM will consolidate the -two states when the client writes to the OM and thus issue VPP only the changes -required. - -The concepts of ownership and statefulness also allow the support for HA -scenarios. -VPP restart: When VPP restarts, VOM will reconnect and ‘replay’ its state, in -dependency order, to VPP. The client does not need to regenerate its desired -state. -Client restart: when the client restarts, VOM will read/dump the current state -of all VPP objects and store them in the OM owned by the special owner “boot”. -As the client reprogrammes its desired state, objects will become owned by both -the boot process and the client. At the point in time, as determined by the -client, all stale state, that owned only by boot, can be purged. Hence the -system reaches the correct final state, with no interruption to VPP forwarding. - - -Basic Design: - -Each object in VOM (i.e. an interface, route, bridge-domain, etc) is stored in a -per-type object database, with an object-type specific key. This ‘singular’ DB -has a value-type of a weak pointer to the object. I use the term ‘singular’ to -refer to the instance of the object stored in these databases, to be distinct -from the instances the client constructs to represent desired state. -The ‘client’ DB maintains the mapping of owner to object. The value type of the -client DB is a shared pointer to the singular instance of the owned object. -Once all the owners are gone, and all the shared pointers are destroyed, the -singular instance is also destroyed. - -Each VOM object has some basic behaviour: - update: issue to VPP an update to this object’s state. This could include the - create - sweep: delete the VPP entity – called when the object is destroyed. - replay: issue to VPP all the commands needed to re-programme (VPP restart HA - scenario) - populate: read state from VPP and add it to the OM (client restart HA -scenario) - -The object code is boiler-plate, in some cases (like the ACLs) even template. -The objects are purposefully left as simple, functionality free as possible. - -Communication with VPP is through a ‘queue’ of ‘commands’. A command is -essentially an object wrapper around a VPP binary API call (although we do use -the VAPI C++ bindings too). Commands come in three flavours: - RPC: do this; done. - DUMP: give me all of these things; here you go - EVENT; tell me about these events; here’s one …. Here’s one…. Oh here’s - another….. etc. - -RPC and DUMP commands are handled synchronously. Therefore on return from -OM::write(…) VPP has been issued with the request and responded. EVENTs are -asynchronous and will be delivered to the listeners in a different thread – so -beware!! - -* As such VOM provides some level of insulation to the changes to the VPP - binary API. -** some of the type names are shorten for brevity’s sake. - -*/ -namespace VOM { -/** - * The interface to writing objects into VPP OM. - */ -class OM -{ -public: - /** - * A class providing the RAII pattern for mark and sweep - */ - class mark_n_sweep - { - public: - /** - * Constructor - will call mark on the key - */ - mark_n_sweep(const client_db::key_t& key); - - /** - * Destructor - will call sweep on the key - */ - ~mark_n_sweep(); - - private: - /** - * no copies - */ - mark_n_sweep(const mark_n_sweep& ms) = delete; - - /** - * The client whose state we are guarding. - */ - client_db::key_t m_key; - }; - - /** - * Init - */ - static void init(); - - /** - * populate the OM with state read from HW. - */ - static void populate(const client_db::key_t& key); - - /** - * Mark all state owned by this key as stale - */ - static void mark(const client_db::key_t& key); - - /** - * Sweep all the key's objects that are stale - */ - static void sweep(const client_db::key_t& key); - - /** - * Replay all of the objects to HW. - */ - static void replay(void); - - /** - * Make the State in VPP reflect the expressed desired state. - * But don't call the HW - use this whilst processing dumped - * data from HW - */ - template <typename OBJ> - static rc_t commit(const client_db::key_t& key, const OBJ& obj) - { - rc_t rc = rc_t::OK; - - HW::disable(); - rc = OM::write(key, obj); - HW::enable(); - - return (rc); - } - - /** - * Make the State in VPP reflect the expressed desired state. - * After processing all the objects in the queue, in FIFO order, - * any remaining state owned by the client_db::key_t is purged. - * This is a template function so the object's update() function is - * always called with the derived type. - */ - template <typename OBJ> - static rc_t write(const client_db::key_t& key, const OBJ& obj) - { - rc_t rc = rc_t::OK; - - /* - * Find the singular instance another owner may have created. - * this always returns something. - */ - std::shared_ptr<OBJ> inst = obj.singular(); - - /* - * Update the existing object with the new desired state - */ - inst->update(obj); - - /* - * Find if the object already stored on behalf of this key. - * and mark them stale - */ - object_ref_list& objs = m_db->find(key); - - /* - * Iterate through this list to find a matchin' object - * to the one requested. - */ - auto match_ptr = [inst](const object_ref& oref) { - return (inst == oref.obj()); - }; - auto it = std::find_if(objs.begin(), objs.end(), match_ptr); - - if (it != objs.end()) { - /* - * yes, this key already owns this object. - */ - it->clear(); - } else { - /* - * Add the singular instance to the owners list - */ - objs.insert(object_ref(inst)); - } - - return (HW::write()); - } - - /** - * Remove all object in the OM referenced by the key - */ - static void remove(const client_db::key_t& key); - - /** - * Print each of the object in the DB into the stream provided - */ - static void dump(const client_db::key_t& key, std::ostream& os); - - /** - * Print each of the KEYS - */ - static void dump(std::ostream& os); - - /** - * Class definition for listeners to OM events - */ - class listener - { - public: - listener() = default; - virtual ~listener() = default; - - /** - * Handle a populate event - */ - virtual void handle_populate(const client_db::key_t& key) = 0; - - /** - * Handle a replay event - */ - virtual void handle_replay() = 0; - - /** - * Get the sortable Id of the listener - */ - virtual dependency_t order() const = 0; - - /** - * less than operator for set sorting - */ - bool operator<(const listener& listener) const - { - return (order() < listener.order()); - } - }; - - /** - * Register a listener of events - */ - static bool register_listener(listener* listener); - -private: - /** - * Database of object state created for each key - */ - static client_db* m_db; - - /** - * Comparator to keep the pointers to listeners in sorted order - */ - struct listener_comparator_t - { - bool operator()(const listener* l1, const listener* l2) const - { - return (l1->order() < l2->order()); - } - }; - - /** - * convenient typedef for the sorted set of listeners - */ - typedef std::multiset<listener*, listener_comparator_t> listener_list; - - /** - * The listeners for events - */ - static std::unique_ptr<listener_list> m_listeners; -}; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "mozilla") - * End: - */ - -#endif |