4
4
#include " select.h"
5
5
#include " selectabletimer.h"
6
6
#include " netdispatcher.h"
7
+ #include " netlink.h"
8
+ #include " notificationconsumer.h"
9
+ #include " subscriberstatetable.h"
7
10
#include " warmRestartHelper.h"
8
11
#include " fpmsyncd/fpmlink.h"
9
12
#include " fpmsyncd/routesync.h"
10
13
14
+ #include < netlink/route/route.h>
11
15
12
16
using namespace std ;
13
17
using namespace swss ;
@@ -47,21 +51,47 @@ static bool eoiuFlagsSet(Table &bgpStateTable)
47
51
int main (int argc, char **argv)
48
52
{
49
53
swss::Logger::linkToDbNative (" fpmsyncd" );
54
+
55
+ const auto routeResponseChannelName = std::string (" APPL_DB_" ) + APP_ROUTE_TABLE_NAME + " _RESPONSE_CHANNEL" ;
56
+
50
57
DBConnector db (" APPL_DB" , 0 );
58
+ DBConnector cfgDb (" CONFIG_DB" , 0 );
59
+ SubscriberStateTable deviceMetadataTableSubscriber (&cfgDb, CFG_DEVICE_METADATA_TABLE_NAME);
60
+ Table deviceMetadataTable (&cfgDb, CFG_DEVICE_METADATA_TABLE_NAME);
61
+ DBConnector applStateDb (" APPL_STATE_DB" , 0 );
62
+ std::unique_ptr<NotificationConsumer> routeResponseChannel;
63
+
51
64
RedisPipeline pipeline (&db);
52
65
RouteSync sync (&pipeline);
53
66
54
67
DBConnector stateDb (" STATE_DB" , 0 );
55
68
Table bgpStateTable (&stateDb, STATE_BGP_TABLE_NAME);
56
69
70
+ NetLink netlink;
71
+
72
+ netlink.registerGroup (RTNLGRP_LINK);
73
+
57
74
NetDispatcher::getInstance ().registerMessageHandler (RTM_NEWROUTE, &sync );
58
75
NetDispatcher::getInstance ().registerMessageHandler (RTM_DELROUTE, &sync );
76
+ NetDispatcher::getInstance ().registerMessageHandler (RTM_NEWLINK, &sync );
77
+ NetDispatcher::getInstance ().registerMessageHandler (RTM_DELLINK, &sync );
78
+
79
+ rtnl_route_read_protocol_names (DefaultRtProtoPath);
80
+
81
+ std::string suppressionEnabledStr;
82
+ deviceMetadataTable.hget (" localhost" , " suppress-fib-pending" , suppressionEnabledStr);
83
+ if (suppressionEnabledStr == " enabled" )
84
+ {
85
+ routeResponseChannel = std::make_unique<NotificationConsumer>(&applStateDb, routeResponseChannelName);
86
+ sync .setSuppressionEnabled (true );
87
+ }
59
88
60
89
while (true )
61
90
{
62
91
try
63
92
{
64
93
FpmLink fpm (&sync );
94
+
65
95
Select s;
66
96
SelectableTimer warmStartTimer (timespec {0 , 0 });
67
97
// Before eoiu flags detected, check them periodically. It also stop upon detection of reconciliation done.
@@ -80,6 +110,13 @@ int main(int argc, char **argv)
80
110
cout << " Connected!" << endl;
81
111
82
112
s.addSelectable (&fpm);
113
+ s.addSelectable (&netlink);
114
+ s.addSelectable (&deviceMetadataTableSubscriber);
115
+
116
+ if (sync .isSuppressionEnabled ())
117
+ {
118
+ s.addSelectable (routeResponseChannel.get ());
119
+ }
83
120
84
121
/* If warm-restart feature is enabled, execute 'restoration' logic */
85
122
bool warmStartEnabled = sync .m_warmStartHelper .checkAndStart ();
@@ -139,11 +176,8 @@ int main(int argc, char **argv)
139
176
SWSS_LOG_NOTICE (" Warm-Restart EOIU hold timer expired." );
140
177
}
141
178
142
- if (sync .m_warmStartHelper .inProgress ())
143
- {
144
- sync .m_warmStartHelper .reconcile ();
145
- SWSS_LOG_NOTICE (" Warm-Restart reconciliation processed." );
146
- }
179
+ sync .onWarmStartEnd (applStateDb);
180
+
147
181
// remove the one-shot timer.
148
182
s.removeSelectable (temps);
149
183
pipeline.flush ();
@@ -182,6 +216,74 @@ int main(int argc, char **argv)
182
216
s.removeSelectable (&eoiuCheckTimer);
183
217
}
184
218
}
219
+ else if (temps == &deviceMetadataTableSubscriber)
220
+ {
221
+ std::deque<KeyOpFieldsValuesTuple> keyOpFvsQueue;
222
+ deviceMetadataTableSubscriber.pops (keyOpFvsQueue);
223
+
224
+ for (const auto & keyOpFvs: keyOpFvsQueue)
225
+ {
226
+ const auto & key = kfvKey (keyOpFvs);
227
+ const auto & op = kfvOp (keyOpFvs);
228
+ const auto & fvs = kfvFieldsValues (keyOpFvs);
229
+
230
+ if (op != SET_COMMAND)
231
+ {
232
+ continue ;
233
+ }
234
+
235
+ if (key != " localhost" )
236
+ {
237
+ continue ;
238
+ }
239
+
240
+ for (const auto & fv: fvs)
241
+ {
242
+ const auto & field = fvField (fv);
243
+ const auto & value = fvValue (fv);
244
+
245
+ if (field != " suppress-fib-pending" )
246
+ {
247
+ continue ;
248
+ }
249
+
250
+ bool shouldEnable = (value == " enabled" );
251
+
252
+ if (shouldEnable && !sync .isSuppressionEnabled ())
253
+ {
254
+ routeResponseChannel = std::make_unique<NotificationConsumer>(&applStateDb, routeResponseChannelName);
255
+ sync .setSuppressionEnabled (true );
256
+ s.addSelectable (routeResponseChannel.get ());
257
+ }
258
+ else if (!shouldEnable && sync .isSuppressionEnabled ())
259
+ {
260
+ /* When disabling suppression we mark all existing routes offloaded in zebra
261
+ * as there could be some transient routes which are pending response from
262
+ * orchagent, thus such updates might be missing. Since we are disabling suppression
263
+ * we no longer care about real HW offload status and can mark all routes as offloaded
264
+ * to avoid routes stuck in suppressed state after transition. */
265
+ sync .markRoutesOffloaded (db);
266
+
267
+ sync .setSuppressionEnabled (false );
268
+ s.removeSelectable (routeResponseChannel.get ());
269
+ routeResponseChannel.reset ();
270
+ }
271
+ } // end for fvs
272
+ } // end for keyOpFvsQueue
273
+ }
274
+ else if (routeResponseChannel && (temps == routeResponseChannel.get ()))
275
+ {
276
+ std::deque<KeyOpFieldsValuesTuple> notifications;
277
+ routeResponseChannel->pops (notifications);
278
+
279
+ for (const auto & notification: notifications)
280
+ {
281
+ const auto & key = kfvKey (notification);
282
+ const auto & fieldValues = kfvFieldsValues (notification);
283
+
284
+ sync .onRouteResponse (key, fieldValues);
285
+ }
286
+ }
185
287
else if (!warmStartEnabled || sync .m_warmStartHelper .isReconciled ())
186
288
{
187
289
pipeline.flush ();
0 commit comments