Skip to content

Commit 9b237a2

Browse files
[vnet/vxlan]: Handle SAI failures without crashing swss (sonic-net#3908)
What I did Remove explicit throwing of exceptions Use generic orchagent SAI failure handling logic Why I did it To avoid unnecessary orchagent crashes when programming vxlan tunnels and nexthops on a vnet in case of SAI errors. How I verified it By running mock tests and making sure that there are no crashes when there are vxlan tunnel, mapping or tunnel termination create/remove failure.
1 parent 1d34817 commit 9b237a2

5 files changed

Lines changed: 632 additions & 19 deletions

File tree

orchagent/vnetorch.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,12 @@ sai_object_id_t VNetVrfObject::getTunnelNextHop(NextHopKey& nh)
315315
nh_id = vxlan_orch->createNextHopTunnel(tun_name, nh.ip_address, nh.mac_address, nh.vni);
316316
if (nh_id == SAI_NULL_OBJECT_ID)
317317
{
318-
throw std::runtime_error("NH Tunnel create failed for " + vnet_name_ + " ip " + nh.ip_address.to_string());
318+
/*
319+
* Log an error and return. Generic error handling and reporting
320+
* is already done in createNextHopTunnel()
321+
*/
322+
SWSS_LOG_ERROR("NH Tunnel create failed for '%s' ip '%s'",
323+
vnet_name_.c_str(), nh.ip_address.to_string().c_str());
319324
}
320325

321326
return nh_id;

orchagent/vxlanorch.cpp

Lines changed: 99 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ extern "C" {
2020
#include "sai_serialize.h"
2121
#include "flex_counter_manager.h"
2222
#include "converter.h"
23+
#include "saihelper.h"
2324

2425
/* Global variables */
2526
extern sai_object_id_t gSwitchId;
@@ -145,7 +146,12 @@ create_tunnel_map(MAP_T map_t)
145146
);
146147
if (status != SAI_STATUS_SUCCESS)
147148
{
148-
throw std::runtime_error("Can't create tunnel map object");
149+
task_process_status handle_status = handleSaiCreateStatus(SAI_API_TUNNEL, status);
150+
if (handle_status != task_success)
151+
{
152+
SWSS_LOG_ERROR("Can't create tunnel map object");
153+
return SAI_NULL_OBJECT_ID;
154+
}
149155
}
150156

151157
return tunnel_map_id;
@@ -157,7 +163,11 @@ remove_tunnel_map(sai_object_id_t tunnel_map_id)
157163
sai_status_t status = sai_tunnel_api->remove_tunnel_map(tunnel_map_id);
158164
if (status != SAI_STATUS_SUCCESS)
159165
{
160-
throw std::runtime_error("Can't remove a tunnel map object");
166+
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_TUNNEL, status);
167+
if (handle_status != task_success)
168+
{
169+
SWSS_LOG_ERROR("Can't remove a tunnel map object");
170+
}
161171
}
162172
}
163173

@@ -204,7 +214,12 @@ static sai_object_id_t create_tunnel_map_entry(
204214

205215
if (status != SAI_STATUS_SUCCESS)
206216
{
207-
throw std::runtime_error("Can't create a tunnel map entry object");
217+
task_process_status handle_status = handleSaiCreateStatus(SAI_API_TUNNEL, status);
218+
if (handle_status != task_success)
219+
{
220+
SWSS_LOG_ERROR("Can't create a tunnel map entry object");
221+
return SAI_NULL_OBJECT_ID;
222+
}
208223
}
209224

210225
return tunnel_map_entry_id;
@@ -221,7 +236,11 @@ void remove_tunnel_map_entry(sai_object_id_t obj_id)
221236

222237
if (status != SAI_STATUS_SUCCESS)
223238
{
224-
throw std::runtime_error("Can't delete a tunnel map entry object");
239+
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_TUNNEL, status);
240+
if (handle_status != task_success)
241+
{
242+
SWSS_LOG_ERROR("Can't delete a tunnel map entry object");
243+
}
225244
}
226245
}
227246

@@ -383,7 +402,12 @@ create_tunnel(
383402
);
384403
if (status != SAI_STATUS_SUCCESS)
385404
{
386-
throw std::runtime_error("Can't create a tunnel object");
405+
task_process_status handle_status = handleSaiCreateStatus(SAI_API_TUNNEL, status);
406+
if (handle_status != task_success)
407+
{
408+
SWSS_LOG_ERROR("Can't create a tunnel object");
409+
return SAI_NULL_OBJECT_ID;
410+
}
387411
}
388412

