VOM: l2fib: Add bvi flag support
[vpp.git] / test / ext / vom_test.cpp
1 /*
2  * Test suite for class VppOM
3  *
4  * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
5  *
6  * This program and the accompanying materials are made available under the
7  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
8  * and is available at http://www.eclipse.org/legal/epl-v10.html
9  */
10 #define BOOST_TEST_MODULE "VPP OBJECT MODEL"
11 #define BOOST_TEST_DYN_LINK
12
13 #include <boost/test/unit_test.hpp>
14 #include <boost/assign/list_inserter.hpp>
15
16
17 #include <iostream>
18 #include <deque>
19
20 #include "vom/om.hpp"
21 #include "vom/interface.hpp"
22 #include "vom/interface_cmds.hpp"
23 #include "vom/l2_binding.hpp"
24 #include "vom/l2_binding_cmds.hpp"
25 #include "vom/l3_binding.hpp"
26 #include "vom/l3_binding_cmds.hpp"
27 #include "vom/bridge_domain.hpp"
28 #include "vom/bridge_domain_entry.hpp"
29 #include "vom/bridge_domain_arp_entry.hpp"
30 #include "vom/bridge_domain_cmds.hpp"
31 #include "vom/bridge_domain_entry_cmds.hpp"
32 #include "vom/bridge_domain_arp_entry_cmds.hpp"
33 #include "vom/prefix.hpp"
34 #include "vom/route.hpp"
35 #include "vom/route_cmds.hpp"
36 #include "vom/route_domain.hpp"
37 #include "vom/route_domain_cmds.hpp"
38 #include "vom/vxlan_tunnel.hpp"
39 #include "vom/vxlan_tunnel_cmds.hpp"
40 #include "vom/sub_interface.hpp"
41 #include "vom/sub_interface_cmds.hpp"
42 #include "vom/acl_list.hpp"
43 #include "vom/acl_binding.hpp"
44 #include "vom/acl_list_cmds.hpp"
45 #include "vom/acl_binding_cmds.hpp"
46 #include "vom/acl_l3_rule.hpp"
47 #include "vom/acl_l2_rule.hpp"
48 #include "vom/arp_proxy_config.hpp"
49 #include "vom/arp_proxy_binding.hpp"
50 #include "vom/arp_proxy_config_cmds.hpp"
51 #include "vom/arp_proxy_binding_cmds.hpp"
52 #include "vom/ip_unnumbered.hpp"
53 #include "vom/ip_unnumbered_cmds.hpp"
54 #include "vom/interface_ip6_nd.hpp"
55 #include "vom/interface_span.hpp"
56 #include "vom/interface_span_cmds.hpp"
57 #include "vom/neighbour.hpp"
58 #include "vom/neighbour_cmds.hpp"
59 #include "vom/nat_static.hpp"
60 #include "vom/nat_static_cmds.hpp"
61 #include "vom/nat_binding.hpp"
62 #include "vom/nat_binding_cmds.hpp"
63
64 using namespace boost;
65 using namespace VOM;
66
67 /**
68  * An expectation exception
69  */
70 class ExpException
71 {
72 public:
73     ExpException(unsigned int number)
74     {
75         // a neat place to add a break point
76         std::cout << "  ExpException here: " << number << std::endl;
77     }
78 };
79
80 class MockListener : public interface::event_listener,
81                      public interface::stat_listener
82 {
83     void handle_interface_stat(interface_cmds::stats_enable_cmd *cmd)
84     {
85     }
86     void handle_interface_event(interface_cmds::events_cmd *cmd)
87     {
88     }
89 };
90
91 class MockCmdQ : public HW::cmd_q
92 {
93 public:
94     MockCmdQ():
95         m_strict_order(true)
96     {
97     }
98     virtual ~MockCmdQ()
99     {
100     }
101     void expect(cmd *f)
102     {
103         m_exp_queue.push_back(f);
104     }
105     void enqueue(cmd *f)
106     {
107         m_act_queue.push_back(f);
108     }
109     void enqueue(std::queue<cmd*> &cmds)
110     {
111         while (cmds.size())
112         {
113             m_act_queue.push_back(cmds.front());
114             cmds.pop();
115         }
116     }
117     void enqueue(std::shared_ptr<cmd> f)
118     {
119         m_act_queue.push_back(f.get());
120     }
121
122     void dequeue(cmd *f)
123     {
124     }
125
126     void dequeue(std::shared_ptr<cmd> cmd)
127     {
128     }
129
130     void strict_order(bool on)
131     {
132         m_strict_order = on;
133     }
134
135     bool is_empty()
136     {
137         return ((0 == m_exp_queue.size()) &&
138                 (0 == m_act_queue.size()));
139     }
140
141     rc_t write()
142     {
143         cmd *f_exp, *f_act;
144         rc_t rc = rc_t::OK;
145
146         while (m_act_queue.size())
147         {
148             bool matched = false;
149             auto it_exp = m_exp_queue.begin();
150             auto it_act = m_act_queue.begin();
151
152             f_act = *it_act;
153
154             std::cout << " Act: " << f_act->to_string() << std::endl;
155             while (it_exp != m_exp_queue.end())
156             {
157                 f_exp = *it_exp;
158                 try
159                 {
160                     std::cout << "  Exp: " << f_exp->to_string() << std::endl;
161
162                     if (typeid(*f_exp) != typeid(*f_act))
163                     {
164                         throw ExpException(1);
165                     }
166
167                     if (typeid(*f_exp) == typeid(interface_cmds::af_packet_create_cmd))
168                     {
169                         rc = handle_derived<interface_cmds::af_packet_create_cmd>(f_exp, f_act);
170                     }
171                     else if (typeid(*f_exp) == typeid(interface_cmds::loopback_create_cmd))
172                     {
173                         rc = handle_derived<interface_cmds::loopback_create_cmd>(f_exp, f_act);
174                     }
175                     else if (typeid(*f_exp) == typeid(interface_cmds::loopback_delete_cmd))
176                     {
177                         rc = handle_derived<interface_cmds::loopback_delete_cmd>(f_exp, f_act);
178                     }
179                     else if (typeid(*f_exp) == typeid(interface_cmds::af_packet_delete_cmd))
180                     {
181                         rc = handle_derived<interface_cmds::af_packet_delete_cmd>(f_exp, f_act);
182                     }
183                     else if (typeid(*f_exp) == typeid(interface_cmds::state_change_cmd))
184                     {
185                         rc = handle_derived<interface_cmds::state_change_cmd>(f_exp, f_act);
186                     }
187                     else if (typeid(*f_exp) == typeid(interface_cmds::set_table_cmd))
188                     {
189                         rc = handle_derived<interface_cmds::set_table_cmd>(f_exp, f_act);
190                     }
191                     else if (typeid(*f_exp) == typeid(interface_cmds::set_mac_cmd))
192                     {
193                         rc = handle_derived<interface_cmds::set_mac_cmd>(f_exp, f_act);
194                     }
195                     else if (typeid(*f_exp) == typeid(interface_cmds::set_tag))
196                     {
197                         rc = handle_derived<interface_cmds::set_tag>(f_exp, f_act);
198                     }
199                     else if (typeid(*f_exp) == typeid(route_domain_cmds::create_cmd))
200                     {
201                         rc = handle_derived<route_domain_cmds::create_cmd>(f_exp, f_act);
202                     }
203                     else if (typeid(*f_exp) == typeid(route_domain_cmds::delete_cmd))
204                     {
205                         rc = handle_derived<route_domain_cmds::delete_cmd>(f_exp, f_act);
206                     }
207                     else if (typeid(*f_exp) == typeid(route::ip_route_cmds::update_cmd))
208                     {
209                         rc = handle_derived<route::ip_route_cmds::update_cmd>(f_exp, f_act);
210                     }
211                     else if (typeid(*f_exp) == typeid(route::ip_route_cmds::delete_cmd))
212                     {
213                         rc = handle_derived<route::ip_route_cmds::delete_cmd>(f_exp, f_act);
214                     }
215                     else if (typeid(*f_exp) == typeid(neighbour_cmds::create_cmd))
216                     {
217                         rc = handle_derived<neighbour_cmds::create_cmd>(f_exp, f_act);
218                     }
219                     else if (typeid(*f_exp) == typeid(neighbour_cmds::delete_cmd))
220                     {
221                         rc = handle_derived<neighbour_cmds::delete_cmd>(f_exp, f_act);
222                     }
223                     else if (typeid(*f_exp) == typeid(l3_binding_cmds::bind_cmd))
224                     {
225                         rc = handle_derived<l3_binding_cmds::bind_cmd>(f_exp, f_act);
226                     }
227                     else if (typeid(*f_exp) == typeid(l3_binding_cmds::unbind_cmd))
228                     {
229                         rc = handle_derived<l3_binding_cmds::unbind_cmd>(f_exp, f_act);
230                     }
231                     else if (typeid(*f_exp) == typeid(bridge_domain_cmds::create_cmd))
232                     {
233                         rc = handle_derived<bridge_domain_cmds::create_cmd>(f_exp, f_act);
234                     }
235                     else if (typeid(*f_exp) == typeid(bridge_domain_cmds::delete_cmd))
236                     {
237                         rc = handle_derived<bridge_domain_cmds::delete_cmd>(f_exp, f_act);
238                     }
239                     else if (typeid(*f_exp) == typeid(bridge_domain_entry_cmds::create_cmd))
240                     {
241                         rc = handle_derived<bridge_domain_entry_cmds::create_cmd>(f_exp, f_act);
242                     }
243                     else if (typeid(*f_exp) == typeid(bridge_domain_entry_cmds::delete_cmd))
244                     {
245                         rc = handle_derived<bridge_domain_entry_cmds::delete_cmd>(f_exp, f_act);
246                     }
247                     else if (typeid(*f_exp) == typeid(bridge_domain_arp_entry_cmds::create_cmd))
248                     {
249                         rc = handle_derived<bridge_domain_arp_entry_cmds::create_cmd>(f_exp, f_act);
250                     }
251                     else if (typeid(*f_exp) == typeid(bridge_domain_arp_entry_cmds::delete_cmd))
252                     {
253                         rc = handle_derived<bridge_domain_arp_entry_cmds::delete_cmd>(f_exp, f_act);
254                     }
255                     else if (typeid(*f_exp) == typeid(l2_binding_cmds::bind_cmd))
256                     {
257                         rc = handle_derived<l2_binding_cmds::bind_cmd>(f_exp, f_act);
258                     }
259                     else if (typeid(*f_exp) == typeid(l2_binding_cmds::unbind_cmd))
260                     {
261                         rc = handle_derived<l2_binding_cmds::unbind_cmd>(f_exp, f_act);
262                     }
263                     else if (typeid(*f_exp) == typeid(l2_binding_cmds::set_vtr_op_cmd))
264                     {
265                         rc = handle_derived<l2_binding_cmds::set_vtr_op_cmd>(f_exp, f_act);
266                     }
267                     else if (typeid(*f_exp) == typeid(vxlan_tunnel_cmds::create_cmd))
268                     {
269                         rc = handle_derived<vxlan_tunnel_cmds::create_cmd>(f_exp, f_act);
270                     }
271                     else if (typeid(*f_exp) == typeid(vxlan_tunnel_cmds::delete_cmd))
272                     {
273                         rc = handle_derived<vxlan_tunnel_cmds::delete_cmd>(f_exp, f_act);
274                     }
275                     else if (typeid(*f_exp) == typeid(sub_interface_cmds::create_cmd))
276                     {
277                         rc = handle_derived<sub_interface_cmds::create_cmd>(f_exp, f_act);
278                     }
279                     else if (typeid(*f_exp) == typeid(sub_interface_cmds::delete_cmd))
280                     {
281                         rc = handle_derived<sub_interface_cmds::delete_cmd>(f_exp, f_act);
282                     }
283                     else if (typeid(*f_exp) == typeid(ACL::list_cmds::l3_update_cmd))
284                     {
285                         rc = handle_derived<ACL::list_cmds::l3_update_cmd>(f_exp, f_act);
286                     }
287                     else if (typeid(*f_exp) == typeid(ACL::list_cmds::l3_delete_cmd))
288                     {
289                         rc = handle_derived<ACL::list_cmds::l3_delete_cmd>(f_exp, f_act);
290                     }
291                     else if (typeid(*f_exp) == typeid(ACL::binding_cmds::l3_bind_cmd))
292                     {
293                         rc = handle_derived<ACL::binding_cmds::l3_bind_cmd>(f_exp, f_act);
294                     }
295                     else if (typeid(*f_exp) == typeid(ACL::binding_cmds::l3_unbind_cmd))
296                     {
297                         rc = handle_derived<ACL::binding_cmds::l3_unbind_cmd>(f_exp, f_act);
298                     }
299                     else if (typeid(*f_exp) == typeid(ACL::list_cmds::l2_update_cmd))
300                     {
301                         rc = handle_derived<ACL::list_cmds::l2_update_cmd>(f_exp, f_act);
302                     }
303                     else if (typeid(*f_exp) == typeid(ACL::list_cmds::l2_delete_cmd))
304                     {
305                         rc = handle_derived<ACL::list_cmds::l2_delete_cmd>(f_exp, f_act);
306                     }
307                     else if (typeid(*f_exp) == typeid(ACL::binding_cmds::l2_bind_cmd))
308                     {
309                         rc = handle_derived<ACL::binding_cmds::l2_bind_cmd>(f_exp, f_act);
310                     }
311                     else if (typeid(*f_exp) == typeid(ACL::binding_cmds::l2_unbind_cmd))
312                     {
313                         rc = handle_derived<ACL::binding_cmds::l2_unbind_cmd>(f_exp, f_act);
314                     }
315                     else if (typeid(*f_exp) == typeid(arp_proxy_binding_cmds::bind_cmd))
316                     {
317                         rc = handle_derived<arp_proxy_binding_cmds::bind_cmd>(f_exp, f_act);
318                     }
319                     else if (typeid(*f_exp) == typeid(arp_proxy_binding_cmds::unbind_cmd))
320                     {
321                         rc = handle_derived<arp_proxy_binding_cmds::unbind_cmd>(f_exp, f_act);
322                     }
323                     else if (typeid(*f_exp) == typeid(arp_proxy_config_cmds::config_cmd))
324                     {
325                         rc = handle_derived<arp_proxy_config_cmds::config_cmd>(f_exp, f_act);
326                     }
327                     else if (typeid(*f_exp) == typeid(arp_proxy_config_cmds::unconfig_cmd))
328                     {
329                         rc = handle_derived<arp_proxy_config_cmds::unconfig_cmd>(f_exp, f_act);
330                     }
331                     else if (typeid(*f_exp) == typeid(ip_unnumbered_cmds::config_cmd))
332                     {
333                         rc = handle_derived<ip_unnumbered_cmds::config_cmd>(f_exp, f_act);
334                     }
335                     else if (typeid(*f_exp) == typeid(ip_unnumbered_cmds::unconfig_cmd))
336                     {
337                         rc = handle_derived<ip_unnumbered_cmds::unconfig_cmd>(f_exp, f_act);
338                     }
339                     else if (typeid(*f_exp) == typeid(ip6nd_ra_config::config_cmd))
340                     {
341                         rc = handle_derived<ip6nd_ra_config::config_cmd>(f_exp, f_act);
342                     }
343                     else if (typeid(*f_exp) == typeid(ip6nd_ra_config::unconfig_cmd))
344                     {
345                         rc = handle_derived<ip6nd_ra_config::unconfig_cmd>(f_exp, f_act);
346                     }
347                     else if (typeid(*f_exp) == typeid(ip6nd_ra_prefix::config_cmd))
348                     {
349                         rc = handle_derived<ip6nd_ra_prefix::config_cmd>(f_exp, f_act);
350                     }
351                     else if (typeid(*f_exp) == typeid(ip6nd_ra_prefix::unconfig_cmd))
352                     {
353                         rc = handle_derived<ip6nd_ra_prefix::unconfig_cmd>(f_exp, f_act);
354                     }
355                     else if (typeid(*f_exp) == typeid(interface_span_cmds::config_cmd))
356                     {
357                         rc = handle_derived<interface_span_cmds::config_cmd>(f_exp, f_act);
358                     }
359                     else if (typeid(*f_exp) == typeid(interface_span_cmds::unconfig_cmd))
360                     {
361                         rc = handle_derived<interface_span_cmds::unconfig_cmd>(f_exp, f_act);
362                     }
363                     else if (typeid(*f_exp) == typeid(nat_static_cmds::create_44_cmd))
364                     {
365                         rc = handle_derived<nat_static_cmds::create_44_cmd>(f_exp, f_act);
366                     }
367                     else if (typeid(*f_exp) == typeid(nat_static_cmds::delete_44_cmd))
368                     {
369                         rc = handle_derived<nat_static_cmds::delete_44_cmd>(f_exp, f_act);
370                     }
371                     else if (typeid(*f_exp) == typeid(nat_binding_cmds::bind_44_input_cmd))
372                     {
373                         rc = handle_derived<nat_binding_cmds::bind_44_input_cmd>(f_exp, f_act);
374                     }
375                     else if (typeid(*f_exp) == typeid(nat_binding_cmds::unbind_44_input_cmd))
376                     {
377                         rc = handle_derived<nat_binding_cmds::unbind_44_input_cmd>(f_exp, f_act);
378                     }
379                     else if (typeid(*f_exp) == typeid(interface_cmds::events_cmd))
380                     {
381                         rc = handle_derived<interface_cmds::events_cmd>(f_exp, f_act);
382                     }
383                     else
384                     {
385                         throw ExpException(2);
386                     }
387
388                     // if we get here then we found the match.
389                     m_exp_queue.erase(it_exp);
390                     m_act_queue.erase(it_act);
391                     delete f_exp;
392                     delete f_act;
393
394                     // return any injected failures to the agent
395                     if (rc_t::OK != rc && rc_t::NOOP != rc)
396                     {
397                         return (rc);
398                     }
399
400                     matched = true;
401                     break;
402                 }
403                 catch (ExpException &e)
404                 {
405                     // The expected and actual do not match
406                     if (m_strict_order)
407                     {
408                         // in strict ordering mode this is fatal, so rethrow
409                         throw e;
410                     }
411                     else
412                     {
413                         // move the iterator onto the next in the expected list and
414                         // check for a match
415                         ++it_exp;
416                     }
417                 }
418             }
419
420             if (!matched)
421                 throw ExpException(3);
422         }
423
424         return (rc);
425     }
426 private:
427
428     template <typename T>
429     rc_t handle_derived(const cmd *f_exp, cmd *f_act)
430     {
431         const T *i_exp;
432         T *i_act;
433
434         i_exp = dynamic_cast<const T*>(f_exp);
435         i_act = dynamic_cast<T*>(f_act);
436         if (!(*i_exp == *i_act))
437         {
438             throw ExpException(4);
439         }
440         // pass the data and return code to the agent
441         i_act->item() = i_exp->item();
442
443         return (i_act->item().rc());
444     }
445
446     // The Q to push the expectations on
447     std::deque<cmd*> m_exp_queue;
448
449     // the queue to push the actual events on
450     std::deque<cmd*> m_act_queue;
451
452     // control whether the expected queue is strictly ordered.
453     bool m_strict_order;
454 };
455
456 class VppInit {
457 public:
458     std::string name;
459     MockCmdQ *f;
460
461     VppInit()
462         : name("vpp-ut"),
463           f(new MockCmdQ())
464     {
465         HW::init(f);
466         OM::init();
467         logger().set(log_level_t::DEBUG);
468     }
469
470     ~VppInit() {
471         delete f;
472     }
473 };
474
475 BOOST_AUTO_TEST_SUITE(VppOM_test)
476
477 #define TRY_CHECK_RC(stmt)                    \
478 {                                             \
479     try {                                     \
480         BOOST_CHECK(rc_t::OK == stmt);        \
481     }                                         \
482     catch (ExpException &e)                   \
483     {                                         \
484         BOOST_CHECK(false);                   \
485     }                                         \
486     BOOST_CHECK(vi.f->is_empty());            \
487 }
488
489 #define TRY_CHECK(stmt)                       \
490 {                                             \
491     try {                                     \
492         stmt;                                 \
493     }                                         \
494     catch (ExpException &e)                   \
495     {                                         \
496         BOOST_CHECK(false);                   \
497     }                                         \
498     BOOST_CHECK(vi.f->is_empty());            \
499 }
500
501 #define ADD_EXPECT(stmt)                      \
502     vi.f->expect(new stmt)
503
504 #define STRICT_ORDER_OFF()                        \
505     vi.f->strict_order(false)
506
507 BOOST_AUTO_TEST_CASE(test_interface) {
508     VppInit vi;
509     const std::string go = "GeorgeOrwell";
510     const std::string js = "JohnSteinbeck";
511     rc_t rc = rc_t::OK;
512
513     /*
514      * George creates and deletes the interface
515      */
516     std::string itf1_name = "afpacket1";
517     interface itf1(itf1_name,
518                    interface::type_t::AFPACKET,
519                    interface::admin_state_t::UP);
520
521     /*
522      * set the expectation for a afpacket interface create.
523      *  2 is the interface handle VPP [mock] assigns
524      */
525     HW::item<handle_t> hw_ifh(2, rc_t::OK);
526     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
527
528     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
529     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
530
531     TRY_CHECK_RC(OM::write(go, itf1));
532
533     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
534     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
535     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
536
537     TRY_CHECK(OM::remove(go));
538
539     /*
540      * George creates the interface, then John brings it down.
541      * George's remove is a no-op, sice John also owns the interface
542      */
543     interface itf1b(itf1_name,
544                     interface::type_t::AFPACKET,
545                     interface::admin_state_t::DOWN);
546
547     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
548     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
549     TRY_CHECK_RC(OM::write(go, itf1));
550
551     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
552     TRY_CHECK_RC(OM::write(js, itf1b));
553
554     TRY_CHECK(OM::remove(go));
555
556     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
557     TRY_CHECK(OM::remove(js));
558
559     /*
560      * George adds an interface, then we flush all of Geroge's state
561      */
562     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
563     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
564     TRY_CHECK_RC(OM::write(go, itf1));
565
566     TRY_CHECK(OM::mark(go));
567
568     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
569     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
570     TRY_CHECK(OM::sweep(go));
571
572     /*
573      * George adds an interface. mark stale. update the same interface. sweep
574      * and expect no delete
575      */
576     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
577     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
578     TRY_CHECK_RC(OM::write(go, itf1b));
579
580     TRY_CHECK(OM::mark(go));
581
582     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
583     TRY_CHECK_RC(OM::write(go, itf1));
584
585     TRY_CHECK(OM::sweep(go));
586
587     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
588     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
589     TRY_CHECK(OM::remove(go));
590
591     /*
592      * George adds an insterface, then we mark that state. Add a second interface
593      * an flush the first that is now stale.
594      */
595     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
596     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
597     TRY_CHECK_RC(OM::write(go, itf1));
598
599     TRY_CHECK(OM::mark(go));
600
601     std::string itf2_name = "afpacket2";
602     interface itf2(itf2_name,
603                    interface::type_t::AFPACKET,
604                    interface::admin_state_t::UP);
605     HW::item<handle_t> hw_ifh2(3, rc_t::OK);
606
607     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf2_name));
608     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh2));
609     TRY_CHECK_RC(OM::write(go, itf2));
610
611     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
612     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
613     TRY_CHECK(OM::sweep(go));
614
615     TRY_CHECK(OM::mark(go));
616
617     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh2));
618     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf2_name));
619     TRY_CHECK(OM::sweep(go));
620 }
621
622 BOOST_AUTO_TEST_CASE(test_bvi) {
623     VppInit vi;
624     const std::string ernest = "ErnestHemmingway";
625     const std::string graham = "GrahamGreene";
626     rc_t rc = rc_t::OK;
627     l3_binding *l3;
628
629     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP,
630                                                 rc_t::OK);
631     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN,
632                                                   rc_t::OK);
633
634     /*
635      * Enrest creates a BVI with address 10.10.10.10/24
636      */
637     route::prefix_t pfx_10("10.10.10.10", 24);
638
639     const std::string bvi_name = "bvi1";
640     interface itf(bvi_name,
641                   interface::type_t::BVI,
642                   interface::admin_state_t::UP);
643     HW::item<handle_t> hw_ifh(4, rc_t::OK);
644     HW::item<route::prefix_t> hw_pfx_10(pfx_10, rc_t::OK);
645
646     ADD_EXPECT(interface_cmds::loopback_create_cmd(hw_ifh, bvi_name));
647     ADD_EXPECT(interface_cmds::set_tag(hw_ifh, bvi_name));
648     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
649     TRY_CHECK_RC(OM::write(ernest, itf));
650
651     l3 = new l3_binding(itf, pfx_10);
652     HW::item<bool> hw_l3_bind(true, rc_t::OK);
653     HW::item<bool> hw_l3_unbind(false, rc_t::OK);
654     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind, hw_ifh.data(), pfx_10));
655     TRY_CHECK_RC(OM::write(ernest, *l3));
656
657     // change the MAC address on the BVI
658     interface itf_new_mac(bvi_name,
659                           interface::type_t::BVI,
660                           interface::admin_state_t::UP);
661     l2_address_t l2_addr({0,1,2,3,4,5});
662     HW::item<l2_address_t> hw_mac(l2_addr, rc_t::OK);
663     itf_new_mac.set(l2_addr);
664     ADD_EXPECT(interface_cmds::set_mac_cmd(hw_mac, hw_ifh));
665     TRY_CHECK_RC(OM::write(ernest, itf_new_mac));
666
667     // create/write the interface to the OM again but with an unset MAC
668     // this should not generate a MAC address update
669     TRY_CHECK_RC(OM::write(ernest, itf));
670
671     // change the MAC address on the BVI - again
672     interface itf_new_mac2(bvi_name,
673                            interface::type_t::BVI,
674                            interface::admin_state_t::UP);
675     l2_address_t l2_addr2({0,1,2,3,4,6});
676     HW::item<l2_address_t> hw_mac2(l2_addr2, rc_t::OK);
677     itf_new_mac2.set(l2_addr2);
678     ADD_EXPECT(interface_cmds::set_mac_cmd(hw_mac2, hw_ifh));
679     TRY_CHECK_RC(OM::write(ernest, itf_new_mac2));
680
681     delete l3;
682     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind, hw_ifh.data(), pfx_10));
683     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
684     ADD_EXPECT(interface_cmds::loopback_delete_cmd(hw_ifh));
685     TRY_CHECK(OM::remove(ernest));
686
687     /*
688      * Graham creates a BVI with address 10.10.10.10/24 in Routing Domain
689      */
690     route_domain rd(1);
691     HW::item<bool> hw_rd4_create(true, rc_t::OK);
692     HW::item<bool> hw_rd4_delete(false, rc_t::OK);
693     HW::item<bool> hw_rd6_create(true, rc_t::OK);
694     HW::item<bool> hw_rd6_delete(false, rc_t::OK);
695     HW::item<route::table_id_t> hw_rd4_bind(1, rc_t::OK);
696     HW::item<route::table_id_t> hw_rd4_unbind(route::DEFAULT_TABLE, rc_t::OK);
697     HW::item<route::table_id_t> hw_rd6_bind(1, rc_t::OK);
698     HW::item<route::table_id_t> hw_rd6_unbind(route::DEFAULT_TABLE, rc_t::OK);
699     ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd4_create, l3_proto_t::IPV4, 1));
700     ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd6_create, l3_proto_t::IPV6, 1));
701     TRY_CHECK_RC(OM::write(graham, rd));
702
703     const std::string bvi2_name = "bvi2";
704     interface *itf2 = new interface(bvi2_name,
705                                     interface::type_t::BVI,
706                                     interface::admin_state_t::UP,
707                                     rd);
708     HW::item<handle_t> hw_ifh2(5, rc_t::OK);
709
710     ADD_EXPECT(interface_cmds::loopback_create_cmd(hw_ifh2, bvi2_name));
711     ADD_EXPECT(interface_cmds::set_tag(hw_ifh2, bvi2_name));
712     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh2));
713     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd4_bind, l3_proto_t::IPV4, hw_ifh2));
714     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd6_bind, l3_proto_t::IPV6, hw_ifh2));
715
716     TRY_CHECK_RC(OM::write(graham, *itf2));
717
718     l3 = new l3_binding(*itf2, pfx_10);
719     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind, hw_ifh2.data(), pfx_10));
720     TRY_CHECK_RC(OM::write(graham, *l3));
721
722     delete l3;
723     delete itf2;
724
725     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind, hw_ifh2.data(), pfx_10));
726     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd4_unbind, l3_proto_t::IPV4, hw_ifh2));
727     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd6_unbind, l3_proto_t::IPV6, hw_ifh2));
728     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh2));
729     ADD_EXPECT(interface_cmds::loopback_delete_cmd(hw_ifh2));
730     ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd4_delete, l3_proto_t::IPV4, 1));
731     ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd6_delete, l3_proto_t::IPV6, 1));
732     TRY_CHECK(OM::remove(graham));
733 }
734
735 BOOST_AUTO_TEST_CASE(test_bridge) {
736     VppInit vi;
737     const std::string franz = "FranzKafka";
738     const std::string dante = "Dante";
739     const std::string jkr = "jkrowling";
740     rc_t rc = rc_t::OK;
741
742     /*
743      * Franz creates an interface, Bridge-domain, then binds the two
744      */
745
746     // interface create
747     std::string itf1_name = "afpacket1";
748     interface itf1(itf1_name,
749                    interface::type_t::AFPACKET,
750                    interface::admin_state_t::UP);
751
752     HW::item<handle_t> hw_ifh(3, rc_t::OK);
753     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP,
754                                                 rc_t::OK);
755     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
756     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
757
758     TRY_CHECK_RC(OM::write(franz, itf1));
759
760     // bridge-domain create
761     bridge_domain bd1(33);
762
763     HW::item<uint32_t> hw_bd(33, rc_t::OK);
764     ADD_EXPECT(bridge_domain_cmds::create_cmd(hw_bd, bridge_domain::learning_mode_t::ON));
765
766     TRY_CHECK_RC(OM::write(franz, bd1));
767
768     // L2-interface create and bind
769     // this needs to be delete'd before the flush below, since it too maintains
770     // references to the BD and Interface
771     l2_binding *l2itf = new l2_binding(itf1, bd1);
772     HW::item<bool> hw_l2_bind(true, rc_t::OK);
773
774     ADD_EXPECT(l2_binding_cmds::bind_cmd(hw_l2_bind, hw_ifh.data(), hw_bd.data(), false));
775     TRY_CHECK_RC(OM::write(franz, *l2itf));
776
777     /*
778      * Dante adds an interface to the same BD
779      */
780     std::string itf2_name = "afpacket2";
781     interface itf2(itf2_name,
782                    interface::type_t::AFPACKET,
783                    interface::admin_state_t::UP);
784
785     HW::item<handle_t> hw_ifh2(4, rc_t::OK);
786     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf2_name));
787     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh2));
788     TRY_CHECK_RC(OM::write(dante, itf2));
789
790     // BD add is a no-op since it exists
791     TRY_CHECK_RC(OM::write(dante, bd1));
792
793     l2_binding *l2itf2 = new l2_binding(itf2, bd1);
794     HW::item<l2_binding::l2_vtr_op_t> hw_set_vtr(l2_binding::l2_vtr_op_t::L2_VTR_POP_1, rc_t::OK);
795     l2itf2->set(l2_binding::l2_vtr_op_t::L2_VTR_POP_1, 68);
796
797     ADD_EXPECT(l2_binding_cmds::bind_cmd(hw_l2_bind, hw_ifh2.data(), hw_bd.data(), false));
798     ADD_EXPECT(l2_binding_cmds::set_vtr_op_cmd(hw_set_vtr, hw_ifh2.data(), 68));
799     TRY_CHECK_RC(OM::write(dante, *l2itf2));
800
801     // Add some static entries to the bridge-domain
802     HW::item<bool> hw_be1(true, rc_t::OK);
803     mac_address_t mac1({0,1,2,3,4,5});
804     bridge_domain_entry *be1 = new bridge_domain_entry(bd1, mac1, itf2);
805     ADD_EXPECT(bridge_domain_entry_cmds::create_cmd(hw_be1, mac1, bd1.id(), hw_ifh2.data(),
806                                                     false));
807     TRY_CHECK_RC(OM::write(dante, *be1));
808
809     // Add some entries to the bridge-domain ARP termination table
810     HW::item<bool> hw_bea1(true, rc_t::OK);
811     boost::asio::ip::address ip1 = boost::asio::ip::address::from_string("10.10.10.10");
812
813     bridge_domain_arp_entry *bea1 = new bridge_domain_arp_entry(bd1, ip1, mac1);
814     ADD_EXPECT(bridge_domain_arp_entry_cmds::create_cmd(hw_be1, bd1.id(), mac1, ip1));
815     TRY_CHECK_RC(OM::write(dante, *bea1));
816
817     // flush Franz's state
818     delete l2itf;
819     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN,
820                                                   rc_t::OK);
821     ADD_EXPECT(l2_binding_cmds::unbind_cmd(hw_l2_bind, hw_ifh.data(), hw_bd.data(), false));
822     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
823     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
824     TRY_CHECK(OM::remove(franz));
825
826     // flush Dante's state - the order the interface and BD are deleted
827     // is an uncontrollable artifact of the C++ object destruction.
828     delete l2itf2;
829     delete be1;
830     delete bea1;
831     STRICT_ORDER_OFF();
832     ADD_EXPECT(bridge_domain_arp_entry_cmds::delete_cmd(hw_be1, bd1.id(), mac1, ip1));
833     ADD_EXPECT(bridge_domain_entry_cmds::delete_cmd(hw_be1, mac1, bd1.id(), false));
834     ADD_EXPECT(l2_binding_cmds::unbind_cmd(hw_l2_bind, hw_ifh2.data(), hw_bd.data(), false));
835
836     ADD_EXPECT(bridge_domain_cmds::delete_cmd(hw_bd));
837     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh2));
838     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf2_name));
839     TRY_CHECK(OM::remove(dante));
840
841     // test the BVI entry in l2fib
842     bridge_domain bd2(99);
843
844     HW::item<uint32_t> hw_bd2(99, rc_t::OK);
845     ADD_EXPECT(bridge_domain_cmds::create_cmd(hw_bd2, bridge_domain::learning_mode_t::ON));
846
847     TRY_CHECK_RC(OM::write(jkr, bd2));
848
849     std::string itf3_name = "bvi";
850     interface itf3(itf3_name,
851                    interface::type_t::BVI,
852                    interface::admin_state_t::UP);
853
854     HW::item<handle_t> hw_ifh3(5, rc_t::OK);
855     ADD_EXPECT(interface_cmds::loopback_create_cmd(hw_ifh3, itf3_name));
856     ADD_EXPECT(interface_cmds::set_tag(hw_ifh3, itf3_name));
857     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh3));
858     TRY_CHECK_RC(OM::write(jkr, itf3));
859
860     l2_binding *l2itf3 = new l2_binding(itf3, bd2);
861     ADD_EXPECT(l2_binding_cmds::bind_cmd(hw_l2_bind, hw_ifh3.data(), hw_bd2.data(), true));
862     TRY_CHECK_RC(OM::write(jkr, *l2itf3));
863
864     HW::item<bool> hw_be2(true, rc_t::OK);
865     mac_address_t mac2({0,1,2,3,4,5});
866     bridge_domain_entry *be2 = new bridge_domain_entry(bd2, mac2, itf3);
867     ADD_EXPECT(bridge_domain_entry_cmds::create_cmd(hw_be2, mac2, bd2.id(), hw_ifh3.data(), true));
868     TRY_CHECK_RC(OM::write(jkr, *be2));
869
870     delete l2itf3;
871     delete be2;
872     STRICT_ORDER_OFF();
873     ADD_EXPECT(l2_binding_cmds::unbind_cmd(hw_l2_bind, hw_ifh3.data(), hw_bd2.data(), true));
874     ADD_EXPECT(bridge_domain_entry_cmds::delete_cmd(hw_be2, mac2, bd2.id(), true));
875     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh3));
876     ADD_EXPECT(interface_cmds::loopback_delete_cmd(hw_ifh3));
877     ADD_EXPECT(bridge_domain_cmds::delete_cmd(hw_bd2));
878     TRY_CHECK(OM::remove(jkr));
879 }
880
881 BOOST_AUTO_TEST_CASE(test_vxlan) {
882     VppInit vi;
883     const std::string franz = "FranzKafka";
884     rc_t rc = rc_t::OK;
885
886     /*
887      * Franz creates an interface, Bridge-domain, then binds the two
888      */
889
890     // VXLAN create
891     vxlan_tunnel::endpoint_t ep(boost::asio::ip::address::from_string("10.10.10.10"),
892                                boost::asio::ip::address::from_string("10.10.10.11"),
893                                322);
894
895     vxlan_tunnel vxt(ep.src, ep.dst, ep.vni);
896
897     HW::item<handle_t> hw_vxt(3, rc_t::OK);
898     ADD_EXPECT(vxlan_tunnel_cmds::create_cmd(hw_vxt, "don't-care", ep));
899
900     TRY_CHECK_RC(OM::write(franz, vxt));
901
902     // bridge-domain create
903     bridge_domain bd1(33, bridge_domain::learning_mode_t::OFF);
904
905     HW::item<uint32_t> hw_bd(33, rc_t::OK);
906     ADD_EXPECT(bridge_domain_cmds::create_cmd(hw_bd, bridge_domain::learning_mode_t::OFF));
907
908     TRY_CHECK_RC(OM::write(franz, bd1));
909
910     // L2-interface create and bind
911     // this needs to be delete'd before the flush below, since it too maintains
912     // references to the BD and Interface
913     l2_binding *l2itf = new l2_binding(vxt, bd1);
914     HW::item<bool> hw_l2_bind(true, rc_t::OK);
915
916     ADD_EXPECT(l2_binding_cmds::bind_cmd(hw_l2_bind, hw_vxt.data(), hw_bd.data(), false));
917     TRY_CHECK_RC(OM::write(franz, *l2itf));
918
919     // flush Franz's state
920     delete l2itf;
921     HW::item<handle_t> hw_vxtdel(3, rc_t::NOOP);
922     STRICT_ORDER_OFF();
923     ADD_EXPECT(l2_binding_cmds::unbind_cmd(hw_l2_bind, hw_vxt.data(), hw_bd.data(), false));
924     ADD_EXPECT(bridge_domain_cmds::delete_cmd(hw_bd));
925     ADD_EXPECT(vxlan_tunnel_cmds::delete_cmd(hw_vxtdel, ep));
926     TRY_CHECK(OM::remove(franz));
927 }
928
929 BOOST_AUTO_TEST_CASE(test_vlan) {
930     VppInit vi;
931     const std::string noam = "NoamChomsky";
932     rc_t rc = rc_t::OK;
933
934     std::string itf1_name = "host1";
935     interface itf1(itf1_name,
936                    interface::type_t::AFPACKET,
937                    interface::admin_state_t::UP);
938
939     HW::item<handle_t> hw_ifh(2, rc_t::OK);
940     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
941
942     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
943     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
944
945     TRY_CHECK_RC(OM::write(noam, itf1));
946
947     sub_interface *vl33 = new sub_interface(itf1,
948                                             interface::admin_state_t::UP,
949                                             33);
950
951     HW::item<handle_t> hw_vl33(3, rc_t::OK);
952     ADD_EXPECT(sub_interface_cmds::create_cmd(hw_vl33, itf1_name+".33", hw_ifh.data(), 33));
953     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_vl33));
954
955     TRY_CHECK_RC(OM::write(noam, *vl33));
956
957     delete vl33;
958     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
959     HW::item<handle_t> hw_vl33_down(3, rc_t::NOOP);
960     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_vl33));
961     ADD_EXPECT(sub_interface_cmds::delete_cmd(hw_vl33_down));
962     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
963     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
964
965     TRY_CHECK(OM::remove(noam));
966 }
967
968 BOOST_AUTO_TEST_CASE(test_acl) {
969     VppInit vi;
970     const std::string fyodor = "FyodorDostoyevsky";
971     const std::string leo = "LeoTolstoy";
972     rc_t rc = rc_t::OK;
973
974     /*
975      * Fyodor adds an ACL in the input direction
976      */
977     std::string itf1_name = "host1";
978     interface itf1(itf1_name,
979                    interface::type_t::AFPACKET,
980                    interface::admin_state_t::UP);
981     HW::item<handle_t> hw_ifh(2, rc_t::OK);
982     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
983     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
984     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
985     TRY_CHECK_RC(OM::write(fyodor, itf1));
986
987     route::prefix_t src("10.10.10.10", 32);
988     ACL::l3_rule r1(10, ACL::action_t::PERMIT, src, route::prefix_t::ZERO);
989     ACL::l3_rule r2(20, ACL::action_t::DENY, route::prefix_t::ZERO, route::prefix_t::ZERO);
990
991     std::string acl_name = "acl1";
992     ACL::l3_list acl1(acl_name);
993     acl1.insert(r2);
994     acl1.insert(r1);
995     ACL::l3_list::rules_t rules = {r1, r2};
996
997     HW::item<handle_t> hw_acl(2, rc_t::OK);
998     ADD_EXPECT(ACL::list_cmds::l3_update_cmd(hw_acl, acl_name, rules));
999     TRY_CHECK_RC(OM::write(fyodor, acl1));
1000
1001     ACL::l3_binding *l3b = new ACL::l3_binding(direction_t::INPUT, itf1, acl1);
1002     HW::item<bool> hw_binding(true, rc_t::OK);
1003     ADD_EXPECT(ACL::binding_cmds::l3_bind_cmd(hw_binding, direction_t::INPUT,
1004                                          hw_ifh.data(), hw_acl.data()));
1005     TRY_CHECK_RC(OM::write(fyodor, *l3b));
1006
1007     /**
1008      * Leo adds an L2 ACL in the output direction
1009      */
1010     TRY_CHECK_RC(OM::write(leo, itf1));
1011
1012     std::string l2_acl_name = "l2_acl1";
1013     mac_address_t mac({0x0, 0x0, 0x1, 0x2, 0x3, 0x4});
1014     mac_address_t mac_mask({0xff, 0xff, 0xff, 0x0, 0x0, 0x0});
1015     ACL::l2_rule l2_r1(10, ACL::action_t::PERMIT, src, mac, mac_mask);
1016     ACL::l2_rule l2_r2(20, ACL::action_t::DENY, src, {}, {});
1017
1018     ACL::l2_list l2_acl(l2_acl_name);
1019     l2_acl.insert(l2_r2);
1020     l2_acl.insert(l2_r1);
1021
1022     ACL::l2_list::rules_t l2_rules = {l2_r1, l2_r2};
1023
1024     HW::item<handle_t> l2_hw_acl(3, rc_t::OK);
1025     ADD_EXPECT(ACL::list_cmds::l2_update_cmd(l2_hw_acl, l2_acl_name, l2_rules));
1026     TRY_CHECK_RC(OM::write(leo, l2_acl));
1027
1028     ACL::l2_binding *l2b = new ACL::l2_binding(direction_t::OUTPUT, itf1, l2_acl);
1029     HW::item<bool> l2_hw_binding(true, rc_t::OK);
1030     ADD_EXPECT(ACL::binding_cmds::l2_bind_cmd(l2_hw_binding, direction_t::OUTPUT,
1031                                        hw_ifh.data(), l2_hw_acl.data()));
1032     TRY_CHECK_RC(OM::write(leo, *l2b));
1033
1034     delete l2b;
1035     ADD_EXPECT(ACL::binding_cmds::l2_unbind_cmd(l2_hw_binding, direction_t::OUTPUT,
1036                                                 hw_ifh.data(), l2_hw_acl.data()));
1037     ADD_EXPECT(ACL::list_cmds::l2_delete_cmd(l2_hw_acl));
1038     TRY_CHECK(OM::remove(leo));
1039
1040     delete l3b;
1041     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN,
1042                                                   rc_t::OK);
1043     STRICT_ORDER_OFF();
1044     ADD_EXPECT(ACL::binding_cmds::l3_unbind_cmd(hw_binding, direction_t::INPUT,
1045                                          hw_ifh.data(), hw_acl.data()));
1046     ADD_EXPECT(ACL::list_cmds::l3_delete_cmd(hw_acl));
1047     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
1048     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
1049
1050     TRY_CHECK(OM::remove(fyodor));
1051 }
1052
1053 BOOST_AUTO_TEST_CASE(test_arp_proxy) {
1054     VppInit vi;
1055     const std::string kurt = "KurtVonnegut";
1056     rc_t rc = rc_t::OK;
1057
1058     asio::ip::address_v4 low  = asio::ip::address_v4::from_string("10.0.0.0");
1059     asio::ip::address_v4 high = asio::ip::address_v4::from_string("10.0.0.255");
1060
1061     arp_proxy_config ap(low, high);
1062     HW::item<bool> hw_ap_cfg(true, rc_t::OK);
1063     ADD_EXPECT(arp_proxy_config_cmds::config_cmd(hw_ap_cfg, low, high));
1064     TRY_CHECK_RC(OM::write(kurt, ap));
1065
1066     std::string itf3_name = "host3";
1067     interface itf3(itf3_name,
1068                    interface::type_t::AFPACKET,
1069                    interface::admin_state_t::UP);
1070     HW::item<handle_t> hw_ifh(2, rc_t::OK);
1071     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
1072     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf3_name));
1073     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
1074     TRY_CHECK_RC(OM::write(kurt, itf3));
1075
1076     arp_proxy_binding *apb = new arp_proxy_binding(itf3, ap);
1077     HW::item<bool> hw_binding(true, rc_t::OK);
1078     ADD_EXPECT(arp_proxy_binding_cmds::bind_cmd(hw_binding, hw_ifh.data()));
1079     TRY_CHECK_RC(OM::write(kurt, *apb));
1080
1081     delete apb;
1082
1083     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN,
1084                                                   rc_t::OK);
1085     STRICT_ORDER_OFF();
1086     ADD_EXPECT(arp_proxy_binding_cmds::unbind_cmd(hw_binding, hw_ifh.data()));
1087     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
1088     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf3_name));
1089     ADD_EXPECT(arp_proxy_config_cmds::unconfig_cmd(hw_ap_cfg, low, high));
1090
1091     TRY_CHECK(OM::remove(kurt));
1092 }
1093
1094 BOOST_AUTO_TEST_CASE(test_ip_unnumbered) {
1095     VppInit vi;
1096     const std::string eric = "EricAmbler";
1097     rc_t rc = rc_t::OK;
1098
1099     /*
1100      * Interface 1 has the L3 address
1101      */
1102     std::string itf1_name = "host1";
1103     interface itf1(itf1_name,
1104                    interface::type_t::AFPACKET,
1105                    interface::admin_state_t::UP);
1106     HW::item<handle_t> hw_ifh(2, rc_t::OK);
1107     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
1108     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
1109     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
1110     TRY_CHECK_RC(OM::write(eric, itf1));
1111
1112     route::prefix_t pfx_10("10.10.10.10", 24);
1113     l3_binding *l3 = new l3_binding(itf1, pfx_10);
1114     HW::item<bool> hw_l3_bind(true, rc_t::OK);
1115     HW::item<bool> hw_l3_unbind(false, rc_t::OK);
1116     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind, hw_ifh.data(), pfx_10));
1117     TRY_CHECK_RC(OM::write(eric, *l3));
1118
1119     /*
1120      * Interface 2 is unnumbered
1121      */
1122     std::string itf2_name = "host2";
1123     interface itf2(itf2_name,
1124                    interface::type_t::AFPACKET,
1125                    interface::admin_state_t::UP);
1126
1127     HW::item<handle_t> hw_ifh2(4, rc_t::OK);
1128     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf2_name));
1129     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh2));
1130     TRY_CHECK_RC(OM::write(eric, itf2));
1131
1132     ip_unnumbered *ipun = new ip_unnumbered(itf2, itf1);
1133     HW::item<bool> hw_ip_cfg(true, rc_t::OK);
1134     HW::item<bool> hw_ip_uncfg(false, rc_t::OK);
1135     ADD_EXPECT(ip_unnumbered_cmds::config_cmd(hw_ip_cfg, hw_ifh2.data(), hw_ifh.data()));
1136     TRY_CHECK_RC(OM::write(eric, *ipun));
1137
1138     delete l3;
1139     delete ipun;
1140
1141     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
1142     STRICT_ORDER_OFF();
1143     ADD_EXPECT(ip_unnumbered_cmds::unconfig_cmd(hw_ip_uncfg, hw_ifh2.data(), hw_ifh.data()));
1144     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind, hw_ifh.data(), pfx_10));
1145     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh2));
1146     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf2_name));
1147     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
1148     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
1149
1150     TRY_CHECK(OM::remove(eric));
1151 }
1152
1153 BOOST_AUTO_TEST_CASE(test_ip6nd) {
1154     VppInit vi;
1155     const std::string paulo = "PauloCoelho";
1156     rc_t rc = rc_t::OK;
1157
1158     /*
1159      * ra config
1160      */
1161     std::string itf_name = "host_ip6nd";
1162     interface itf(itf_name,
1163                    interface::type_t::AFPACKET,
1164                    interface::admin_state_t::UP);
1165     HW::item<handle_t> hw_ifh(3, rc_t::OK);
1166     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
1167     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf_name));
1168     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
1169     TRY_CHECK_RC(OM::write(paulo, itf));
1170
1171     route::prefix_t pfx_10("fd8f:69d8:c12c:ca62::3", 128);
1172     l3_binding *l3 = new l3_binding(itf, pfx_10);
1173     HW::item<bool> hw_l3_bind(true, rc_t::OK);
1174     HW::item<bool> hw_l3_unbind(false, rc_t::OK);
1175     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind, hw_ifh.data(), pfx_10));
1176     TRY_CHECK_RC(OM::write(paulo, *l3));
1177
1178     ra_config ra(0, 1, 0, 4);
1179     ip6nd_ra_config *ip6ra = new ip6nd_ra_config(itf, ra);
1180     HW::item<bool> hw_ip6nd_ra_config_config(true, rc_t::OK);
1181     HW::item<bool> hw_ip6nd_ra_config_unconfig(false, rc_t::OK);
1182     ADD_EXPECT(ip6nd_ra_config::config_cmd(hw_ip6nd_ra_config_config, hw_ifh.data(), ra));
1183     TRY_CHECK_RC(OM::write(paulo, *ip6ra));
1184
1185     /*
1186      * ra prefix
1187      */
1188     ra_prefix ra_pfx(pfx_10, 0, 0, 2592000, 604800);
1189     ip6nd_ra_prefix *ip6pfx = new ip6nd_ra_prefix(itf, ra_pfx);
1190     HW::item<bool> hw_ip6nd_ra_prefix_config(true, rc_t::OK);
1191     HW::item<bool> hw_ip6nd_ra_prefix_unconfig(false, rc_t::OK);
1192     ADD_EXPECT(ip6nd_ra_prefix::config_cmd(hw_ip6nd_ra_prefix_config, hw_ifh.data(), ra_pfx));
1193     TRY_CHECK_RC(OM::write(paulo, *ip6pfx));
1194
1195     delete ip6pfx;
1196
1197     ADD_EXPECT(ip6nd_ra_prefix::unconfig_cmd(hw_ip6nd_ra_prefix_unconfig, hw_ifh.data(), ra_pfx));
1198
1199     delete ip6ra;
1200     delete l3;
1201
1202     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
1203
1204     STRICT_ORDER_OFF();
1205     ADD_EXPECT(ip6nd_ra_config::unconfig_cmd(hw_ip6nd_ra_config_unconfig, hw_ifh.data(), ra));
1206     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind, hw_ifh.data(), pfx_10));
1207     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
1208     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf_name));
1209
1210     TRY_CHECK(OM::remove(paulo));
1211 }
1212
1213 BOOST_AUTO_TEST_CASE(test_interface_span) {
1214     VppInit vi;
1215     const std::string elif = "ElifShafak";
1216     rc_t rc = rc_t::OK;
1217
1218     /*
1219      * Interface 1 to be mirrored
1220      */
1221     std::string itf1_name = "port-from";
1222     interface itf1(itf1_name,
1223                    interface::type_t::AFPACKET,
1224                    interface::admin_state_t::UP);
1225     HW::item<handle_t> hw_ifh(2, rc_t::OK);
1226     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
1227     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
1228     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
1229     TRY_CHECK_RC(OM::write(elif, itf1));
1230
1231     /*
1232      * Interface 2 where traffic is mirrored
1233      */
1234     std::string itf2_name = "port-to";
1235     interface itf2(itf2_name,
1236                    interface::type_t::AFPACKET,
1237                    interface::admin_state_t::UP);
1238
1239     HW::item<handle_t> hw_ifh2(4, rc_t::OK);
1240     HW::item<interface::admin_state_t> hw_as_up2(interface::admin_state_t::UP, rc_t::OK);
1241
1242     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf2_name));
1243     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up2, hw_ifh2));
1244     TRY_CHECK_RC(OM::write(elif, itf2));
1245
1246     interface_span *itf_span = new interface_span(itf1, itf2, interface_span::state_t::TX_RX_ENABLED);
1247     HW::item<bool> hw_is_cfg(true, rc_t::OK);
1248     HW::item<bool> hw_is_uncfg(true, rc_t::OK);
1249     ADD_EXPECT(interface_span_cmds::config_cmd(hw_is_cfg, hw_ifh.data(), hw_ifh2.data(), interface_span::state_t::TX_RX_ENABLED));
1250     TRY_CHECK_RC(OM::write(elif, *itf_span));
1251
1252     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
1253     HW::item<interface::admin_state_t> hw_as_down2(interface::admin_state_t::DOWN, rc_t::OK);
1254
1255     delete itf_span;
1256     STRICT_ORDER_OFF();
1257     ADD_EXPECT(interface_span_cmds::unconfig_cmd(hw_is_uncfg, hw_ifh.data(), hw_ifh2.data()));
1258     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
1259     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
1260     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down2, hw_ifh2));
1261     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf2_name));
1262
1263     TRY_CHECK(OM::remove(elif));
1264 }
1265
1266 BOOST_AUTO_TEST_CASE(test_routing) {
1267     VppInit vi;
1268     const std::string ian = "IanFleming";
1269     rc_t rc = rc_t::OK;
1270
1271     /*
1272      * non-default route domain
1273      */
1274     route_domain rd4(1);
1275     HW::item<bool> hw_rd4_create(true, rc_t::OK);
1276     HW::item<bool> hw_rd4_delete(false, rc_t::OK);
1277     HW::item<bool> hw_rd6_create(true, rc_t::OK);
1278     HW::item<bool> hw_rd6_delete(false, rc_t::OK);
1279     HW::item<route::table_id_t> hw_rd4_bind(1, rc_t::OK);
1280     HW::item<route::table_id_t> hw_rd4_unbind(route::DEFAULT_TABLE, rc_t::OK);
1281     HW::item<route::table_id_t> hw_rd6_bind(1, rc_t::OK);
1282     HW::item<route::table_id_t> hw_rd7_unbind(route::DEFAULT_TABLE, rc_t::OK);
1283     ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd4_create, l3_proto_t::IPV4, 1));
1284     ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd6_create, l3_proto_t::IPV6, 1));
1285     TRY_CHECK_RC(OM::write(ian, rd4));
1286
1287     /*
1288      * a couple of interfaces
1289      */
1290     std::string itf1_name = "af1";
1291     interface itf1(itf1_name,
1292                    interface::type_t::AFPACKET,
1293                    interface::admin_state_t::UP);
1294     HW::item<handle_t> hw_ifh(2, rc_t::OK);
1295     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
1296     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
1297     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
1298     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
1299     TRY_CHECK_RC(OM::write(ian, itf1));
1300
1301     std::string itf2_name = "af2";
1302     interface *itf2 = new interface(itf2_name,
1303                                     interface::type_t::AFPACKET,
1304                                     interface::admin_state_t::UP,
1305                                     rd4);
1306
1307     HW::item<handle_t> hw_ifh2(4, rc_t::OK);
1308     HW::item<interface::admin_state_t> hw_as_up2(interface::admin_state_t::UP, rc_t::OK);
1309     HW::item<interface::admin_state_t> hw_as_down2(interface::admin_state_t::DOWN, rc_t::OK);
1310     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf2_name));
1311     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up2, hw_ifh2));
1312     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd4_bind, l3_proto_t::IPV4, hw_ifh2));
1313     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd6_bind, l3_proto_t::IPV6, hw_ifh2));
1314     TRY_CHECK_RC(OM::write(ian, *itf2));
1315
1316     /*
1317      * prefix on each interface
1318      */
1319     route::prefix_t pfx_10("10.10.10.10", 24);
1320     l3_binding *l3_10 = new l3_binding(itf1, pfx_10);
1321     HW::item<bool> hw_l3_10_bind(true, rc_t::OK);
1322     HW::item<bool> hw_l3_10_unbind(false, rc_t::OK);
1323     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_10_bind, hw_ifh.data(), pfx_10));
1324     TRY_CHECK_RC(OM::write(ian, *l3_10));
1325     route::prefix_t pfx_11("11.11.11.11", 24);
1326     l3_binding *l3_11 = new l3_binding(*itf2, pfx_11);
1327     HW::item<bool> hw_l3_11_bind(true, rc_t::OK);
1328     HW::item<bool> hw_l3_11_unbind(false, rc_t::OK);
1329     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_11_bind, hw_ifh2.data(), pfx_11));
1330     TRY_CHECK_RC(OM::write(ian, *l3_11));
1331
1332     /*
1333      * A route via interface 1 in the default table
1334      */
1335     route::prefix_t pfx_5("5.5.5.5", 32);
1336     boost::asio::ip::address nh_10 = boost::asio::ip::address::from_string("10.10.10.11");
1337     route::path *path_10 = new route::path(nh_10, itf1);
1338     route::ip_route *route_5 = new route::ip_route(pfx_5);
1339     route_5->add(*path_10);
1340     HW::item<bool> hw_route_5(true, rc_t::OK);
1341     ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_5, 0, pfx_5, {*path_10}));
1342     TRY_CHECK_RC(OM::write(ian, *route_5));
1343
1344     /*
1345      * A route via interface 2 in the non-default table
1346      */
1347     boost::asio::ip::address nh_11 = boost::asio::ip::address::from_string("11.11.11.10");
1348     route::path *path_11 = new route::path(nh_11, *itf2);
1349     route::ip_route *route_5_2 = new route::ip_route(rd4, pfx_5);
1350     route_5_2->add(*path_11);
1351     HW::item<bool> hw_route_5_2(true, rc_t::OK);
1352     ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_5_2, 1, pfx_5, {*path_11}));
1353     TRY_CHECK_RC(OM::write(ian, *route_5_2));
1354
1355     /*
1356      * An ARP entry for the neighbour on itf1
1357      */
1358     HW::item<bool> hw_neighbour(true, rc_t::OK);
1359     mac_address_t mac_n({0,1,2,4,5,6});
1360     neighbour *ne = new neighbour(itf1, nh_10, mac_n);
1361     ADD_EXPECT(neighbour_cmds::create_cmd(hw_neighbour, hw_ifh.data(), mac_n, nh_10));
1362     TRY_CHECK_RC(OM::write(ian, *ne));
1363
1364     /*
1365      * A DVR route
1366      */
1367     route::prefix_t pfx_6("6.6.6.6", 32);
1368     route::path *path_l2 = new route::path(*itf2, nh_proto_t::ETHERNET);
1369     route::ip_route *route_dvr = new route::ip_route(pfx_6);
1370     route_dvr->add(*path_l2);
1371     HW::item<bool> hw_route_dvr(true, rc_t::OK);
1372     ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_dvr, 0, pfx_6, {*path_l2}));
1373     TRY_CHECK_RC(OM::write(ian, *route_dvr));
1374
1375     STRICT_ORDER_OFF();
1376     // delete the stack objects that hold references to others
1377     // so the OM::remove is the call that removes the last reference
1378     delete l3_11;
1379     delete l3_10;
1380     delete itf2;
1381     delete route_5;
1382     delete path_10;
1383     delete route_5_2;
1384     delete path_11;
1385     delete route_dvr;
1386     delete path_l2;
1387     delete ne;
1388     ADD_EXPECT(neighbour_cmds::delete_cmd(hw_neighbour, hw_ifh.data(), mac_n, nh_10));
1389     ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_dvr, 0, pfx_6));
1390     ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5_2, 1, pfx_5));
1391     ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5, 0, pfx_5));
1392     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_10_unbind, hw_ifh.data(), pfx_10));
1393     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_11_unbind, hw_ifh2.data(), pfx_11));
1394     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
1395     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
1396     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd4_unbind, l3_proto_t::IPV4, hw_ifh2));
1397     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd4_unbind, l3_proto_t::IPV6, hw_ifh2));
1398     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down2, hw_ifh2));
1399     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf2_name));
1400     ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd4_delete, l3_proto_t::IPV4, 1));
1401     ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd6_delete, l3_proto_t::IPV6, 1));
1402
1403     TRY_CHECK(OM::remove(ian));
1404 }
1405
1406 BOOST_AUTO_TEST_CASE(test_nat) {
1407     VppInit vi;
1408     const std::string gs = "GeorgeSimenon";
1409     rc_t rc = rc_t::OK;
1410
1411     /*
1412      * Inside Interface
1413      */
1414     std::string itf_in_name = "inside";
1415     interface itf_in(itf_in_name,
1416                      interface::type_t::AFPACKET,
1417                      interface::admin_state_t::UP);
1418     HW::item<handle_t> hw_ifh(2, rc_t::OK);
1419     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
1420     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
1421     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf_in_name));
1422     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
1423     TRY_CHECK_RC(OM::write(gs, itf_in));
1424
1425     /*
1426      * outside
1427      */
1428     std::string itf_out_name = "port-to";
1429     interface itf_out(itf_out_name,
1430                    interface::type_t::AFPACKET,
1431                    interface::admin_state_t::UP);
1432
1433     HW::item<handle_t> hw_ifh2(4, rc_t::OK);
1434     HW::item<interface::admin_state_t> hw_as_up2(interface::admin_state_t::UP, rc_t::OK);
1435     HW::item<interface::admin_state_t> hw_as_down2(interface::admin_state_t::DOWN, rc_t::OK);
1436
1437     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf_out_name));
1438     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up2, hw_ifh2));
1439     TRY_CHECK_RC(OM::write(gs, itf_out));
1440
1441     /*
1442      * A NAT static mapping
1443      */
1444     boost::asio::ip::address in_addr = boost::asio::ip::address::from_string("10.0.0.1");
1445     boost::asio::ip::address_v4 out_addr = boost::asio::ip::address_v4::from_string("1.1.1.1");
1446
1447     nat_static ns(in_addr, out_addr);
1448     HW::item<bool> hw_ns(true, rc_t::OK);
1449
1450     ADD_EXPECT(nat_static_cmds::create_44_cmd(hw_ns, 0, in_addr.to_v4(), out_addr));
1451     TRY_CHECK_RC(OM::write(gs, ns));
1452
1453     /*
1454      * bind nat inside and out
1455      */
1456     nat_binding *nb_in = new nat_binding(itf_in,
1457                                          direction_t::INPUT,
1458                                          l3_proto_t::IPV4,
1459                                          nat_binding::zone_t::INSIDE);
1460     HW::item<bool> hw_nb_in(true, rc_t::OK);
1461
1462     ADD_EXPECT(nat_binding_cmds::bind_44_input_cmd(hw_nb_in,
1463                                                    hw_ifh.data().value(),
1464                                                    nat_binding::zone_t::INSIDE));
1465     TRY_CHECK_RC(OM::write(gs, *nb_in));
1466
1467     nat_binding *nb_out = new nat_binding(itf_out,
1468                                           direction_t::INPUT,
1469                                           l3_proto_t::IPV4,
1470                                           nat_binding::zone_t::OUTSIDE);
1471     HW::item<bool> hw_nb_out(true, rc_t::OK);
1472
1473     ADD_EXPECT(nat_binding_cmds::bind_44_input_cmd(hw_nb_out,
1474                                                    hw_ifh2.data().value(),
1475                                                    nat_binding::zone_t::OUTSIDE));
1476     TRY_CHECK_RC(OM::write(gs, *nb_out));
1477
1478
1479     STRICT_ORDER_OFF();
1480     delete nb_in;
1481     delete nb_out;
1482     ADD_EXPECT(nat_binding_cmds::unbind_44_input_cmd(hw_nb_in,
1483                                                      hw_ifh.data().value(),
1484                                                      nat_binding::zone_t::INSIDE));
1485     ADD_EXPECT(nat_binding_cmds::unbind_44_input_cmd(hw_nb_out,
1486                                                      hw_ifh2.data().value(),
1487                                                      nat_binding::zone_t::OUTSIDE));
1488     ADD_EXPECT(nat_static_cmds::delete_44_cmd(hw_ns, 0, in_addr.to_v4(), out_addr));
1489     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
1490     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf_in_name));
1491     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down2, hw_ifh2));
1492     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf_out_name));
1493
1494     TRY_CHECK(OM::remove(gs));
1495 }
1496
1497 BOOST_AUTO_TEST_CASE(test_interface_events) {
1498     VppInit vi;
1499     MockListener ml;
1500
1501     HW::item<bool> hw_want(true, rc_t::OK);
1502
1503     ADD_EXPECT(interface_cmds::events_cmd(ml));
1504     cmd* itf = new interface_cmds::events_cmd(ml);
1505
1506     HW::enqueue(itf);
1507     HW::write();
1508 }
1509
1510 BOOST_AUTO_TEST_CASE(test_interface_route_domain_change) {
1511     VppInit vi;
1512     const std::string rene = "ReneGoscinny";
1513     rc_t rc = rc_t::OK;
1514
1515     /*
1516      * Create an interface with two IP addresses
1517      */
1518     std::string itf1_name = "host1";
1519     interface itf1(itf1_name,
1520                    interface::type_t::AFPACKET,
1521                    interface::admin_state_t::UP);
1522     HW::item<handle_t> hw_ifh1(2, rc_t::OK);
1523     HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
1524     HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
1525     ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh1, itf1_name));
1526     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh1));
1527     TRY_CHECK_RC(OM::write(rene, itf1));
1528
1529     route::prefix_t pfx_10("10.10.10.10", 24);
1530     l3_binding *l3_1 = new l3_binding(itf1, pfx_10);
1531     HW::item<bool> hw_l3_bind1(true, rc_t::OK);
1532     HW::item<bool> hw_l3_unbind1(false, rc_t::OK);
1533     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10));
1534     TRY_CHECK_RC(OM::write(rene, *l3_1));
1535
1536     route::prefix_t pfx_11("10.10.11.11", 24);
1537     l3_binding *l3_2 = new l3_binding(itf1, pfx_11);
1538     HW::item<bool> hw_l3_bind2(true, rc_t::OK);
1539     HW::item<bool> hw_l3_unbind2(false, rc_t::OK);
1540     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11));
1541     TRY_CHECK_RC(OM::write(rene, *l3_2));
1542
1543     route_domain rd(1);
1544     HW::item<bool> hw_rd_create(true, rc_t::OK);
1545     HW::item<bool> hw_rd_delete(false, rc_t::OK);
1546     HW::item<route::table_id_t> hw_rd_bind(1, rc_t::OK);
1547     HW::item<route::table_id_t> hw_rd_unbind(route::DEFAULT_TABLE, rc_t::OK);
1548     ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd_create, l3_proto_t::IPV4, 1));
1549     ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd_create, l3_proto_t::IPV6, 1));
1550     TRY_CHECK_RC(OM::write(rene, rd));
1551
1552     /*
1553      * update the interface to change to a new route-domain
1554      * expect that the l3-bindings are removed and readded.
1555      */
1556     interface *itf2 = new interface(itf1_name,
1557                                     interface::type_t::AFPACKET,
1558                                     interface::admin_state_t::UP,
1559                                     rd);
1560     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10));
1561     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11));
1562     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_bind, l3_proto_t::IPV4, hw_ifh1));
1563     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_bind, l3_proto_t::IPV6, hw_ifh1));
1564     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10));
1565     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11));
1566     TRY_CHECK_RC(OM::write(rene, *itf2));
1567
1568     /*
1569      * mve the interface back to the default route-domain
1570      */
1571     interface itf3(itf1_name,
1572                    interface::type_t::AFPACKET,
1573                    interface::admin_state_t::UP);
1574     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10));
1575     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11));
1576     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_unbind, l3_proto_t::IPV4, hw_ifh1));
1577     ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_unbind, l3_proto_t::IPV6, hw_ifh1));
1578     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10));
1579     ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11));
1580     TRY_CHECK_RC(OM::write(rene, itf3));
1581
1582     delete l3_1;
1583     delete l3_2;
1584     delete itf2;
1585
1586     STRICT_ORDER_OFF();
1587     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10));
1588     ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11));
1589     ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh1));
1590     ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh1, itf1_name));
1591     ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd_delete, l3_proto_t::IPV4, 1));
1592     ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd_delete, l3_proto_t::IPV6, 1));
1593
1594     TRY_CHECK(OM::remove(rene));
1595 }
1596
1597 BOOST_AUTO_TEST_SUITE_END()