1+ #define private public // make Directory::m_values available to clean it.
2+ #include " directory.h"
3+ #undef private
4+ #include " gtest/gtest.h"
5+ #include " ut_helper.h"
6+ #include " mock_orchagent_main.h"
7+ #include " mock_table.h"
8+ #include < memory>
9+ #include < vector>
10+
11+
12+
13+ namespace intfsorch_test
14+ {
15+ using namespace std ;
16+
17+ int create_rif_count = 0 ;
18+ int remove_rif_count = 0 ;
19+ sai_router_interface_api_t *pold_sai_rif_api;
20+ sai_router_interface_api_t ut_sai_rif_api;
21+
22+ sai_status_t _ut_create_router_interface (
23+ _Out_ sai_object_id_t *router_interface_id,
24+ _In_ sai_object_id_t switch_id,
25+ _In_ uint32_t attr_count,
26+ _In_ const sai_attribute_t *attr_list)
27+ {
28+ ++create_rif_count;
29+ return SAI_STATUS_SUCCESS;
30+ }
31+
32+ sai_status_t _ut_remove_router_interface (
33+ _In_ sai_object_id_t router_interface_id)
34+ {
35+ ++remove_rif_count;
36+ return SAI_STATUS_SUCCESS;
37+ }
38+
39+ struct IntfsOrchTest : public ::testing::Test
40+ {
41+ shared_ptr<swss::DBConnector> m_app_db;
42+ shared_ptr<swss::DBConnector> m_config_db;
43+ shared_ptr<swss::DBConnector> m_state_db;
44+ shared_ptr<swss::DBConnector> m_chassis_app_db;
45+
46+ // sai_router_interface_api_t *old_sai_rif_api_ptr;
47+
48+ // sai_create_router_interface_fn old_create_rif;
49+ // sai_remove_router_interface_fn old_remove_rif;
50+ void SetUp () override
51+ {
52+ map<string, string> profile = {
53+ { " SAI_VS_SWITCH_TYPE" , " SAI_VS_SWITCH_TYPE_BCM56850" },
54+ { " KV_DEVICE_MAC_ADDRESS" , " 20:03:04:05:06:00" }
55+ };
56+
57+ ut_helper::initSaiApi (profile);
58+ pold_sai_rif_api = sai_router_intfs_api;
59+ ut_sai_rif_api = *sai_router_intfs_api;
60+ sai_router_intfs_api = &ut_sai_rif_api;
61+
62+ sai_router_intfs_api->create_router_interface = _ut_create_router_interface;
63+ sai_router_intfs_api->remove_router_interface = _ut_remove_router_interface;
64+
65+ m_app_db = make_shared<swss::DBConnector>(" APPL_DB" , 0 );
66+ m_config_db = make_shared<swss::DBConnector>(" CONFIG_DB" , 0 );
67+ m_state_db = make_shared<swss::DBConnector>(" STATE_DB" , 0 );
68+ m_chassis_app_db = make_shared<swss::DBConnector>(" CHASSIS_APP_DB" , 0 );
69+
70+ sai_attribute_t attr;
71+
72+ attr.id = SAI_SWITCH_ATTR_INIT_SWITCH;
73+ attr.value .booldata = true ;
74+
75+ auto status = sai_switch_api->create_switch (&gSwitchId , 1 , &attr);
76+ ASSERT_EQ (status, SAI_STATUS_SUCCESS);
77+
78+ // Get switch source MAC address
79+ attr.id = SAI_SWITCH_ATTR_SRC_MAC_ADDRESS;
80+ status = sai_switch_api->get_switch_attribute (gSwitchId , 1 , &attr);
81+
82+ ASSERT_EQ (status, SAI_STATUS_SUCCESS);
83+
84+ gMacAddress = attr.value .mac ;
85+
86+ attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID;
87+ status = sai_switch_api->get_switch_attribute (gSwitchId , 1 , &attr);
88+
89+ ASSERT_EQ (status, SAI_STATUS_SUCCESS);
90+
91+ gVirtualRouterId = attr.value .oid ;
92+
93+
94+ ASSERT_EQ (gCrmOrch , nullptr );
95+ gCrmOrch = new CrmOrch (m_config_db.get (), CFG_CRM_TABLE_NAME);
96+
97+ TableConnector stateDbSwitchTable (m_state_db.get (), " SWITCH_CAPABILITY" );
98+ TableConnector conf_asic_sensors (m_config_db.get (), CFG_ASIC_SENSORS_TABLE_NAME);
99+ TableConnector app_switch_table (m_app_db.get (), APP_SWITCH_TABLE_NAME);
100+
101+ vector<TableConnector> switch_tables = {
102+ conf_asic_sensors,
103+ app_switch_table
104+ };
105+
106+ ASSERT_EQ (gSwitchOrch , nullptr );
107+ gSwitchOrch = new SwitchOrch (m_app_db.get (), switch_tables, stateDbSwitchTable);
108+
109+ // Create dependencies ...
110+ TableConnector stateDbBfdSessionTable (m_state_db.get (), STATE_BFD_SESSION_TABLE_NAME);
111+ gBfdOrch = new BfdOrch (m_app_db.get (), APP_BFD_SESSION_TABLE_NAME, stateDbBfdSessionTable);
112+
113+ const int portsorch_base_pri = 40 ;
114+ vector<table_name_with_pri_t > ports_tables = {
115+ { APP_PORT_TABLE_NAME, portsorch_base_pri + 5 },
116+ { APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 },
117+ { APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri },
118+ { APP_LAG_TABLE_NAME, portsorch_base_pri + 4 },
119+ { APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri }
120+ };
121+
122+ vector<string> flex_counter_tables = {
123+ CFG_FLEX_COUNTER_TABLE_NAME
124+ };
125+ auto * flexCounterOrch = new FlexCounterOrch (m_config_db.get (), flex_counter_tables);
126+ gDirectory .set (flexCounterOrch);
127+
128+ ASSERT_EQ (gPortsOrch , nullptr );
129+ gPortsOrch = new PortsOrch (m_app_db.get (), m_state_db.get (), ports_tables, m_chassis_app_db.get ());
130+
131+ vector<string> vnet_tables = {
132+ APP_VNET_RT_TABLE_NAME,
133+ APP_VNET_RT_TUNNEL_TABLE_NAME
134+ };
135+
136+ vector<string> cfg_vnet_tables = {
137+ CFG_VNET_RT_TABLE_NAME,
138+ CFG_VNET_RT_TUNNEL_TABLE_NAME
139+ };
140+
141+ auto * vnet_orch = new VNetOrch (m_app_db.get (), APP_VNET_TABLE_NAME);
142+ gDirectory .set (vnet_orch);
143+ auto * cfg_vnet_rt_orch = new VNetCfgRouteOrch (m_config_db.get (), m_app_db.get (), cfg_vnet_tables);
144+ gDirectory .set (cfg_vnet_rt_orch);
145+ auto * vnet_rt_orch = new VNetRouteOrch (m_app_db.get (), vnet_tables, vnet_orch);
146+ gDirectory .set (vnet_rt_orch);
147+ ASSERT_EQ (gVrfOrch , nullptr );
148+ gVrfOrch = new VRFOrch (m_app_db.get (), APP_VRF_TABLE_NAME, m_state_db.get (), STATE_VRF_OBJECT_TABLE_NAME);
149+ gDirectory .set (gVrfOrch );
150+
151+ ASSERT_EQ (gIntfsOrch , nullptr );
152+ gIntfsOrch = new IntfsOrch (m_app_db.get (), APP_INTF_TABLE_NAME, gVrfOrch , m_chassis_app_db.get ());
153+
154+ const int fdborch_pri = 20 ;
155+
156+ vector<table_name_with_pri_t > app_fdb_tables = {
157+ { APP_FDB_TABLE_NAME, FdbOrch::fdborch_pri},
158+ { APP_VXLAN_FDB_TABLE_NAME, FdbOrch::fdborch_pri},
159+ { APP_MCLAG_FDB_TABLE_NAME, fdborch_pri}
160+ };
161+
162+ TableConnector stateDbFdb (m_state_db.get (), STATE_FDB_TABLE_NAME);
163+ TableConnector stateMclagDbFdb (m_state_db.get (), STATE_MCLAG_REMOTE_FDB_TABLE_NAME);
164+ ASSERT_EQ (gFdbOrch , nullptr );
165+ gFdbOrch = new FdbOrch (m_app_db.get (), app_fdb_tables, stateDbFdb, stateMclagDbFdb, gPortsOrch );
166+
167+ ASSERT_EQ (gNeighOrch , nullptr );
168+ gNeighOrch = new NeighOrch (m_app_db.get (), APP_NEIGH_TABLE_NAME, gIntfsOrch , gFdbOrch , gPortsOrch , m_chassis_app_db.get ());
169+
170+ auto * tunnel_decap_orch = new TunnelDecapOrch (m_app_db.get (), APP_TUNNEL_DECAP_TABLE_NAME);
171+ vector<string> mux_tables = {
172+ CFG_MUX_CABLE_TABLE_NAME,
173+ CFG_PEER_SWITCH_TABLE_NAME
174+ };
175+ auto * mux_orch = new MuxOrch (m_config_db.get (), mux_tables, tunnel_decap_orch, gNeighOrch , gFdbOrch );
176+ gDirectory .set (mux_orch);
177+
178+ ASSERT_EQ (gFgNhgOrch , nullptr );
179+ const int fgnhgorch_pri = 15 ;
180+
181+ vector<table_name_with_pri_t > fgnhg_tables = {
182+ { CFG_FG_NHG, fgnhgorch_pri },
183+ { CFG_FG_NHG_PREFIX, fgnhgorch_pri },
184+ { CFG_FG_NHG_MEMBER, fgnhgorch_pri }
185+ };
186+ gFgNhgOrch = new FgNhgOrch (m_config_db.get (), m_app_db.get (), m_state_db.get (), fgnhg_tables, gNeighOrch , gIntfsOrch , gVrfOrch );
187+
188+ ASSERT_EQ (gSrv6Orch , nullptr );
189+ vector<string> srv6_tables = {
190+ APP_SRV6_SID_LIST_TABLE_NAME,
191+ APP_SRV6_MY_SID_TABLE_NAME
192+ };
193+ gSrv6Orch = new Srv6Orch (m_app_db.get (), srv6_tables, gSwitchOrch , gVrfOrch , gNeighOrch );
194+
195+ // Start FlowCounterRouteOrch
196+ static const vector<string> route_pattern_tables = {
197+ CFG_FLOW_COUNTER_ROUTE_PATTERN_TABLE_NAME,
198+ };
199+ gFlowCounterRouteOrch = new FlowCounterRouteOrch (m_config_db.get (), route_pattern_tables);
200+
201+ ASSERT_EQ (gRouteOrch , nullptr );
202+ const int routeorch_pri = 5 ;
203+ vector<table_name_with_pri_t > route_tables = {
204+ { APP_ROUTE_TABLE_NAME, routeorch_pri },
205+ { APP_LABEL_ROUTE_TABLE_NAME, routeorch_pri }
206+ };
207+ gRouteOrch = new RouteOrch (m_app_db.get (), route_tables, gSwitchOrch , gNeighOrch , gIntfsOrch , gVrfOrch , gFgNhgOrch , gSrv6Orch );
208+ gNhgOrch = new NhgOrch (m_app_db.get (), APP_NEXTHOP_GROUP_TABLE_NAME);
209+
210+ // Recreate buffer orch to read populated data
211+ vector<string> buffer_tables = { APP_BUFFER_POOL_TABLE_NAME,
212+ APP_BUFFER_PROFILE_TABLE_NAME,
213+ APP_BUFFER_QUEUE_TABLE_NAME,
214+ APP_BUFFER_PG_TABLE_NAME,
215+ APP_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME,
216+ APP_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME };
217+
218+ gBufferOrch = new BufferOrch (m_app_db.get (), m_config_db.get (), m_state_db.get (), buffer_tables);
219+
220+ Table portTable = Table (m_app_db.get (), APP_PORT_TABLE_NAME);
221+
222+ // Get SAI default ports to populate DB
223+ auto ports = ut_helper::getInitialSaiPorts ();
224+
225+ // Populate pot table with SAI ports
226+ for (const auto &it : ports)
227+ {
228+ portTable.set (it.first , it.second );
229+ }
230+ // Set PortConfigDone
231+ portTable.set (" PortConfigDone" , { { " count" , to_string (ports.size ()) } });
232+ gPortsOrch ->addExistingData (&portTable);
233+ static_cast <Orch *>(gPortsOrch )->doTask ();
234+ portTable.set (" PortInitDone" , { { " lanes" , " 0" } });
235+ gPortsOrch ->addExistingData (&portTable);
236+ static_cast <Orch *>(gPortsOrch )->doTask ();
237+ }
238+
239+ void TearDown () override
240+ {
241+ gDirectory .m_values .clear ();
242+
243+ delete gCrmOrch ;
244+ gCrmOrch = nullptr ;
245+
246+ delete gSwitchOrch ;
247+ gSwitchOrch = nullptr ;
248+
249+ delete gBfdOrch ;
250+ gBfdOrch = nullptr ;
251+
252+ delete gNeighOrch ;
253+ gNeighOrch = nullptr ;
254+
255+ delete gFdbOrch ;
256+ gFdbOrch = nullptr ;
257+
258+ delete gPortsOrch ;
259+ gPortsOrch = nullptr ;
260+
261+ delete gIntfsOrch ;
262+ gIntfsOrch = nullptr ;
263+
264+ delete gFgNhgOrch ;
265+ gFgNhgOrch = nullptr ;
266+
267+ delete gSrv6Orch ;
268+ gSrv6Orch = nullptr ;
269+
270+ delete gRouteOrch ;
271+ gRouteOrch = nullptr ;
272+
273+ delete gNhgOrch ;
274+ gNhgOrch = nullptr ;
275+
276+ delete gBufferOrch ;
277+ gBufferOrch = nullptr ;
278+
279+ delete gVrfOrch ;
280+ gVrfOrch = nullptr ;
281+
282+ delete gFlowCounterRouteOrch ;
283+ gFlowCounterRouteOrch = nullptr ;
284+
285+ sai_router_intfs_api = pold_sai_rif_api;
286+ ut_helper::uninitSaiApi ();
287+ }
288+ };
289+
290+ TEST_F (IntfsOrchTest, IntfsOrchDeleteCreateRetry)
291+ {
292+ // create a interface
293+ std::deque<KeyOpFieldsValuesTuple> entries;
294+ entries.push_back ({" Ethernet0" , " SET" , { {" mtu" , " 9100" }}});
295+ auto consumer = dynamic_cast <Consumer *>(gIntfsOrch ->getExecutor (APP_INTF_TABLE_NAME));
296+ consumer->addToSync (entries);
297+ auto current_create_count = create_rif_count;
298+ static_cast <Orch *>(gIntfsOrch )->doTask ();
299+ ASSERT_EQ (current_create_count + 1 , create_rif_count);
300+
301+ // create dependency to the interface
302+ gIntfsOrch ->increaseRouterIntfsRefCount (" Ethernet0" );
303+
304+ // delete the interface, expect retry because dependency exists
305+ entries.clear ();
306+ entries.push_back ({" Ethernet0" , " DEL" , { {} }});
307+ consumer = dynamic_cast <Consumer *>(gIntfsOrch ->getExecutor (APP_INTF_TABLE_NAME));
308+ consumer->addToSync (entries);
309+ auto current_remove_count = remove_rif_count;
310+ static_cast <Orch *>(gIntfsOrch )->doTask ();
311+ ASSERT_EQ (current_remove_count, remove_rif_count);
312+
313+ // create the interface again, expect retry because interface is in removing
314+ entries.clear ();
315+ entries.push_back ({" Ethernet0" , " SET" , { {" mtu" , " 9100" }}});
316+ consumer = dynamic_cast <Consumer *>(gIntfsOrch ->getExecutor (APP_INTF_TABLE_NAME));
317+ consumer->addToSync (entries);
318+ current_create_count = create_rif_count;
319+ static_cast <Orch *>(gIntfsOrch )->doTask ();
320+ ASSERT_EQ (current_create_count, create_rif_count);
321+
322+ // remove the dependency, expect delete and create a new one
323+ gIntfsOrch ->decreaseRouterIntfsRefCount (" Ethernet0" );
324+ current_create_count = create_rif_count;
325+ current_remove_count = remove_rif_count;
326+ static_cast <Orch *>(gIntfsOrch )->doTask ();
327+ ASSERT_EQ (current_create_count + 1 , create_rif_count);
328+ ASSERT_EQ (current_remove_count + 1 , remove_rif_count);
329+ }
330+ }
0 commit comments