@@ -25,6 +25,7 @@ def __init__(self, common_objs, db, table):
25
25
self .directory .subscribe ([("CONFIG_DB" , swsscommon .CFG_DEVICE_METADATA_TABLE_NAME , "localhost/bgp_asn" ),], self .on_bgp_asn_change )
26
26
self .static_routes = {}
27
27
self .vrf_pending_redistribution = set ()
28
+ self .config_db = None
28
29
29
30
OP_DELETE = 'DELETE'
30
31
OP_ADD = 'ADD'
@@ -41,7 +42,17 @@ def set_handler(self, key, data):
41
42
intf_list = arg_list (data ['ifname' ]) if 'ifname' in data else None
42
43
dist_list = arg_list (data ['distance' ]) if 'distance' in data else None
43
44
nh_vrf_list = arg_list (data ['nexthop-vrf' ]) if 'nexthop-vrf' in data else None
44
- route_tag = self .ROUTE_ADVERTISE_DISABLE_TAG if 'advertise' in data and data ['advertise' ] == "false" else self .ROUTE_ADVERTISE_ENABLE_TAG
45
+ bfd_enable = arg_list (data ['bfd' ]) if 'bfd' in data else None
46
+ route_tag = self .ROUTE_ADVERTISE_DISABLE_TAG if 'advertise' in data and data ['advertise' ] == "false" else self .ROUTE_ADVERTISE_ENABLE_TAG
47
+
48
+ # bfd enabled route would be handled in staticroutebfd, skip here
49
+ if bfd_enable and bfd_enable [0 ].lower () == "true" :
50
+ log_debug ("{} static route {} bfd flag is true" .format (self .db_name , key ))
51
+ tmp_nh_set , tmp_route_tag = self .static_routes .get (vrf , {}).get (ip_prefix , (IpNextHopSet (is_ipv6 ), route_tag ))
52
+ if tmp_nh_set : #clear nexthop set if it is not empty
53
+ log_debug ("{} static route {} bfd flag is true, cur_nh is not empty, clear it" .format (self .db_name , key ))
54
+ self .static_routes .setdefault (vrf , {}).pop (ip_prefix , None )
55
+ return True
45
56
46
57
try :
47
58
ip_nh_set = IpNextHopSet (is_ipv6 , bkh_list , nh_list , intf_list , dist_list , nh_vrf_list )
@@ -60,19 +71,59 @@ def set_handler(self, key, data):
60
71
61
72
if cmd_list :
62
73
self .cfg_mgr .push_list (cmd_list )
63
- log_debug ("Static route {} is scheduled for updates" .format (key ))
74
+ log_debug ("{} Static route {} is scheduled for updates. {} " .format (self . db_name , key , str ( cmd_list ) ))
64
75
else :
65
- log_debug ("Nothing to update for static route {}" .format (key ))
76
+ log_debug ("{} Nothing to update for static route {}" .format (self . db_name , key ))
66
77
67
78
self .static_routes .setdefault (vrf , {})[ip_prefix ] = (ip_nh_set , route_tag )
68
79
69
80
return True
70
81
71
82
83
+ def skip_appl_del (self , vrf , ip_prefix ):
84
+ """
85
+ If a static route is bfd enabled, the processed static route is written into application DB by staticroutebfd.
86
+ When we disable bfd for that route at runtime, that static route entry will be removed from APPL_DB STATIC_ROUTE_TABLE.
87
+ In the case, the StaticRouteMgr(appl_db) cannot uninstall the static route from FRR if the static route is still in CONFIG_DB,
88
+ so need this checking (skip appl_db deletion) to avoid race condition between StaticRouteMgr(appl_db) and StaticRouteMgr(config_db)
89
+ For more detailed information:
90
+ https://github.com/sonic-net/SONiC/blob/master/doc/static-route/SONiC_static_route_bfd_hld.md#bfd-field-changes-from-true-to-false
91
+
92
+ :param vrf: vrf from the split_key(key) return
93
+ :param ip_prefix: ip_prefix from the split_key(key) return
94
+ :return: True if the deletion comes from APPL_DB and the vrf|ip_prefix exists in CONFIG_DB, otherwise return False
95
+ """
96
+ if self .db_name == "CONFIG_DB" :
97
+ return False
98
+
99
+ if self .config_db is None :
100
+ self .config_db = swsscommon .SonicV2Connector ()
101
+ self .config_db .connect (self .config_db .CONFIG_DB )
102
+
103
+ #just pop local cache if the route exist in config_db
104
+ cfg_key = "STATIC_ROUTE|" + vrf + "|" + ip_prefix
105
+ nexthop = self .config_db .get (self .config_db .CONFIG_DB , cfg_key , "nexthop" )
106
+ if nexthop and len (nexthop )> 0 :
107
+ self .static_routes .setdefault (vrf , {}).pop (ip_prefix , None )
108
+ return True
109
+
110
+ if vrf == "default" :
111
+ cfg_key = "STATIC_ROUTE|" + ip_prefix
112
+ nexthop = self .config_db .get (self .config_db .CONFIG_DB , cfg_key , "nexthop" )
113
+ if nexthop and len (nexthop )> 0 :
114
+ self .static_routes .setdefault (vrf , {}).pop (ip_prefix , None )
115
+ return True
116
+
117
+ return False
118
+
72
119
def del_handler (self , key ):
73
120
vrf , ip_prefix = self .split_key (key )
74
121
is_ipv6 = TemplateFabric .is_ipv6 (ip_prefix )
75
122
123
+ if self .skip_appl_del (vrf , ip_prefix ):
124
+ log_debug ("{} ignore appl_db static route deletion because of key {} exist in config_db" .format (self .db_name , key ))
125
+ return
126
+
76
127
ip_nh_set = IpNextHopSet (is_ipv6 )
77
128
cur_nh_set , route_tag = self .static_routes .get (vrf , {}).get (ip_prefix , (IpNextHopSet (is_ipv6 ), self .ROUTE_ADVERTISE_DISABLE_TAG ))
78
129
cmd_list = self .static_route_commands (ip_nh_set , cur_nh_set , ip_prefix , vrf , route_tag , route_tag )
@@ -85,9 +136,9 @@ def del_handler(self, key):
85
136
86
137
if cmd_list :
87
138
self .cfg_mgr .push_list (cmd_list )
88
- log_debug ("Static route {} is scheduled for updates" .format (key ))
139
+ log_debug ("{} Static route {} is scheduled for updates. {} " .format (self . db_name , key , str ( cmd_list ) ))
89
140
else :
90
- log_debug ("Nothing to update for static route {}" .format (key ))
141
+ log_debug ("{} Nothing to update for static route {}" .format (self . db_name , key ))
91
142
92
143
self .static_routes .setdefault (vrf , {}).pop (ip_prefix , None )
93
144
0 commit comments