FD.io VPP  v21.06
Vector Packet Processing
vapi_cpp_test.cpp
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 #include <memory>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <assert.h>
22 #include <setjmp.h>
23 #include <check.h>
24 #include <vapi/vapi.hpp>
25 #include <vapi/vpe.api.vapi.hpp>
26 #include <vapi/interface.api.vapi.hpp>
27 #include <fake.api.vapi.hpp>
28 
32 
33 static char *app_name = nullptr;
34 static char *api_prefix = nullptr;
35 static const int max_outstanding_requests = 32;
36 static const int response_queue_size = 32;
37 
38 #define WAIT_FOR_RESPONSE(param, ret) \
39  do \
40  { \
41  ret = con.wait_for_response (param); \
42  } \
43  while (ret == VAPI_EAGAIN)
44 
45 using namespace vapi;
46 
47 void verify_show_version_reply (const Show_version_reply &r)
48 {
49  auto &p = r.get_payload ();
50  printf ("show_version_reply: program: `%s', version: `%s', build directory: "
51  "`%s', build date: `%s'\n",
52  p.program, p.version, p.build_directory, p.build_date);
53  ck_assert_str_eq ("vpe", (char *)p.program);
54 }
55 
57 
58 void setup (void)
59 {
60  vapi_error_e rv = con.connect (
62  ck_assert_int_eq (VAPI_OK, rv);
63 }
64 
65 void teardown (void)
66 {
67  con.disconnect ();
68 }
69 
70 START_TEST (test_show_version_1)
71 {
72  printf ("--- Show version by reading response associated to request ---\n");
73  Show_version sv (con);
74  vapi_error_e rv = sv.execute ();
75  ck_assert_int_eq (VAPI_OK, rv);
76  WAIT_FOR_RESPONSE (sv, rv);
77  ck_assert_int_eq (VAPI_OK, rv);
78  auto &r = sv.get_response ();
80 }
81 
83 
85 {
86  Show_version_cb () : called{0} {};
87  int called;
88  vapi_error_e operator() (Show_version &sv)
89  {
90  auto &r = sv.get_response ();
92  ++called;
93  return VAPI_OK;
94  }
95 };
96 
97 START_TEST (test_show_version_2)
98 {
99  printf ("--- Show version by getting a callback ---\n");
100  Show_version_cb cb;
101  Show_version sv (con, std::ref (cb));
102  vapi_error_e rv = sv.execute ();
103  ck_assert_int_eq (VAPI_OK, rv);
104  con.dispatch (sv);
105  ck_assert_int_eq (1, cb.called);
106 }
107 
108 END_TEST;
109 
110 START_TEST (test_loopbacks_1)
111 {
112  printf ("--- Create/delete loopbacks by waiting for response ---\n");
113  const auto num_ifs = 5;
114  u8 mac_addresses[num_ifs][6];
115  memset (&mac_addresses, 0, sizeof (mac_addresses));
116  u32 sw_if_indexes[num_ifs];
117  memset (&sw_if_indexes, 0xff, sizeof (sw_if_indexes));
118  for (int i = 0; i < num_ifs; ++i)
119  {
120  memcpy (&mac_addresses[i], "\1\2\3\4\5\6", 6);
121  mac_addresses[i][5] = i;
122  }
123  for (int i = 0; i < num_ifs; ++i)
124  {
125  Create_loopback cl (con);
126  auto &p = cl.get_request ().get_payload ();
127  memcpy (p.mac_address, mac_addresses[i], sizeof (p.mac_address));
128  auto e = cl.execute ();
129  ck_assert_int_eq (VAPI_OK, e);
131  WAIT_FOR_RESPONSE (cl, rv);
132  ck_assert_int_eq (VAPI_OK, rv);
133  auto &rp = cl.get_response ().get_payload ();
134  ck_assert_int_eq (0, rp.retval);
135  sw_if_indexes[i] = rp.sw_if_index;
136  }
137  for (int i = 0; i < num_ifs; ++i)
138  {
139  printf ("Created loopback with MAC %02x:%02x:%02x:%02x:%02x:%02x --> "
140  "sw_if_index %u\n",
141  mac_addresses[i][0], mac_addresses[i][1], mac_addresses[i][2],
142  mac_addresses[i][3], mac_addresses[i][4], mac_addresses[i][5],
143  sw_if_indexes[i]);
144  }
145 
146  { // new context
147  bool seen[num_ifs] = {0};
148  Sw_interface_dump d (con);
149  d.get_request ().get_payload ();
150  auto rv = d.execute ();
151  ck_assert_int_eq (VAPI_OK, rv);
152  WAIT_FOR_RESPONSE (d, rv);
153  ck_assert_int_eq (VAPI_OK, rv);
154  auto &rs = d.get_result_set ();
155  for (auto &r : rs)
156  {
157  auto &p = r.get_payload ();
158  for (int i = 0; i < num_ifs; ++i)
159  {
160  if (sw_if_indexes[i] == p.sw_if_index)
161  {
162  ck_assert_int_eq (0, seen[i]);
163  seen[i] = true;
164  }
165  }
166  }
167  for (int i = 0; i < num_ifs; ++i)
168  {
169  ck_assert_int_eq (1, seen[i]);
170  }
171  }
172 
173  for (int i = 0; i < num_ifs; ++i)
174  {
175  Delete_loopback dl (con);
176  dl.get_request ().get_payload ().sw_if_index = sw_if_indexes[i];
177  auto rv = dl.execute ();
178  ck_assert_int_eq (VAPI_OK, rv);
179  WAIT_FOR_RESPONSE (dl, rv);
180  ck_assert_int_eq (VAPI_OK, rv);
181  auto &response = dl.get_response ();
182  auto rp = response.get_payload ();
183  ck_assert_int_eq (0, rp.retval);
184  printf ("Deleted loopback with sw_if_index %u\n", sw_if_indexes[i]);
185  }
186 
187  { // new context
188  Sw_interface_dump d (con);
189  d.get_request ().get_payload ();
190  auto rv = d.execute ();
191  ck_assert_int_eq (VAPI_OK, rv);
192  WAIT_FOR_RESPONSE (d, rv);
193  ck_assert_int_eq (VAPI_OK, rv);
194  auto &rs = d.get_result_set ();
195  for (auto &r : rs)
196  {
197  auto &p = r.get_payload ();
198  for (int i = 0; i < num_ifs; ++i)
199  {
200  ck_assert_int_ne (sw_if_indexes[i], p.sw_if_index);
201  }
202  }
203  }
204 }
205 
206 END_TEST;
207 
209 {
210  Create_loopback_cb () : called{0}, sw_if_index{0} {};
211  int called;
213  bool seen;
214  vapi_error_e operator() (Create_loopback &cl)
215  {
216  auto &r = cl.get_response ();
217  sw_if_index = r.get_payload ().sw_if_index;
218  ++called;
219  return VAPI_OK;
220  }
221 };
222 
224 {
225  Delete_loopback_cb () : called{0}, sw_if_index{0} {};
226  int called;
228  bool seen;
229  vapi_error_e operator() (Delete_loopback &dl)
230  {
231  auto &r = dl.get_response ();
232  ck_assert_int_eq (0, r.get_payload ().retval);
233  ++called;
234  return VAPI_OK;
235  }
236 };
237 
238 template <int num_ifs> struct Sw_interface_dump_cb
239 {
240  Sw_interface_dump_cb (std::array<Create_loopback_cb, num_ifs> &cbs)
241  : called{0}, cbs{cbs} {};
242  int called;
243  std::array<Create_loopback_cb, num_ifs> &cbs;
244  vapi_error_e operator() (Sw_interface_dump &d)
245  {
246  for (auto &y : cbs)
247  {
248  y.seen = false;
249  }
250  for (auto &x : d.get_result_set ())
251  {
252  auto &p = x.get_payload ();
253  for (auto &y : cbs)
254  {
255  if (p.sw_if_index == y.sw_if_index)
256  {
257  y.seen = true;
258  }
259  }
260  }
261  for (auto &y : cbs)
262  {
263  ck_assert_int_eq (true, y.seen);
264  }
265  ++called;
266  return VAPI_OK;
267  }
268 };
269 
270 START_TEST (test_loopbacks_2)
271 {
272  printf ("--- Create/delete loopbacks by getting a callback ---\n");
273  const auto num_ifs = 5;
274  u8 mac_addresses[num_ifs][6];
275  memset (&mac_addresses, 0, sizeof (mac_addresses));
276  for (int i = 0; i < num_ifs; ++i)
277  {
278  memcpy (&mac_addresses[i], "\1\2\3\4\5\6", 6);
279  mac_addresses[i][5] = i;
280  }
281  std::array<Create_loopback_cb, num_ifs> ccbs;
282  std::array<std::unique_ptr<Create_loopback>, num_ifs> clcs;
283  for (int i = 0; i < num_ifs; ++i)
284  {
285  Create_loopback *cl = new Create_loopback (con, std::ref (ccbs[i]));
286  clcs[i].reset (cl);
287  auto &p = cl->get_request ().get_payload ();
288  memcpy (p.mac_address, mac_addresses[i], sizeof (p.mac_address));
289  auto e = cl->execute ();
290  ck_assert_int_eq (VAPI_OK, e);
291  }
292  con.dispatch ();
293  for (int i = 0; i < num_ifs; ++i)
294  {
295  ck_assert_int_eq (1, ccbs[i].called);
296  printf ("Created loopback with MAC %02x:%02x:%02x:%02x:%02x:%02x --> "
297  "sw_if_index %u\n",
298  mac_addresses[i][0], mac_addresses[i][1], mac_addresses[i][2],
299  mac_addresses[i][3], mac_addresses[i][4], mac_addresses[i][5],
300  ccbs[i].sw_if_index);
301  }
302 
303  Sw_interface_dump_cb<num_ifs> swdcb (ccbs);
304  Sw_interface_dump d (con, std::ref (swdcb));
305  d.get_request ().get_payload ();
306  auto rv = d.execute ();
307  ck_assert_int_eq (VAPI_OK, rv);
308  WAIT_FOR_RESPONSE (d, rv);
309  ck_assert_int_eq (VAPI_OK, rv);
310  ck_assert_int_ne (0, swdcb.called);
311  std::array<Delete_loopback_cb, num_ifs> dcbs;
312  std::array<std::unique_ptr<Delete_loopback>, num_ifs> dlcs;
313  for (int i = 0; i < num_ifs; ++i)
314  {
315  Delete_loopback *dl = new Delete_loopback (con, std::ref (dcbs[i]));
316  dlcs[i].reset (dl);
317  auto &p = dl->get_request ().get_payload ();
318  p.sw_if_index = ccbs[i].sw_if_index;
319  dcbs[i].sw_if_index = ccbs[i].sw_if_index;
320  auto e = dl->execute ();
321  ck_assert_int_eq (VAPI_OK, e);
322  }
323  con.dispatch ();
324  for (auto &x : dcbs)
325  {
326  ck_assert_int_eq (true, x.called);
327  printf ("Deleted loopback with sw_if_index %u\n", x.sw_if_index);
328  }
329 
330  { // new context
331  Sw_interface_dump d (con);
332  d.get_request ().get_payload ();
333  auto rv = d.execute ();
334  ck_assert_int_eq (VAPI_OK, rv);
335  WAIT_FOR_RESPONSE (d, rv);
336  ck_assert_int_eq (VAPI_OK, rv);
337  auto &rs = d.get_result_set ();
338  for (auto &r : rs)
339  {
340  auto &p = r.get_payload ();
341  for (int i = 0; i < num_ifs; ++i)
342  {
343  ck_assert_int_ne (ccbs[i].sw_if_index, p.sw_if_index);
344  }
345  }
346  }
347 }
348 
349 END_TEST;
350 
351 START_TEST (test_unsupported)
352 {
353  printf ("--- Unsupported messages ---\n");
354  bool thrown = false;
355  try
356  {
357  Test_fake_msg fake (con);
358  }
359  catch (const Msg_not_available_exception &)
360  {
361  thrown = true;
362  printf ("Constructing unsupported msg not possible - test pass.\n");
363  }
364  ck_assert_int_eq (true, thrown);
365  thrown = false;
366  try
367  {
368  Test_fake_dump fake (con);
369  }
370  catch (const Msg_not_available_exception &)
371  {
372  thrown = true;
373  printf ("Constructing unsupported dump not possible - test pass.\n");
374  }
375  ck_assert_int_eq (true, thrown);
376  thrown = false;
377  try
378  {
380  }
381  catch (const Msg_not_available_exception &)
382  {
383  thrown = true;
384  printf ("Constructing unsupported event registration not possible - "
385  "test pass.\n");
386  }
387  ck_assert_int_eq (true, thrown);
388 }
389 
390 END_TEST;
391 
392 Suite *test_suite (void)
393 {
394  Suite *s = suite_create ("VAPI test");
395 
396  TCase *tc_cpp_api = tcase_create ("C++ API");
397  tcase_set_timeout (tc_cpp_api, 25);
398  tcase_add_checked_fixture (tc_cpp_api, setup, teardown);
399  tcase_add_test (tc_cpp_api, test_show_version_1);
400  tcase_add_test (tc_cpp_api, test_show_version_2);
401  tcase_add_test (tc_cpp_api, test_loopbacks_1);
402  tcase_add_test (tc_cpp_api, test_loopbacks_2);
403  tcase_add_test (tc_cpp_api, test_unsupported);
404  suite_add_tcase (s, tc_cpp_api);
405 
406  return s;
407 }
408 
409 int main (int argc, char *argv[])
410 {
411  if (3 != argc)
412  {
413  printf ("Invalid argc==`%d'\n", argc);
414  return EXIT_FAILURE;
415  }
416  app_name = argv[1];
417  api_prefix = argv[2];
418  printf ("App name: `%s', API prefix: `%s'\n", app_name, api_prefix);
419 
420  int number_failed;
421  Suite *s;
422  SRunner *sr;
423 
424  s = test_suite ();
425  sr = srunner_create (s);
426 
427  srunner_run_all (sr, CK_NORMAL);
428  number_failed = srunner_ntests_failed (sr);
429  srunner_free (sr);
430  return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
431 }
432 
433 /*
434  * fd.io coding-style-patch-verification: ON
435  *
436  * Local Variables:
437  * eval: (c-set-style "gnu")
438  * End:
439  */
int main(int argc, char *argv[])
vnet_hw_if_output_node_runtime_t * r
DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON
unsigned char u8
Definition: types.h:56
void setup(void)
unsigned int u32
Definition: types.h:88
static const int max_outstanding_requests
C++ VPP API.
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
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
void verify_show_version_reply(const Show_version_reply &r)
int __clib_unused rv
Definition: application.c:491
Suite * test_suite(void)
static const int response_queue_size
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
static char * app_name
vapi_error_e disconnect()
disconnect from vpp
Definition: vapi.hpp:216
void teardown(void)
Sw_interface_dump_cb(std::array< Create_loopback_cb, num_ifs > &cbs)
static char * api_prefix
END_TEST
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
std::array< Create_loopback_cb, num_ifs > & cbs
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
Class representing a connection to VPP.
Definition: vapi.hpp:153
success
Definition: vapi_common.h:27
#define WAIT_FOR_RESPONSE(param, ret)
DEFINE_VAPI_MSG_IDS_FAKE_API_JSON
DEFINE_VAPI_MSG_IDS_VPE_API_JSON
Connection con
vapi_error_e
Definition: vapi_common.h:25
START_TEST(test_show_version_1)