+
+ // test the BVI entry in l2fib
+ bridge_domain bd2(99);
+
+ HW::item<uint32_t> hw_bd2(99, rc_t::OK);
+ ADD_EXPECT(bridge_domain_cmds::create_cmd(hw_bd2,
+ bridge_domain::learning_mode_t::ON,
+ bridge_domain::arp_term_mode_t::ON,
+ bridge_domain::flood_mode_t::ON,
+ bridge_domain::mac_age_mode_t::OFF));
+
+ TRY_CHECK_RC(OM::write(jkr, bd2));
+
+ std::string itf3_name = "bvi";
+ interface itf3(itf3_name,
+ interface::type_t::BVI,
+ interface::admin_state_t::UP);
+
+ HW::item<handle_t> hw_ifh3(5, rc_t::OK);
+ ADD_EXPECT(interface_cmds::loopback_create_cmd(hw_ifh3, itf3_name));
+ ADD_EXPECT(interface_cmds::set_tag(hw_ifh3, itf3_name));
+ ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh3));
+ TRY_CHECK_RC(OM::write(jkr, itf3));
+
+ l2_binding *l2itf3 = new l2_binding(itf3, bd2);
+ ADD_EXPECT(l2_binding_cmds::bind_cmd(hw_l2_bind,
+ hw_ifh3.data(),
+ hw_bd2.data(),
+ l2_binding::l2_port_type_t::L2_PORT_TYPE_BVI));
+ TRY_CHECK_RC(OM::write(jkr, *l2itf3));
+
+ HW::item<bool> hw_be2(true, rc_t::OK);
+ mac_address_t mac2({0,1,2,3,4,5});
+ bridge_domain_entry *be2 = new bridge_domain_entry(bd2, mac2, itf3);
+ ADD_EXPECT(bridge_domain_entry_cmds::create_cmd(hw_be2, mac2, bd2.id(), hw_ifh3.data(), true));
+ TRY_CHECK_RC(OM::write(jkr, *be2));
+
+ delete l2itf3;
+ delete be2;
+ STRICT_ORDER_OFF();
+ ADD_EXPECT(l2_binding_cmds::unbind_cmd(hw_l2_bind,
+ hw_ifh3.data(),
+ hw_bd2.data(),
+ l2_binding::l2_port_type_t::L2_PORT_TYPE_BVI));
+ ADD_EXPECT(bridge_domain_entry_cmds::delete_cmd(hw_be2, mac2, bd2.id(), true));
+ ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh3));
+ ADD_EXPECT(interface_cmds::loopback_delete_cmd(hw_ifh3));
+ ADD_EXPECT(bridge_domain_cmds::delete_cmd(hw_bd2));
+ TRY_CHECK(OM::remove(jkr));
+}
+
+BOOST_AUTO_TEST_CASE(test_l2_xconnect) {
+ VppInit vi;
+ const std::string nicholas = "NicholasAbercrombie";
+ rc_t rc = rc_t::OK;
+
+ /*
+ * Interface 1
+ */
+ std::string itf1_name = "host1";
+ interface itf1(itf1_name,
+ interface::type_t::AFPACKET,
+ interface::admin_state_t::UP);
+ HW::item<handle_t> hw_ifh(2, rc_t::OK);
+ HW::item<interface::admin_state_t> hw_as_up(interface::admin_state_t::UP, rc_t::OK);
+ ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh, itf1_name));
+ ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh));
+ TRY_CHECK_RC(OM::write(nicholas, itf1));
+
+ /*
+ * Interface 2
+ */
+ std::string itf2_name = "host2";
+ interface itf2(itf2_name,
+ interface::type_t::AFPACKET,
+ interface::admin_state_t::UP);
+
+ HW::item<handle_t> hw_ifh2(4, rc_t::OK);
+ ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh2, itf2_name));
+ ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh2));
+ TRY_CHECK_RC(OM::write(nicholas, itf2));
+
+ l2_xconnect *l2_xconn = new l2_xconnect(itf1, itf2);
+ HW::item<bool> xconnect_east(true, rc_t::OK);
+ HW::item<bool> xconnect_west(true, rc_t::OK);
+ HW::item<bool> xconnect_east_unbind(false, rc_t::OK);
+ HW::item<bool> xconnect_west_unbind(false, rc_t::OK);
+ ADD_EXPECT(l2_xconnect_cmds::bind_cmd(xconnect_east, hw_ifh.data(), hw_ifh2.data()));
+ ADD_EXPECT(l2_xconnect_cmds::bind_cmd(xconnect_west, hw_ifh2.data(), hw_ifh.data()));
+ TRY_CHECK_RC(OM::write(nicholas, *l2_xconn));
+
+ delete l2_xconn;
+
+ HW::item<interface::admin_state_t> hw_as_down(interface::admin_state_t::DOWN, rc_t::OK);
+ STRICT_ORDER_OFF();
+ ADD_EXPECT(l2_xconnect_cmds::unbind_cmd(xconnect_east_unbind, hw_ifh.data(), hw_ifh2.data()));
+ ADD_EXPECT(l2_xconnect_cmds::unbind_cmd(xconnect_west_unbind, hw_ifh2.data(), hw_ifh.data()));
+ ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh2));
+ ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh2, itf2_name));
+ ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh));
+ ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh, itf1_name));
+
+ TRY_CHECK(OM::remove(nicholas));