VPP Object Model (VOM)
[vpp.git] / src / vpp-api / vom / acl_list.hpp
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #ifndef __VOM_ACL_LIST_H__
17 #define __VOM_ACL_LIST_H__
18
19 #include <set>
20
21 #include "vom/acl_l2_rule.hpp"
22 #include "vom/acl_l3_rule.hpp"
23 #include "vom/acl_types.hpp"
24 #include "vom/dump_cmd.hpp"
25 #include "vom/hw.hpp"
26 #include "vom/inspect.hpp"
27 #include "vom/om.hpp"
28 #include "vom/rpc_cmd.hpp"
29 #include "vom/singular_db.hpp"
30
31 #include <vapi/acl.api.vapi.hpp>
32
33 namespace VOM {
34 namespace ACL {
35 /**
36  * An ACL list comprises a set of match actions rules to be applied to
37  * packets.
38  * A list is bound to a given interface.
39  */
40 template <typename RULE, typename UPDATE, typename DELETE, typename DUMP>
41 class list : public object_base
42 {
43 public:
44   /**
45    * The KEY can be used to uniquely identify the ACL.
46    * (other choices for keys, like the summation of the properties
47    * of the rules, are rather too cumbersome to use
48    */
49   typedef std::string key_t;
50
51   /**
52    * The rule container type
53    */
54   typedef std::multiset<RULE> rules_t;
55
56   /**
57    * Construct a new object matching the desried state
58    */
59   list(const key_t& key)
60     : m_key(key)
61   {
62   }
63
64   list(const handle_t& hdl, const key_t& key)
65     : m_hdl(hdl)
66     , m_key(key)
67   {
68   }
69
70   list(const key_t& key, const rules_t& rules)
71     : m_key(key)
72     , m_rules(rules)
73   {
74     m_evh.order();
75   }
76
77   /**
78    * Copy Constructor
79    */
80   list(const list& o)
81     : m_hdl(o.m_hdl)
82     , m_key(o.m_key)
83     , m_rules(o.m_rules)
84   {
85   }
86
87   /**
88    * Destructor
89    */
90   ~list()
91   {
92     sweep();
93     m_db.release(m_key, this);
94   }
95
96   /**
97    * Return the 'sigular instance' of the ACL that matches this object
98    */
99   std::shared_ptr<list> singular() const { return find_or_add(*this); }
100
101   /**
102    * Dump all ACLs into the stream provided
103    */
104   static void dump(std::ostream& os) { m_db.dump(os); }
105
106   /**
107    * convert to string format for debug purposes
108    */
109   std::string to_string() const
110   {
111     std::ostringstream s;
112     s << "acl-list:[" << m_key << " " << m_hdl.to_string() << " rules:[";
113
114     for (auto rule : m_rules) {
115       s << rule.to_string() << " ";
116     }
117
118     s << "]]";
119
120     return (s.str());
121   }
122
123   /**
124    * Insert priority sorted a rule into the list
125    */
126   void insert(const RULE& rule) { m_rules.insert(rule); }
127
128   /**
129    * Remove a rule from the list
130    */
131   void remove(const RULE& rule) { m_rules.erase(rule); }
132
133   /**
134    * Return the VPP assign handle
135    */
136   const handle_t& handle() const { return m_hdl.data(); }
137
138   /**
139    * A command class that Create the list
140    */
141   class update_cmd
142     : public rpc_cmd<HW::item<handle_t>, HW::item<handle_t>, UPDATE>
143   {
144   public:
145     /**
146      * Constructor
147      */
148     update_cmd(HW::item<handle_t>& item, const key_t& key, const rules_t& rules)
149       : rpc_cmd<HW::item<handle_t>, HW::item<handle_t>, UPDATE>(item)
150       , m_key(key)
151       , m_rules(rules)
152     {
153     }
154
155     /**
156      * Issue the command to VPP/HW
157      */
158     rc_t issue(connection& con);
159
160     /**
161      * convert to string format for debug purposes
162      */
163     std::string to_string() const
164     {
165       std::ostringstream s;
166       s << "ACL-list-update: " << this->item().to_string();
167
168       return (s.str());
169     }
170
171     /**
172      * Comparison operator - only used for UT
173      */
174     bool operator==(const update_cmd& other) const
175     {
176       return ((m_key == other.m_key) && (m_rules == other.m_rules));
177     }
178
179     void complete()
180     {
181       std::shared_ptr<list> sp = find(m_key);
182       if (sp && this->item()) {
183         list::add(this->item().data(), sp);
184       }
185     }
186
187     void succeeded()
188     {
189       rpc_cmd<HW::item<handle_t>, HW::item<handle_t>, UPDATE>::succeeded();
190       complete();
191     }
192
193     /**
194      * A callback function for handling ACL creates
195      */
196     virtual vapi_error_e operator()(UPDATE& reply)
197     {
198       int acl_index = reply.get_response().get_payload().acl_index;
199       int retval = reply.get_response().get_payload().retval;
200
201       VOM_LOG(log_level_t::DEBUG) << this->to_string() << " " << retval;
202
203       HW::item<handle_t> res(acl_index, rc_t::from_vpp_retval(retval));
204
205       this->fulfill(res);
206
207       return (VAPI_OK);
208     }
209
210   private:
211     /**
212      * The key.
213      */
214     const key_t& m_key;
215
216     /**
217      * The rules
218      */
219     const rules_t& m_rules;
220   };
221
222   /**
223    * A cmd class that Deletes an ACL
224    */
225   class delete_cmd : public rpc_cmd<HW::item<handle_t>, rc_t, DELETE>
226   {
227   public:
228     /**
229      * Constructor
230      */
231     delete_cmd(HW::item<handle_t>& item)
232       : rpc_cmd<HW::item<handle_t>, rc_t, DELETE>(item)
233     {
234     }
235
236     /**
237      * Issue the command to VPP/HW
238      */
239     rc_t issue(connection& con) { return (rc_t::INVALID); }
240
241     /**
242      * convert to string format for debug purposes
243      */
244     std::string to_string() const
245     {
246       std::ostringstream s;
247       s << "ACL-list-delete: " << this->item().to_string();
248
249       return (s.str());
250     }
251
252     /**
253      * Comparison operator - only used for UT
254      */
255     bool operator==(const delete_cmd& other) const
256     {
257       return (this->item().data() == other.item().data());
258     }
259   };
260
261   /**
262    * A cmd class that Dumps all the ACLs
263    */
264   class dump_cmd : public VOM::dump_cmd<DUMP>
265   {
266   public:
267     /**
268      * Constructor
269      */
270     dump_cmd() = default;
271     dump_cmd(const dump_cmd& d) = default;
272
273     /**
274      * Issue the command to VPP/HW
275      */
276     rc_t issue(connection& con) { return rc_t::INVALID; }
277
278     /**
279      * convert to string format for debug purposes
280      */
281     std::string to_string() const { return ("acl-list-dump"); }
282
283   private:
284     /**
285      * HW reutrn code
286      */
287     HW::item<bool> item;
288   };
289
290   static std::shared_ptr<list> find(const handle_t& handle)
291   {
292     return (m_hdl_db[handle].lock());
293   }
294
295   static std::shared_ptr<list> find(const key_t& key)
296   {
297     return (m_db.find(key));
298   }
299
300   static void add(const handle_t& handle, std::shared_ptr<list> sp)
301   {
302     m_hdl_db[handle] = sp;
303   }
304
305   static void remove(const handle_t& handle) { m_hdl_db.erase(handle); }
306
307 private:
308   /**
309    * Class definition for listeners to OM events
310    */
311   class event_handler : public OM::listener, public inspect::command_handler
312   {
313   public:
314     event_handler()
315     {
316       OM::register_listener(this);
317       inspect::register_handler({ "acl" }, "ACL lists", this);
318     }
319     virtual ~event_handler() = default;
320
321     /**
322      * Handle a populate event
323      */
324     void handle_populate(const client_db::key_t& key);
325
326     /**
327      * Handle a replay event
328      */
329     void handle_replay() { m_db.replay(); }
330
331     /**
332      * Show the object in the Singular DB
333      */
334     void show(std::ostream& os) { m_db.dump(os); }
335
336     /**
337      * Get the sortable Id of the listener
338      */
339     dependency_t order() const { return (dependency_t::ACL); }
340   };
341
342   /**
343    * event_handler to register with OM
344    */
345   static event_handler m_evh;
346
347   /**
348    * Enquue commonds to the VPP command Q for the update
349    */
350   void update(const list& obj)
351   {
352     /*
353      * always update the instance with the latest rule set
354      */
355     if (!m_hdl || obj.m_rules != m_rules) {
356       HW::enqueue(new update_cmd(m_hdl, m_key, m_rules));
357     }
358     /*
359      * We don't, can't, read the priority from VPP,
360      * so the is equals check above does not include the priorty.
361      * but we save it now.
362      */
363     m_rules = obj.m_rules;
364   }
365
366   /**
367    * HW assigned handle
368    */
369   HW::item<handle_t> m_hdl;
370
371   /**
372    * Find or add the sigular instance in the DB
373    */
374   static std::shared_ptr<list> find_or_add(const list& temp)
375   {
376     return (m_db.find_or_add(temp.m_key, temp));
377   }
378
379   /*
380    * It's the VOM::OM class that updates call update
381    */
382   friend class VOM::OM;
383
384   /**
385    * It's the VOM::singular_db class that calls replay()
386    */
387   friend class singular_db<key_t, list>;
388
389   /**
390    * Sweep/reap the object if still stale
391    */
392   void sweep(void)
393   {
394     if (m_hdl) {
395       HW::enqueue(new delete_cmd(m_hdl));
396     }
397     HW::write();
398   }
399
400   /**
401    * Replay the objects state to HW
402    */
403   void replay(void)
404   {
405     if (m_hdl) {
406       HW::enqueue(new update_cmd(m_hdl, m_key, m_rules));
407     }
408   }
409
410   /**
411    * A map of all ACL's against the client's key
412    */
413   static singular_db<key_t, list> m_db;
414
415   /**
416    * A map of all ACLs keyed against VPP's handle
417    */
418   static std::map<const handle_t, std::weak_ptr<list>> m_hdl_db;
419
420   /**
421    * The Key is a user defined identifer for this ACL
422    */
423   const key_t m_key;
424
425   /**
426    * A sorted list of the rules
427    */
428   rules_t m_rules;
429 };
430
431 /**
432  * Typedef the L3 ACL type
433  */
434 typedef list<l3_rule, vapi::Acl_add_replace, vapi::Acl_del, vapi::Acl_dump>
435   l3_list;
436
437 /**
438  * Typedef the L2 ACL type
439  */
440 typedef list<l2_rule,
441              vapi::Macip_acl_add,
442              vapi::Macip_acl_del,
443              vapi::Macip_acl_dump>
444   l2_list;
445
446 /**
447  * Definition of the static singular_db for ACL Lists
448  */
449 template <typename RULE, typename UPDATE, typename DELETE, typename DUMP>
450 singular_db<typename ACL::list<RULE, UPDATE, DELETE, DUMP>::key_t,
451             ACL::list<RULE, UPDATE, DELETE, DUMP>>
452   list<RULE, UPDATE, DELETE, DUMP>::m_db;
453
454 /**
455  * Definition of the static per-handle DB for ACL Lists
456  */
457 template <typename RULE, typename UPDATE, typename DELETE, typename DUMP>
458 std::map<const handle_t, std::weak_ptr<ACL::list<RULE, UPDATE, DELETE, DUMP>>>
459   list<RULE, UPDATE, DELETE, DUMP>::m_hdl_db;
460
461 template <typename RULE, typename UPDATE, typename DELETE, typename DUMP>
462 typename ACL::list<RULE, UPDATE, DELETE, DUMP>::event_handler
463   list<RULE, UPDATE, DELETE, DUMP>::m_evh;
464 };
465 };
466
467 /*
468  * fd.io coding-style-patch-verification: ON
469  *
470  * Local Variables:
471  * eval: (c-set-style "mozilla")
472  * End:
473  */
474
475 #endif