FD.io VPP  v19.04-6-g6f05f72
Vector Packet Processing
vapi.hpp
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17 
18 #ifndef vapi_hpp_included
19 #define vapi_hpp_included
20 
21 #include <cstddef>
22 #include <vector>
23 #include <mutex>
24 #include <queue>
25 #include <cassert>
26 #include <functional>
27 #include <algorithm>
28 #include <atomic>
29 #include <vppinfra/types.h>
30 #include <vapi/vapi.h>
31 #include <vapi/vapi_internal.h>
32 #include <vapi/vapi_dbg.h>
33 #include <vapi/vpe.api.vapi.h>
34 
35 #if VAPI_CPP_DEBUG_LEAKS
36 #include <unordered_set>
37 #endif
38 
39 /**
40  * @file
41  * @brief C++ VPP API
42  */
43 
44 namespace vapi
45 {
46 
47 class Connection;
48 
49 template <typename Req, typename Resp, typename... Args> class Request;
50 template <typename M> class Msg;
51 template <typename M> void vapi_swap_to_be (M *msg);
52 template <typename M> void vapi_swap_to_host (M *msg);
53 template <typename M, typename... Args>
54 M *vapi_alloc (Connection &con, Args...);
55 template <typename M> vapi_msg_id_t vapi_get_msg_id_t ();
56 template <typename M> class Event_registration;
57 
58 class Unexpected_msg_id_exception : public std::exception
59 {
60 public:
61  virtual const char *what () const throw ()
62  {
63  return "unexpected message id";
64  }
65 };
66 
67 class Msg_not_available_exception : public std::exception
68 {
69 public:
70  virtual const char *what () const throw ()
71  {
72  return "message unavailable";
73  }
74 };
75 
76 typedef enum {
77  /** response not ready yet */
79 
80  /** response to request is ready */
82 
83  /** no response to request (will never come) */
86 
87 /**
88  * Class representing common functionality of a request - response state
89  * and context
90  */
92 {
93 public:
94  virtual ~Common_req (){};
95 
97  {
98  return con;
99  };
100 
101  vapi_response_state_e get_response_state (void) const
102  {
103  return response_state;
104  }
105 
106 private:
107  Connection &con;
108  Common_req (Connection &con)
109  : con (con), context{0}, response_state{RESPONSE_NOT_READY}
110  {
111  }
112 
113  void set_response_state (vapi_response_state_e state)
114  {
115  response_state = state;
116  }
117 
118  virtual std::tuple<vapi_error_e, bool> assign_response (vapi_msg_id_t id,
119  void *shm_data) = 0;
120 
121  void set_context (u32 context)
122  {
123  this->context = context;
124  }
125 
126  u32 get_context ()
127  {
128  return context;
129  }
130 
131  u32 context;
132  vapi_response_state_e response_state;
133 
134  friend class Connection;
135 
136  template <typename M> friend class Msg;
137 
138  template <typename Req, typename Resp, typename... Args>
139  friend class Request;
140 
141  template <typename Req, typename Resp, typename... Args> friend class Dump;
142 
143  template <typename M> friend class Event_registration;
144 };
145 
146 /**
147  * Class representing a connection to VPP
148  *
149  * After creating a Connection object, call connect() to actually connect
150  * to VPP. Use is_msg_available to discover whether a specific message is known
151  * and supported by the VPP connected to.
152  */
154 {
155 public:
156  Connection (void) : vapi_ctx{0}, event_count{0}
157  {
158 
159  vapi_error_e rv = VAPI_OK;
160  if (!vapi_ctx)
161  {
162  if (VAPI_OK != (rv = vapi_ctx_alloc (&vapi_ctx)))
163  {
164  throw std::bad_alloc ();
165  }
166  }
167  events.reserve (vapi_get_message_count () + 1);
168  }
169 
170  Connection (const Connection &) = delete;
171 
172  ~Connection (void)
173  {
174  vapi_ctx_free (vapi_ctx);
175 #if VAPI_CPP_DEBUG_LEAKS
176  for (auto x : shm_data_set)
177  {
178  printf ("Leaked shm_data@%p!\n", x);
179  }
180 #endif
181  }
182 
183  /**
184  * @brief check if message identified by it's message id is known by the
185  * vpp to which the connection is open
186  */
188  {
189  return vapi_is_msg_available (vapi_ctx, type);
190  }
191 
192  /**
193  * @brief connect to vpp
194  *
195  * @param name application name
196  * @param chroot_prefix shared memory prefix
197  * @param max_queued_request max number of outstanding requests queued
198  * @param handle_keepalives handle memclnt_keepalive automatically
199  *
200  * @return VAPI_OK on success, other error code on error
201  */
202  vapi_error_e connect (const char *name, const char *chroot_prefix,
203  int max_outstanding_requests, int response_queue_size,
204  bool handle_keepalives = true)
205  {
206  return vapi_connect (vapi_ctx, name, chroot_prefix,
207  max_outstanding_requests, response_queue_size,
208  VAPI_MODE_BLOCKING, handle_keepalives);
209  }
210 
211  /**
212  * @brief disconnect from vpp
213  *
214  * @return VAPI_OK on success, other error code on error
215  */
217  {
218  auto x = requests.size ();
219  while (x > 0)
220  {
221  VAPI_DBG ("popping request @%p", requests.front ());
222  requests.pop_front ();
223  --x;
224  }
225  return vapi_disconnect (vapi_ctx);
226  };
227 
228  /**
229  * @brief get event file descriptor
230  *
231  * @note this file descriptor becomes readable when messages (from vpp)
232  * are waiting in queue
233  *
234  * @param[out] fd pointer to result variable
235  *
236  * @return VAPI_OK on success, other error code on error
237  */
239  {
240  return vapi_get_fd (vapi_ctx, fd);
241  }
242 
243  /**
244  * @brief wait for responses from vpp and assign them to appropriate objects
245  *
246  * @param limit stop dispatch after the limit object received it's response
247  *
248  * @return VAPI_OK on success, other error code on error
249  */
250  vapi_error_e dispatch (const Common_req *limit = nullptr, u32 time = 5)
251  {
252  std::lock_guard<std::mutex> lock (dispatch_mutex);
253  vapi_error_e rv = VAPI_OK;
254  bool loop_again = true;
255  while (loop_again)
256  {
257  void *shm_data;
258  size_t shm_data_size;
259  rv = vapi_recv (vapi_ctx, &shm_data, &shm_data_size, SVM_Q_TIMEDWAIT,
260  time);
261  if (VAPI_OK != rv)
262  {
263  return rv;
264  }
265 #if VAPI_CPP_DEBUG_LEAKS
266  on_shm_data_alloc (shm_data);
267 #endif
268  std::lock_guard<std::recursive_mutex> requests_lock (requests_mutex);
269  std::lock_guard<std::recursive_mutex> events_lock (events_mutex);
271  vapi_ctx, be16toh (*static_cast<u16 *> (shm_data)));
272  bool has_context = vapi_msg_is_with_context (id);
273  bool break_dispatch = false;
274  Common_req *matching_req = nullptr;
275  if (has_context)
276  {
277  u32 context = *reinterpret_cast<u32 *> (
278  (static_cast<u8 *> (shm_data) + vapi_get_context_offset (id)));
279  const auto x = requests.front ();
280  matching_req = x;
281  if (context == x->context)
282  {
283  std::tie (rv, break_dispatch) =
284  x->assign_response (id, shm_data);
285  }
286  else
287  {
288  std::tie (rv, break_dispatch) =
289  x->assign_response (id, nullptr);
290  }
291  if (break_dispatch)
292  {
293  requests.pop_front ();
294  }
295  }
296  else
297  {
298  if (events[id])
299  {
300  std::tie (rv, break_dispatch) =
301  events[id]->assign_response (id, shm_data);
302  matching_req = events[id];
303  }
304  else
305  {
306  msg_free (shm_data);
307  }
308  }
309  if ((matching_req && matching_req == limit && break_dispatch) ||
310  VAPI_OK != rv)
311  {
312  return rv;
313  }
314  loop_again = !requests.empty () || (event_count > 0);
315  }
316  return rv;
317  }
318 
319  /**
320  * @brief convenience wrapper function
321  */
323  {
324  return dispatch (&limit);
325  }
326 
327  /**
328  * @brief wait for response to a specific request
329  *
330  * @param req request to wait for response for
331  *
332  * @return VAPI_OK on success, other error code on error
333  */
335  {
336  if (RESPONSE_READY == req.get_response_state ())
337  {
338  return VAPI_OK;
339  }
340  return dispatch (req);
341  }
342 
343 private:
344  void msg_free (void *shm_data)
345  {
346 #if VAPI_CPP_DEBUG_LEAKS
347  on_shm_data_free (shm_data);
348 #endif
349  vapi_msg_free (vapi_ctx, shm_data);
350  }
351 
352  template <template <typename XReq, typename XResp, typename... XArgs>
353  class X,
354  typename Req, typename Resp, typename... Args>
355  vapi_error_e send (X<Req, Resp, Args...> *req)
356  {
357  if (!req)
358  {
359  return VAPI_EINVAL;
360  }
361  u32 req_context =
362  req_context_counter.fetch_add (1, std::memory_order_relaxed);
363  req->request.shm_data->header.context = req_context;
364  vapi_swap_to_be<Req> (req->request.shm_data);
365  std::lock_guard<std::recursive_mutex> lock (requests_mutex);
366  vapi_error_e rv = vapi_send (vapi_ctx, req->request.shm_data);
367  if (VAPI_OK == rv)
368  {
369  VAPI_DBG ("Push %p", req);
370  requests.emplace_back (req);
371  req->set_context (req_context);
372 #if VAPI_CPP_DEBUG_LEAKS
373  on_shm_data_free (req->request.shm_data);
374 #endif
375  req->request.shm_data = nullptr; /* consumed by vapi_send */
376  }
377  else
378  {
379  vapi_swap_to_host<Req> (req->request.shm_data);
380  }
381  return rv;
382  }
383 
384  template <template <typename XReq, typename XResp, typename... XArgs>
385  class X,
386  typename Req, typename Resp, typename... Args>
387  vapi_error_e send_with_control_ping (X<Req, Resp, Args...> *req)
388  {
389  if (!req)
390  {
391  return VAPI_EINVAL;
392  }
393  u32 req_context =
394  req_context_counter.fetch_add (1, std::memory_order_relaxed);
395  req->request.shm_data->header.context = req_context;
396  vapi_swap_to_be<Req> (req->request.shm_data);
397  std::lock_guard<std::recursive_mutex> lock (requests_mutex);
398  vapi_error_e rv = vapi_send_with_control_ping (
399  vapi_ctx, req->request.shm_data, req_context);
400  if (VAPI_OK == rv)
401  {
402  VAPI_DBG ("Push %p", req);
403  requests.emplace_back (req);
404  req->set_context (req_context);
405 #if VAPI_CPP_DEBUG_LEAKS
406  on_shm_data_free (req->request.shm_data);
407 #endif
408  req->request.shm_data = nullptr; /* consumed by vapi_send */
409  }
410  else
411  {
412  vapi_swap_to_host<Req> (req->request.shm_data);
413  }
414  return rv;
415  }
416 
417  void unregister_request (Common_req *request)
418  {
419  std::lock_guard<std::recursive_mutex> lock (requests_mutex);
420  std::remove (requests.begin (), requests.end (), request);
421  }
422 
423  template <typename M> void register_event (Event_registration<M> *event)
424  {
425  const vapi_msg_id_t id = M::get_msg_id ();
426  std::lock_guard<std::recursive_mutex> lock (events_mutex);
427  events[id] = event;
428  ++event_count;
429  }
430 
431  template <typename M> void unregister_event (Event_registration<M> *event)
432  {
433  const vapi_msg_id_t id = M::get_msg_id ();
434  std::lock_guard<std::recursive_mutex> lock (events_mutex);
435  events[id] = nullptr;
436  --event_count;
437  }
438 
439  vapi_ctx_t vapi_ctx;
440  std::atomic_ulong req_context_counter;
441  std::mutex dispatch_mutex;
442 
443  std::recursive_mutex requests_mutex;
444  std::recursive_mutex events_mutex;
445  std::deque<Common_req *> requests;
446  std::vector<Common_req *> events;
447  int event_count;
448 
449  template <typename Req, typename Resp, typename... Args>
450  friend class Request;
451 
452  template <typename Req, typename Resp, typename... Args> friend class Dump;
453 
454  template <typename M> friend class Result_set;
455 
456  template <typename M> friend class Event_registration;
457 
458  template <typename M, typename... Args>
459  friend M *vapi_alloc (Connection &con, Args...);
460 
461  template <typename M> friend class Msg;
462 
463 #if VAPI_CPP_DEBUG_LEAKS
464  void on_shm_data_alloc (void *shm_data)
465  {
466  if (shm_data)
467  {
468  auto pos = shm_data_set.find (shm_data);
469  if (pos == shm_data_set.end ())
470  {
471  shm_data_set.insert (shm_data);
472  }
473  else
474  {
475  printf ("Double-add shm_data @%p!\n", shm_data);
476  }
477  }
478  }
479 
480  void on_shm_data_free (void *shm_data)
481  {
482  auto pos = shm_data_set.find (shm_data);
483  if (pos == shm_data_set.end ())
484  {
485  printf ("Freeing untracked shm_data @%p!\n", shm_data);
486  }
487  else
488  {
489  shm_data_set.erase (pos);
490  }
491  }
492  std::unordered_set<void *> shm_data_set;
493 #endif
494 };
495 
496 template <typename Req, typename Resp, typename... Args> class Request;
497 
498 template <typename Req, typename Resp, typename... Args> class Dump;
499 
500 template <class, class = void> struct vapi_has_payload_trait : std::false_type
501 {
502 };
503 
504 template <class... T> using vapi_void_t = void;
505 
506 template <class T>
507 struct vapi_has_payload_trait<T, vapi_void_t<decltype (&T::payload)>>
508  : std::true_type
509 {
510 };
511 
512 template <typename M> void vapi_msg_set_msg_id (vapi_msg_id_t id)
513 {
514  Msg<M>::set_msg_id (id);
515 }
516 
517 /**
518  * Class representing a message stored in shared memory
519  */
520 template <typename M> class Msg
521 {
522 public:
523  Msg (const Msg &) = delete;
524 
525  ~Msg ()
526  {
527  VAPI_DBG ("Destroy Msg<%s>@%p, shm_data@%p",
528  vapi_get_msg_name (get_msg_id ()), this, shm_data);
529  if (shm_data)
530  {
531  con.get ().msg_free (shm_data);
532  shm_data = nullptr;
533  }
534  }
535 
537  {
538  return *msg_id_holder ();
539  }
540 
541  template <typename X = M>
542  typename std::enable_if<vapi_has_payload_trait<X>::value,
543  decltype (X::payload) &>::type
544  get_payload () const
545  {
546  return shm_data->payload;
547  }
548 
549 private:
550  Msg (Msg<M> &&msg) : con{msg.con}
551  {
552  VAPI_DBG ("Move construct Msg<%s> from msg@%p to msg@%p, shm_data@%p",
553  vapi_get_msg_name (get_msg_id ()), &msg, this, msg.shm_data);
554  shm_data = msg.shm_data;
555  msg.shm_data = nullptr;
556  }
557 
558  Msg<M> &operator= (Msg<M> &&msg)
559  {
560  VAPI_DBG ("Move assign Msg<%s> from msg@%p to msg@%p, shm_data@%p",
561  vapi_get_msg_name (get_msg_id ()), &msg, this, msg.shm_data);
562  con.get ().msg_free (shm_data);
563  con = msg.con;
564  shm_data = msg.shm_data;
565  msg.shm_data = nullptr;
566  return *this;
567  }
568 
569  struct Msg_allocator : std::allocator<Msg<M>>
570  {
571  template <class U, class... Args> void construct (U *p, Args &&... args)
572  {
573  ::new ((void *)p) U (std::forward<Args> (args)...);
574  }
575 
576  template <class U> struct rebind
577  {
578  typedef Msg_allocator other;
579  };
580  };
581 
582  static void set_msg_id (vapi_msg_id_t id)
583  {
584  assert ((VAPI_INVALID_MSG_ID == *msg_id_holder ()) ||
585  (id == *msg_id_holder ()));
586  *msg_id_holder () = id;
587  }
588 
589  static vapi_msg_id_t *msg_id_holder ()
590  {
591  static vapi_msg_id_t my_id{VAPI_INVALID_MSG_ID};
592  return &my_id;
593  }
594 
595  Msg (Connection &con, void *shm_data) : con{con}
596  {
597  if (!con.is_msg_available (get_msg_id ()))
598  {
600  }
601  this->shm_data = static_cast<shm_data_type *> (shm_data);
602  VAPI_DBG ("New Msg<%s>@%p shm_data@%p", vapi_get_msg_name (get_msg_id ()),
603  this, shm_data);
604  }
605 
606  void assign_response (vapi_msg_id_t resp_id, void *shm_data)
607  {
608  assert (nullptr == this->shm_data);
609  if (resp_id != get_msg_id ())
610  {
612  }
613  this->shm_data = static_cast<M *> (shm_data);
614  vapi_swap_to_host<M> (this->shm_data);
615  VAPI_DBG ("Assign response to Msg<%s>@%p shm_data@%p",
616  vapi_get_msg_name (get_msg_id ()), this, shm_data);
617  }
618 
619  std::reference_wrapper<Connection> con;
620  using shm_data_type = M;
621  shm_data_type *shm_data;
622 
623  friend class Connection;
624 
625  template <typename Req, typename Resp, typename... Args>
626  friend class Request;
627 
628  template <typename Req, typename Resp, typename... Args> friend class Dump;
629 
630  template <typename X> friend class Event_registration;
631 
632  template <typename X> friend class Result_set;
633 
634  friend struct Msg_allocator;
635 
636  template <typename X> friend void vapi_msg_set_msg_id (vapi_msg_id_t id);
637 };
638 
639 /**
640  * Class representing a simple request - with a single response message
641  */
642 template <typename Req, typename Resp, typename... Args>
643 class Request : public Common_req
644 {
645 public:
646  Request (Connection &con, Args... args,
647  std::function<vapi_error_e (Request<Req, Resp, Args...> &)>
648  callback = nullptr)
649  : Common_req{con}, callback{callback},
650  request{con, vapi_alloc<Req> (con, args...)}, response{con, nullptr}
651  {
652  }
653 
654  Request (const Request &) = delete;
655 
656  virtual ~Request ()
657  {
658  if (RESPONSE_NOT_READY == get_response_state ())
659  {
660  con.unregister_request (this);
661  }
662  }
663 
664  vapi_error_e execute ()
665  {
666  return con.send (this);
667  }
668 
669  const Msg<Req> &get_request (void) const
670  {
671  return request;
672  }
673 
674  const Msg<Resp> &get_response (void)
675  {
676  return response;
677  }
678 
679 private:
680  virtual std::tuple<vapi_error_e, bool> assign_response (vapi_msg_id_t id,
681  void *shm_data)
682  {
683  assert (RESPONSE_NOT_READY == get_response_state ());
684  response.assign_response (id, shm_data);
685  set_response_state (RESPONSE_READY);
686  if (nullptr != callback)
687  {
688  return std::make_pair (callback (*this), true);
689  }
690  return std::make_pair (VAPI_OK, true);
691  }
692  std::function<vapi_error_e (Request<Req, Resp, Args...> &)> callback;
694  Msg<Resp> response;
695 
696  friend class Connection;
697 };
698 
699 /**
700  * Class representing iterable set of responses of the same type
701  */
702 template <typename M> class Result_set
703 {
704 public:
706  {
707  }
708 
709  Result_set (const Result_set &) = delete;
710 
711  bool is_complete () const
712  {
713  return complete;
714  }
715 
716  size_t size () const
717  {
718  return set.size ();
719  }
720 
721  using const_iterator =
722  typename std::vector<Msg<M>,
724 
726  {
727  return set.begin ();
728  }
729 
731  {
732  return set.end ();
733  }
734 
736  {
737  set.erase (pos);
738  }
739 
741  {
742  set.clear ();
743  }
744 
745 private:
746  void mark_complete ()
747  {
748  complete = true;
749  }
750 
751  void assign_response (vapi_msg_id_t resp_id, void *shm_data)
752  {
753  if (resp_id != Msg<M>::get_msg_id ())
754  {
755  {
757  }
758  }
759  else if (shm_data)
760  {
761  vapi_swap_to_host<M> (static_cast<M *> (shm_data));
762  set.emplace_back (con, shm_data);
763  VAPI_DBG ("Result_set@%p emplace_back shm_data@%p", this, shm_data);
764  }
765  }
766 
767  Result_set (Connection &con) : con (con), complete{false}
768  {
769  }
770 
771  Connection &con;
772  bool complete;
773  std::vector<Msg<M>, typename Msg<M>::Msg_allocator> set;
774 
775  template <typename Req, typename Resp, typename... Args> friend class Dump;
776 
777  template <typename X> friend class Event_registration;
778 };
779 
780 /**
781  * Class representing a dump request - zero or more identical responses to a
782  * single request message
783  */
784 template <typename Req, typename Resp, typename... Args>
785 class Dump : public Common_req
786 {
787 public:
788  Dump (Connection &con, Args... args,
789  std::function<vapi_error_e (Dump<Req, Resp, Args...> &)> callback =
790  nullptr)
791  : Common_req{con}, request{con, vapi_alloc<Req> (con, args...)},
792  result_set{con}, callback{callback}
793  {
794  }
795 
796  Dump (const Dump &) = delete;
797 
798  virtual ~Dump ()
799  {
800  }
801 
802  virtual std::tuple<vapi_error_e, bool> assign_response (vapi_msg_id_t id,
803  void *shm_data)
804  {
806  {
807  con.msg_free (shm_data);
808  result_set.mark_complete ();
809  set_response_state (RESPONSE_READY);
810  if (nullptr != callback)
811  {
812  return std::make_pair (callback (*this), true);
813  }
814  return std::make_pair (VAPI_OK, true);
815  }
816  else
817  {
818  result_set.assign_response (id, shm_data);
819  }
820  return std::make_pair (VAPI_OK, false);
821  }
822 
823  vapi_error_e execute ()
824  {
825  return con.send_with_control_ping (this);
826  }
827 
829  {
830  return request;
831  }
832 
834 
835  const Result_set<Resp> &get_result_set (void) const
836  {
837  return result_set;
838  }
839 
840 private:
842  Result_set<resp_type> result_set;
843  std::function<vapi_error_e (Dump<Req, Resp, Args...> &)> callback;
844 
845  friend class Connection;
846 };
847 
848 /**
849  * Class representing event registration - incoming events (messages) from
850  * vpp as a result of a subscription (typically a want_* simple request)
851  */
852 template <typename M> class Event_registration : public Common_req
853 {
854 public:
856  Connection &con,
857  std::function<vapi_error_e (Event_registration<M> &)> callback = nullptr)
858  : Common_req{con}, result_set{con}, callback{callback}
859  {
860  if (!con.is_msg_available (M::get_msg_id ()))
861  {
863  }
864  con.register_event (this);
865  }
866 
867  Event_registration (const Event_registration &) = delete;
868 
870  {
871  con.unregister_event (this);
872  }
873 
874  virtual std::tuple<vapi_error_e, bool> assign_response (vapi_msg_id_t id,
875  void *shm_data)
876  {
877  result_set.assign_response (id, shm_data);
878  if (nullptr != callback)
879  {
880  return std::make_pair (callback (*this), true);
881  }
882  return std::make_pair (VAPI_OK, true);
883  }
884 
885  using resp_type = typename M::shm_data_type;
886 
888  {
889  return result_set;
890  }
891 
892 private:
893  Result_set<resp_type> result_set;
894  std::function<vapi_error_e (Event_registration<M> &)> callback;
895 };
896 };
897 
898 #endif
899 
900 /*
901  * fd.io coding-style-patch-verification: ON
902  *
903  * Local Variables:
904  * eval: (c-set-style "gnu")
905  * End:
906  */
~Msg()
Definition: vapi.hpp:525
no response to request (will never come)
Definition: vapi.hpp:84
void vapi_msg_set_msg_id(vapi_msg_id_t id)
Definition: vapi.hpp:512
vapi_error_e dispatch(const Common_req &limit)
convenience wrapper function
Definition: vapi.hpp:322
operations block until response received
Definition: vapi_common.h:44
static vapi_msg_id_t get_msg_id()
Definition: vapi.hpp:536
virtual ~Request()
Definition: vapi.hpp:656
size_t vapi_get_message_count()
Definition: vapi.c:965
vapi_msg_id_t vapi_get_msg_id_t()
Connection & get_connection()
Definition: vapi.hpp:96
virtual ~Common_req()
Definition: vapi.hpp:94
vapi_error_e execute()
Definition: vapi.hpp:823
vapi_error_e vapi_recv(vapi_ctx_t ctx, void **msg, size_t *msg_size, svm_q_conditional_wait_t cond, u32 time)
low-level api for reading messages from vpp
Definition: vapi.c:527
vapi_error_e vapi_send(vapi_ctx_t ctx, void *msg)
low-level api for sending messages to vpp
Definition: vapi.c:441
vapi_error_e vapi_connect(vapi_ctx_t ctx, const char *name, const char *chroot_prefix, int max_outstanding_requests, int response_queue_size, vapi_mode_e mode, bool handle_keepalives)
connect to vpp
Definition: vapi.c:301
virtual const char * what() const
Definition: vapi.hpp:61
unsigned char u8
Definition: types.h:56
typename Msg< Resp >::shm_data_type resp_type
Definition: vapi.hpp:833
~Connection(void)
Definition: vapi.hpp:172
#define assert(x)
Definition: dlmalloc.c:30
blocking call, returns on signal or time-out - best used in combination with condvars, with eventfds we don&#39;t yield the cpu
Definition: queue.h:46
vapi_error_e connect(const char *name, const char *chroot_prefix, int max_outstanding_requests, int response_queue_size, bool handle_keepalives=true)
connect to vpp
Definition: vapi.hpp:202
void vapi_swap_to_be(M *msg)
Class representing event registration - incoming events (messages) from vpp as a result of a subscrip...
Definition: vapi.hpp:56
Forward declarations.
Definition: vapi.hpp:44
vapi_response_state_e get_response_state(void) const
Definition: vapi.hpp:101
vapi_error_e vapi_disconnect(vapi_ctx_t ctx)
disconnect from vpp
Definition: vapi.c:419
const Result_set< Resp > & get_result_set(void) const
Definition: vapi.hpp:835
Class representing iterable set of responses of the same type.
Definition: vapi.hpp:702
vhost_vring_state_t state
Definition: vhost_user.h:120
unsigned int u32
Definition: types.h:88
const Msg< Resp > & get_response(void)
Definition: vapi.hpp:674
#define VAPI_INVALID_MSG_ID
Definition: vapi_common.h:57
size_t vapi_get_context_offset(vapi_msg_id_t id)
Definition: vapi.c:900
response to request is ready
Definition: vapi.hpp:81
vapi_msg_id_t vapi_msg_id_control_ping_reply
Definition: vapi.c:40
const Msg< Req > & get_request(void) const
Definition: vapi.hpp:669
const char * vapi_get_msg_name(vapi_msg_id_t id)
Definition: vapi.c:971
vapi_error_e disconnect()
disconnect from vpp
Definition: vapi.hpp:216
virtual ~Dump()
Definition: vapi.hpp:798
void free_all_responses()
Definition: vapi.hpp:740
vapi_error_e get_fd(int *fd)
get event file descriptor
Definition: vapi.hpp:238
invalid value encountered
Definition: vapi_common.h:28
common vpp api C declarations
virtual std::tuple< vapi_error_e, bool > assign_response(vapi_msg_id_t id, void *shm_data)
Definition: vapi.hpp:802
#define VAPI_DBG(...)
Definition: vapi_dbg.h:65
u8 name[64]
Definition: memclnt.api:152
bool vapi_msg_is_with_context(vapi_msg_id_t id)
Definition: vapi.c:740
Connection(void)
Definition: vapi.hpp:156
Result_set< resp_type > & get_result_set(void)
Definition: vapi.hpp:887
M * vapi_alloc(Connection &con, Args...)
vapi_msg_id_t vapi_lookup_vapi_msg_id_t(vapi_ctx_t ctx, u16 vl_msg_id)
Definition: vapi.c:241
virtual ~Event_registration()
Definition: vapi.hpp:869
Class representing a message stored in shared memory.
Definition: vapi.hpp:50
Dump(Connection &con, Args...args, std::function< vapi_error_e(Dump< Req, Resp, Args... > &)> callback=nullptr)
Definition: vapi.hpp:788
u32 context
Definition: ipsec_gre.api:33
Msg< Req > & get_request(void)
Definition: vapi.hpp:828
typename std::vector< Msg< resp_type >, typename Msg< resp_type >::Msg_allocator >::const_iterator const_iterator
Definition: vapi.hpp:723
vapi_error_e dispatch(const Common_req *limit=nullptr, u32 time=5)
wait for responses from vpp and assign them to appropriate objects
Definition: vapi.hpp:250
void vapi_swap_to_host(M *msg)
Class representing a connection to VPP.
Definition: vapi.hpp:153
internal vpp api C declarations
void free_response(const_iterator pos)
Definition: vapi.hpp:735
bool vapi_is_msg_available(vapi_ctx_t ctx, vapi_msg_id_t id)
check if message identified by it&#39;s message id is known by the vpp to which the connection is open ...
Definition: vapi.c:295
virtual std::tuple< vapi_error_e, bool > assign_response(vapi_msg_id_t id, void *shm_data)
Definition: vapi.hpp:874
success
Definition: vapi_common.h:27
const_iterator end() const
Definition: vapi.hpp:730
vapi_response_state_e
Definition: vapi.hpp:76
size_t size() const
Definition: vapi.hpp:716
response not ready yet
Definition: vapi.hpp:78
virtual const char * what() const
Definition: vapi.hpp:70
Request(Connection &con, Args...args, std::function< vapi_error_e(Request< Req, Resp, Args... > &)> callback=nullptr)
Definition: vapi.hpp:646
Event_registration(Connection &con, std::function< vapi_error_e(Event_registration< M > &)> callback=nullptr)
Definition: vapi.hpp:855
vapi_error_e wait_for_response(const Common_req &req)
wait for response to a specific request
Definition: vapi.hpp:334
void vapi_ctx_free(vapi_ctx_t ctx)
free vapi context
Definition: vapi.c:283
std::enable_if< vapi_has_payload_trait< X >::value, decltype(X::payload)& >::type get_payload() const
Definition: vapi.hpp:544
Class representing a simple request - with a single response message.
Definition: vapi.hpp:49
void vapi_void_t
Definition: vapi.hpp:504
Class representing a dump request - zero or more identical responses to a single request message...
Definition: vapi.hpp:498
bool is_msg_available(vapi_msg_id_t type)
check if message identified by it&#39;s message id is known by the vpp to which the connection is open ...
Definition: vapi.hpp:187
vhost_user_req_t request
Definition: vhost_user.h:114
typename M::shm_data_type resp_type
Definition: vapi.hpp:885
vapi_error_e vapi_get_fd(vapi_ctx_t ctx, int *fd)
get event file descriptor
Definition: vapi.c:435
vapi_error_e execute()
Definition: vapi.hpp:664
void vapi_msg_free(vapi_ctx_t ctx, void *msg)
free a vapi message
Definition: vapi.c:228
Class representing common functionality of a request - response state and context.
Definition: vapi.hpp:91
const_iterator begin() const
Definition: vapi.hpp:725
u32 id
Definition: udp.api:45
vapi_error_e vapi_ctx_alloc(vapi_ctx_t *result)
allocate vapi context
Definition: vapi.c:251
unsigned int vapi_msg_id_t
Definition: vapi_common.h:55
bool is_complete() const
Definition: vapi.hpp:711
vapi_error_e
Definition: vapi_common.h:25
#define M(T, mp)