389413
return tunnel_id;
@@ -397,7 +421,11 @@ remove_tunnel(sai_object_id_t tunnel_id)
397421
sai_status_t status = sai_tunnel_api->remove_tunnel(tunnel_id);
398422
if (status != SAI_STATUS_SUCCESS)
399423
{
400-
throw std::runtime_error("Can't remove a tunnel object");
424+
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_TUNNEL, status);
425+
if (handle_status != task_success)
426+
{
427+
SWSS_LOG_ERROR("Can't remove a tunnel object");
428+
}
401429
}
402430
}
403431
else
@@ -459,7 +487,12 @@ create_tunnel_termination(
459487
);
460488
if (status != SAI_STATUS_SUCCESS)
461489
{
462-
throw std::runtime_error("Can't create a tunnel term table object");
490+
task_process_status handle_status = handleSaiCreateStatus(SAI_API_TUNNEL, status);
491+
if (handle_status != task_success)
492+
{
493+
SWSS_LOG_ERROR("Can't create a tunnel term table object");
494+
return SAI_NULL_OBJECT_ID;
495+
}
463496
}
464497

465498
return term_table_id;
@@ -473,7 +506,11 @@ remove_tunnel_termination(sai_object_id_t term_table_id)
473506
sai_status_t status = sai_tunnel_api->remove_tunnel_term_table_entry(term_table_id);
474507
if (status != SAI_STATUS_SUCCESS)
475508
{
476-
throw std::runtime_error("Can't remove a tunnel term table object");
509+
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_TUNNEL, status);
510+
if (handle_status != task_success)
511+
{
512+
SWSS_LOG_ERROR("Can't remove a tunnel term table object");
513+
}
477514
}
478515
}
479516
else
@@ -615,12 +652,16 @@ bool VxlanTunnel::removeNextHop(IpAddress& ipAddr, MacAddress macAddress, uint32
615652

616653
if (!nh_tunnels_[key].ref_count)
617654
{
618-
if (sai_next_hop_api->remove_next_hop(nh_tunnels_[key].nh_id) != SAI_STATUS_SUCCESS)
655+
sai_status_t status = sai_next_hop_api->remove_next_hop(nh_tunnels_[key].nh_id);
656+
if (status != SAI_STATUS_SUCCESS)
619657
{
620-
SWSS_LOG_INFO("delete NH tunnel for ip '%s', mac '%s' vni %d failed",
658+
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_NEXT_HOP, status);
659+
if (handle_status != task_success)
660+
{
661+
SWSS_LOG_ERROR("delete NH tunnel for ip '%s', mac '%s' vni %d failed",
621662
ipAddr.to_string().c_str(), macAddress.to_string().c_str(), vni);
622-
string err_msg = "NH tunnel delete failed for " + ipAddr.to_string();
623-
throw std::runtime_error(err_msg);
663+
return false;
664+
}
624665
}
625666

626667
nh_tunnels_.erase(key);
@@ -869,11 +910,30 @@ bool VxlanTunnel::createTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src,
869910
{
870911
tunnel_orch->addTunnelToFlexCounter(ids_.tunnel_id, tunnel_name_);
871912
}
913+
else
914+
{
915+
// Undo changes in createMapperHw if create_tunnel fails.
916+
deleteMapperHw(mapper_list, map_src);
917+
ids_.tunnel_id = SAI_NULL_OBJECT_ID;
918+
ids_.tunnel_term_id = SAI_NULL_OBJECT_ID;
919+
active_ = false;
920+
return false;
921+
}
872922

873923
if (with_term)
874924
{
875925
ids_.tunnel_term_id = create_tunnel_termination(ids_.tunnel_id, ips,
876926
ip, gVirtualRouterId);
927+
if (ids_.tunnel_term_id == SAI_NULL_OBJECT_ID)
928+
{
929+
// Undo changes if create_tunnel_termination fails
930+
tunnel_orch->removeTunnelFromFlexCounter(ids_.tunnel_id, tunnel_name_);
931+
remove_tunnel(ids_.tunnel_id);
932+
deleteMapperHw(mapper_list, map_src);
933+
ids_.tunnel_id = SAI_NULL_OBJECT_ID;
934+
active_ = false;
935+
return false;
936+
}
877937
}
878938

879939
active_ = true;
@@ -1366,10 +1426,17 @@ VxlanTunnelOrch::createNextHopTunnel(string tunnelName, IpAddress& ipAddr,
13661426
macptr = &mac;
13671427
}
13681428

1369-
if (create_nexthop_tunnel(host_ip, vni, macptr, tunnel_id, &nh_id) != SAI_STATUS_SUCCESS)
1429+
sai_status_t status = create_nexthop_tunnel(host_ip, vni, macptr, tunnel_id, &nh_id);
1430+
if (status != SAI_STATUS_SUCCESS)
13701431
{
1371-
string err_msg = "NH tunnel create failed for " + ipAddr.to_string() + " " + to_string(vni);
1372-
throw std::runtime_error(err_msg);
1432+
task_process_status handle_status = handleSaiCreateStatus(SAI_API_NEXT_HOP, status);
1433+
if (handle_status != task_success)
1434+
{
1435+
SWSS_LOG_ERROR("NH vxlan tunnel create failed for %s, ip %s, mac %s, vni %d",
1436+
tunnelName.c_str(), ipAddr.to_string().c_str(),
1437+
macAddress.to_string().c_str(), vni);
1438+
return SAI_NULL_OBJECT_ID;
1439+
}
13731440
}
13741441

13751442
//Store the nh tunnel id
@@ -1412,6 +1479,7 @@ bool VxlanTunnelOrch::createVxlanTunnelMap(string tunnelName, tunnel_map_type_t
14121479
}
14131480

14141481
auto tunnel_obj = getVxlanTunnel(tunnelName);
1482+
bool tunnel_created = false;
14151483

14161484
if (!tunnel_obj->isActive())
14171485
{
@@ -1420,13 +1488,21 @@ bool VxlanTunnelOrch::createVxlanTunnelMap(string tunnelName, tunnel_map_type_t
14201488
uint8_t mapper_list = 0;
14211489
TUNNELMAP_SET_VLAN(mapper_list);
14221490
TUNNELMAP_SET_VRF(mapper_list);
1423-
tunnel_obj->createTunnelHw(mapper_list, TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP , true, encap_ttl);
1491+
tunnel_created = tunnel_obj->createTunnelHw(mapper_list, TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP , true, encap_ttl);
1492+
if (!tunnel_created)
1493+
{
1494+
return false;
1495+
}
14241496
}
14251497
else if (map == TUNNEL_MAP_T_BRIDGE)
14261498
{
14271499
uint8_t mapper_list = 0;
14281500
TUNNELMAP_SET_BRIDGE(mapper_list);
1429-
tunnel_obj->createTunnelHw(mapper_list, TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP, true, encap_ttl);
1501+
tunnel_created = tunnel_obj->createTunnelHw(mapper_list, TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP, true, encap_ttl);
1502+
if (!tunnel_created)
1503+
{
1504+
return false;
1505+
}
14301506
}
14311507
}
14321508

@@ -1990,7 +2066,12 @@ bool VxlanTunnelMapOrch::addOperation(const Request& request)
19902066
uint8_t mapper_list = 0;
19912067
TUNNELMAP_SET_VLAN(mapper_list);
19922068
TUNNELMAP_SET_VRF(mapper_list);
1993-
tunnel_obj->createTunnelHw(mapper_list,TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP);
2069+
bool tunnel_created = tunnel_obj->createTunnelHw(mapper_list,
2070+
TUNNEL_MAP_USE_DEDICATED_ENCAP_DECAP);
2071+
if (!tunnel_created)
2072+
{
2073+
return false;
2074+
}
19942075
if (!tunnel_orch->isDipTunnelsSupported())
19952076
{
19962077
Port tunPort;

tests/mock_tests/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ tests_INCLUDES = -I $(FLEX_CTR_DIR) -I $(DEBUG_CTR_DIR) -I $(top_srcdir)/lib -I$
3131
tests_SOURCES = aclorch_ut.cpp \
3232
aclorch_rule_ut.cpp \
3333
portsorch_ut.cpp \
34+
vxlanorch_ut.cpp \
3435
routeorch_ut.cpp \
3536
qosorch_ut.cpp \
3637
bufferorch_ut.cpp \

tests/mock_tests/mock_sai_tunnel.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#pragma once
2+
3+
#include <gmock/gmock.h>
4+
5+
extern "C"
6+
{
7+
#include "sai.h"
8+
}
9+
10+
// Mock Class mapping methods to tunnel object SAI APIs.
11+
class MockSaiTunnel
12+
{
13+
public:
14+
MOCK_METHOD4(create_tunnel, sai_status_t(_Out_ sai_object_id_t *tunnel_id, _In_ sai_object_id_t switch_id,
15+
_In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list));
16+
17+
MOCK_METHOD4(create_tunnel_map, sai_status_t(_Out_ sai_object_id_t *tunnel_map_id, _In_ sai_object_id_t switch_id,
18+
_In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list));
19+
20+
MOCK_METHOD4(create_tunnel_map_entry, sai_status_t(_Out_ sai_object_id_t *tunnel_map_entry_id, _In_ sai_object_id_t switch_id,
21+
_In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list));
22+
23+
MOCK_METHOD4(create_tunnel_term_table_entry, sai_status_t(_Out_ sai_object_id_t *tunnel_term_table_entry_id, _In_ sai_object_id_t switch_id,
24+
_In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list));
25+
26+
MOCK_METHOD1(remove_tunnel, sai_status_t(_In_ sai_object_id_t tunnel_id));
27+
28+
MOCK_METHOD1(remove_tunnel_map, sai_status_t(_In_ sai_object_id_t tunnel_map_id));
29+
30+
MOCK_METHOD1(remove_tunnel_map_entry, sai_status_t(sai_object_id_t tunnel_map_entry_id));
31+
32+
MOCK_METHOD1(remove_tunnel_term_table_entry, sai_status_t(sai_object_id_t tunnel_term_table_entry_id));
33+
34+
};
35+
36+
MockSaiTunnel *mock_sai_tunnel;
37+
38+
sai_status_t mock_create_tunnel(_Out_ sai_object_id_t *tunnel_id, _In_ sai_object_id_t switch_id,
39+
_In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)
40+
{
41+
return mock_sai_tunnel->create_tunnel(tunnel_id, switch_id, attr_count, attr_list);
42+
}
43+
44+
sai_status_t mock_create_tunnel_map(_Out_ sai_object_id_t *tunnel_map_id, _In_ sai_object_id_t switch_id,
45+
_In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)
46+
{
47+
return mock_sai_tunnel->create_tunnel_map(tunnel_map_id, switch_id, attr_count, attr_list);
48+
}
49+
50+
sai_status_t mock_create_tunnel_map_entry(_Out_ sai_object_id_t *tunnel_map_entry_id, _In_ sai_object_id_t switch_id,
51+
_In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)
52+
{
53+
return mock_sai_tunnel->create_tunnel_map_entry(tunnel_map_entry_id, switch_id, attr_count, attr_list);
54+
}
55+
56+
sai_status_t mock_create_tunnel_term_table_entry(_Out_ sai_object_id_t *tunnel_term_table_entry_id, _In_ sai_object_id_t switch_id,
57+
_In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)
58+
{
59+
return mock_sai_tunnel->create_tunnel_term_table_entry(tunnel_term_table_entry_id, switch_id, attr_count, attr_list);
60+
}
61+
62+
sai_status_t mock_remove_tunnel(_In_ sai_object_id_t tunnel_id)
63+
{
64+
return mock_sai_tunnel->remove_tunnel(tunnel_id);
65+
}
66+
67+
sai_status_t mock_remove_tunnel_map(_In_ sai_object_id_t tunnel_map_id)
68+
{
69+
return mock_sai_tunnel->remove_tunnel_map(tunnel_map_id);
70+
}
71+
72+
sai_status_t mock_remove_tunnel_map_entry(_In_ sai_object_id_t tunnel_map_entry_id)
73+
{
74+
return mock_sai_tunnel->remove_tunnel_map_entry(tunnel_map_entry_id);
75+
}
76+
77+
sai_status_t mock_remove_tunnel_term_table_entry(_In_ sai_object_id_t tunnel_term_table_entry_id)
78+
{
79+
return mock_sai_tunnel->remove_tunnel_term_table_entry(tunnel_term_table_entry_id);
80+
}

0 commit comments

Comments
 (0)