Line data Source code
1 : /*
2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <cmn/agent_cmn.h>
6 :
7 : #include <cmn/agent_factory.h>
8 : #include <cmn/agent_stats.h>
9 : #include <cmn/event_notifier.h>
10 : #include <init/agent_param.h>
11 :
12 : #include <cfg/cfg_init.h>
13 : #include <vgw/cfg_vgw.h>
14 :
15 : #include <oper/operdb_init.h>
16 : #include <oper/sg.h>
17 : #include <oper/vrf.h>
18 : #include <oper/nexthop.h>
19 : #include <oper/vn.h>
20 : #include <oper/vm.h>
21 : #include <oper/interface.h>
22 : #include <oper/route_common.h>
23 : #include <oper/agent_profile.h>
24 : #include <oper/crypt_tunnel.h>
25 : #include <filter/acl.h>
26 : #include <oper/multicast_policy.h>
27 : #include <controller/controller_init.h>
28 : #include <resource_manager/resource_manager.h>
29 :
30 : #include "agent_init.h"
31 :
32 2 : AgentInit::AgentInit() :
33 4 : agent_(new Agent()), agent_param_(NULL), trigger_(),
34 6 : enable_controller_(true) {
35 2 : }
36 :
37 2 : AgentInit::~AgentInit() {
38 2 : stats_.reset();
39 2 : trigger_.reset();
40 2 : controller_.reset();
41 2 : cfg_.reset();
42 2 : oper_.reset();
43 2 : resource_manager_.reset();
44 2 : agent_->db()->ClearFactoryRegistry();
45 2 : agent_.reset();
46 2 : }
47 :
48 : /****************************************************************************
49 : * Initialization routines
50 : ****************************************************************************/
51 2 : void AgentInit::ProcessOptions
52 : (const std::string &config_file, const std::string &program_name) {
53 2 : agent_param_->Init(config_file, program_name);
54 2 : }
55 :
56 4 : int AgentInit::ModuleType() {
57 4 : return Module::VROUTER_AGENT;
58 : }
59 :
60 2 : string AgentInit::ModuleName() {
61 2 : Module::type module = static_cast<Module::type>(ModuleType());
62 4 : return g_vns_constants.ModuleNames.find(module)->second;
63 : }
64 :
65 2 : string AgentInit::AgentName() {
66 2 : return agent_param_->agent_name();
67 : }
68 :
69 2 : string AgentInit::InstanceId() {
70 2 : return g_vns_constants.INSTANCE_ID_DEFAULT;
71 : }
72 :
73 2 : void AgentInit::InitPlatform() {
74 2 : boost::system::error_code ec;
75 2 : Ip4Address ip = Ip4Address::from_string("127.0.0.1", ec);
76 2 : if (ec.value() != 0) {
77 0 : assert(0);
78 : }
79 :
80 2 : if (agent_param_->platform() == AgentParam::VROUTER_ON_NIC) {
81 0 : agent_->set_vrouter_server_ip(ip);
82 0 : agent_->set_vrouter_server_port(VROUTER_SERVER_PORT);
83 0 : agent_->set_pkt_interface_name("pkt0");
84 2 : } else if (agent_param_->platform() == AgentParam::VROUTER_ON_HOST_DPDK) {
85 0 : agent_->set_vrouter_server_ip(ip);
86 0 : agent_->set_vrouter_server_port(VROUTER_SERVER_PORT);
87 0 : agent_->set_pkt_interface_name("unix");
88 : }
89 2 : }
90 :
91 : // Start of Agent init.
92 : // Trigger init in DBTable task context
93 2 : int AgentInit::Start(Logging &logging) {
94 2 : agent_->set_task_scheduler(TaskScheduler::GetInstance());
95 2 : agent_->set_agent_init(this);
96 :
97 : // Init platform specific information
98 2 : InitPlatform();
99 :
100 : // Copy tunable parameters into agent_
101 2 : agent_->CopyConfig(agent_param_);
102 :
103 2 : string module_name = ModuleName();
104 2 : agent_->set_agent_name(AgentName());
105 2 : agent_->set_instance_id(InstanceId());
106 2 : agent_->set_module_type(ModuleType());
107 2 : agent_->set_module_name(module_name);
108 2 : std::vector<std::string> v_slo_destinations = agent_param_->
109 2 : get_slo_destination();
110 2 : std::string log_property_file = agent_param_->log_property_file();
111 2 : if (log_property_file.size()) {
112 0 : logging.Init(log_property_file);
113 : }
114 : else {
115 6 : logging.Init(agent_param_->log_file(), agent_param_->log_file_size(),
116 2 : agent_param_->log_files_count(), false,
117 4 : agent_param_->syslog_facility(), module_name,
118 : SandeshLevelTolog4Level(
119 2 : Sandesh::StringToLevel(agent_param_->log_level())));
120 : }
121 2 : agent_param_->LogConfig();
122 :
123 : // Set the sample logger params
124 2 : Sandesh::set_logger_appender(agent_param_->log_file(),
125 2 : agent_param_->log_file_size(),
126 2 : agent_param_->log_files_count(),
127 4 : agent_param_->syslog_facility(),
128 2 : agent_param_->get_sample_destination(),
129 : module_name, true);
130 : // Set the SLO logger params
131 2 : Sandesh::set_logger_appender(agent_param_->log_file(),
132 2 : agent_param_->log_file_size(),
133 2 : agent_param_->log_files_count(),
134 4 : agent_param_->syslog_facility(),
135 2 : agent_param_->get_slo_destination(),
136 : module_name, false);
137 :
138 2 : Sandesh::set_send_to_collector_flags(agent_param_->get_sample_destination(),
139 2 : agent_param_->get_slo_destination());
140 :
141 2 : int ret = agent_param_->Validate();
142 2 : if (ret != 0) {
143 0 : return ret;
144 : }
145 :
146 2 : agent_param_->PostValidateLogConfig();
147 :
148 2 : int task_id = agent_->task_scheduler()->GetTaskId(AGENT_INIT_TASKNAME);
149 4 : trigger_.reset(new TaskTrigger(boost::bind(&AgentInit::InitBase, this),
150 2 : task_id, 0));
151 2 : trigger_->Set();
152 2 : return 0;
153 2 : }
154 :
155 : // Start init sequence
156 2 : bool AgentInit::InitBase() {
157 2 : FactoryInit();
158 2 : InitLoggingBase();
159 2 : CreatePeersBase();
160 2 : CreateModulesBase();
161 2 : CreateResourceManager();
162 2 : return true;
163 : }
164 :
165 2 : void AgentInit::SetResourceManagerReady() {
166 2 : agent_->SetResourceManagerReady();
167 2 : CreateDBTablesBase();
168 2 : RegisterDBClientsBase();
169 2 : InitModulesBase();
170 2 : InitCollectorBase();
171 2 : CreateVrfBase();
172 2 : CreateNextHopsBase();
173 2 : CreateInterfacesBase();
174 2 : InitDoneBase();
175 :
176 2 : Init();
177 2 : agent_->set_init_done(true);
178 2 : ConnectToControllerBase();
179 2 : }
180 :
181 2 : void AgentInit::InitLoggingBase() {
182 4 : Sandesh::SetLoggingParams(agent_param_->log_local(),
183 2 : agent_param_->log_category(),
184 2 : agent_param_->log_level(),
185 : false,
186 2 : agent_param_->log_flow());
187 2 : InitLogging();
188 2 : }
189 :
190 : // Connect to collector specified in config
191 2 : void AgentInit::InitCollectorBase() {
192 2 : agent_->InitCollector();
193 2 : InitCollector();
194 2 : }
195 :
196 : // Create peers
197 2 : void AgentInit::CreatePeersBase() {
198 2 : agent_->InitPeers();
199 2 : CreatePeers();
200 2 : }
201 :
202 : // Create the basic modules for agent operation.
203 : // Optional modules or modules that have different implementation are created
204 : // by init module
205 2 : void AgentInit::CreateModulesBase() {
206 : //Event notify manager
207 2 : event_notifier_.reset(new EventNotifier(agent()));
208 2 : agent()->set_event_notifier(event_notifier_.get());
209 :
210 2 : cfg_.reset(new AgentConfig(agent()));
211 2 : agent_->set_cfg(cfg_.get());
212 :
213 2 : oper_.reset(new OperDB(agent()));
214 2 : agent_->set_oper_db(oper_.get());
215 :
216 2 : if (enable_controller_) {
217 2 : controller_.reset(new VNController(agent()));
218 2 : agent_->set_controller(controller_.get());
219 : }
220 :
221 2 : stats_.reset(new AgentStats(agent()));
222 2 : agent()->set_stats(stats_.get());
223 :
224 2 : CreateModules();
225 2 : }
226 :
227 2 : void AgentInit::CreateResourceManager() {
228 2 : resource_manager_.reset(new ResourceManager(agent()));
229 2 : resource_manager_->Init();
230 2 : }
231 :
232 2 : void AgentInit::CreateDBTablesBase() {
233 2 : if (cfg_.get()) {
234 2 : cfg_->CreateDBTables(agent_->db());
235 : }
236 :
237 2 : if (oper_.get()) {
238 2 : oper_->CreateDBTables(agent_->db());
239 : }
240 :
241 2 : CreateDBTables();
242 2 : }
243 :
244 2 : void AgentInit::RegisterDBClientsBase() {
245 2 : if (cfg_.get()) {
246 2 : cfg_->RegisterDBClients(agent_->db());
247 : }
248 :
249 2 : if (oper_.get()) {
250 2 : oper_->RegisterDBClients();
251 : }
252 :
253 2 : RegisterDBClients();
254 2 : }
255 :
256 2 : void AgentInit::InitModulesBase() {
257 2 : if (cfg_.get()) {
258 2 : cfg_->Init();
259 : }
260 :
261 2 : if (oper_.get()) {
262 2 : oper_->Init();
263 : }
264 :
265 2 : InitModules();
266 2 : }
267 :
268 2 : static void CreateVrfIndependentNextHop(Agent *agent) {
269 :
270 2 : DiscardNH::Create();
271 2 : DiscardNHKey key1;
272 2 : NextHop *nh = static_cast<NextHop *>
273 2 : (agent->nexthop_table()->FindActiveEntry(&key1));
274 2 : agent->nexthop_table()->set_discard_nh(nh);
275 :
276 : //Reserve index 2, this would be used to
277 : //set as RPF NH when packet has to be discarded
278 : //due to source route mismatch
279 2 : assert(agent->nexthop_table()->ReserveIndex() ==
280 : NextHopTable::kRpfDiscardIndex);
281 2 : L2ReceiveNH::Create();
282 2 : L2ReceiveNHKey key2;
283 2 : nh = static_cast<NextHop *>
284 2 : (agent->nexthop_table()->FindActiveEntry(&key2));
285 2 : agent->nexthop_table()->set_l2_receive_nh(nh);
286 2 : }
287 :
288 2 : void AgentInit::CreateVrfBase() {
289 : // Bridge Receive routes are added on VRF creation. Ensure that Bridge
290 : // Receive-NH which is independent of VRF is created first
291 2 : CreateVrfIndependentNextHop(agent_.get());
292 :
293 : // Create the default VRF
294 2 : VrfTable *vrf_table = agent_->vrf_table();
295 :
296 2 : vrf_table->CreateStaticVrf(agent_->fabric_vrf_name());
297 2 : vrf_table->CreateFabricPolicyVrf(agent_->fabric_policy_vrf_name());
298 2 : VrfEntry *vrf = vrf_table->FindVrfFromName(agent_->fabric_vrf_name());
299 2 : assert(vrf);
300 2 : VrfEntry *policy_vrf = vrf_table->FindVrfFromName(agent_->
301 : fabric_policy_vrf_name());
302 2 : assert(policy_vrf);
303 :
304 2 : agent_->set_fabric_vrf(vrf);
305 2 : agent_->set_fabric_policy_vrf(policy_vrf);
306 2 : agent_->set_fabric_inet4_unicast_table(vrf->GetInet4UnicastRouteTable());
307 2 : agent_->set_fabric_inet4_mpls_table(vrf->GetInet4MplsUnicastRouteTable());
308 : agent_->set_fabric_inet4_multicast_table
309 2 : (vrf->GetInet4MulticastRouteTable());
310 2 : agent_->set_fabric_l2_unicast_table(vrf->GetBridgeRouteTable());
311 2 : agent_->set_fabric_evpn_table(vrf->GetEvpnRouteTable());
312 :
313 2 : CreateVrf();
314 2 : }
315 :
316 2 : void AgentInit::CreateNextHopsBase() {
317 2 : CreateNextHops();
318 2 : }
319 :
320 2 : void AgentInit::CreateInterfacesBase() {
321 2 : CreateInterfaces();
322 2 : }
323 :
324 2 : void AgentInit::ConnectToControllerBase() {
325 2 : if (agent_->router_id_configured() == false) {
326 0 : LOG(DEBUG,
327 : "Router ID not configured. Connection to controller postponed");
328 : } else {
329 2 : LOG(DEBUG, "Router ID configured. Connection to controller initiated");
330 : // Connect to controller and DNS servers
331 2 : agent_->controller()->Connect();
332 : }
333 :
334 2 : ConnectToController();
335 2 : if (agent_->controller()) {
336 2 : agent_->controller()->EnableWorkQueue();
337 : }
338 2 : }
339 :
340 2 : void AgentInit::InitDoneBase() {
341 2 : TaskScheduler *scheduler = agent_->task_scheduler();
342 : // Enable task latency measurements once init is done
343 2 : scheduler->EnableLatencyThresholds(agent_param_->tbb_exec_delay(),
344 2 : agent_param_->tbb_schedule_delay());
345 2 : agent_param_->vgw_config_table()->InitDone(agent_.get());
346 2 : if (cfg_.get()) {
347 2 : cfg_->InitDone();
348 : }
349 : // Enable task latency measurements once init is done
350 : scheduler->EnableLatencyThresholds
351 2 : (agent_param_->tbb_exec_delay() * 1000,
352 2 : agent_param_->tbb_schedule_delay() * 1000);
353 :
354 : // Flow related tasks are known have greater latency. Add exception
355 : // for them
356 2 : uint32_t execute_delay = (20 * 1000);
357 2 : uint32_t schedule_delay = (20 * 1000);
358 2 : scheduler->SetLatencyThreshold(kTaskFlowEvent, execute_delay,
359 : schedule_delay);
360 2 : scheduler->SetLatencyThreshold(kTaskFlowKSync, execute_delay,
361 : schedule_delay);
362 2 : scheduler->SetLatencyThreshold(kTaskFlowUpdate, execute_delay,
363 : schedule_delay);
364 2 : scheduler->SetLatencyThreshold(kTaskFlowStatsCollector, (execute_delay * 2),
365 : (schedule_delay * 2));
366 2 : scheduler->SetLatencyThreshold(kTaskSessionStatsCollector, (execute_delay * 2),
367 : (schedule_delay * 2));
368 2 : scheduler->SetLatencyThreshold(kTaskSessionStatsCollectorEvent, (execute_delay * 2),
369 : (schedule_delay * 2));
370 2 : agent_->InitDone();
371 2 : InitDone();
372 2 : }
373 :
374 : /****************************************************************************
375 : * Shutdown routines
376 : ***************************************************************************/
377 : typedef boost::function<bool(void)> TaskFnPtr;
378 40 : static void RunInTaskContext(AgentInit *init, uint32_t task_id, TaskFnPtr fn) {
379 40 : TaskTrigger trigger(fn, task_id, 0);
380 40 : trigger.Set();
381 40 : init->WaitForIdle();
382 80 : return;
383 40 : }
384 :
385 : // Shutdown IO channel to controller+DNS
386 2 : void AgentInit::IoShutdownBase() {
387 2 : agent_->controller()->Cleanup();
388 2 : agent_->controller()->DisConnect();
389 2 : IoShutdown();
390 2 : }
391 :
392 2 : static bool IoShutdownInternal(AgentInit *init) {
393 2 : init->IoShutdownBase();
394 2 : return true;
395 : }
396 :
397 2 : void AgentInit::FlushFlowsBase() {
398 2 : FlushFlows();
399 2 : return;
400 : }
401 :
402 2 : static bool FlushFlowsInternal(AgentInit *init) {
403 2 : init->FlushFlowsBase();
404 2 : return true;
405 : }
406 :
407 2 : void AgentInit::VgwShutdownBase() {
408 2 : VgwShutdown();
409 2 : return;
410 : }
411 :
412 2 : static bool VgwShutdownInternal(AgentInit *init) {
413 2 : init->VgwShutdownBase();
414 2 : return true;
415 : }
416 :
417 2 : void AgentInit::DeleteRoutesBase() {
418 2 : DeleteRoutes();
419 2 : if (agent_->oper_db())
420 2 : agent_->oper_db()->DeleteRoutes();
421 2 : }
422 :
423 2 : static bool DeleteRoutesInternal(AgentInit *init) {
424 2 : init->DeleteRoutesBase();
425 2 : return true;
426 : }
427 :
428 16 : static bool FlushTable(AgentDBTable *table) {
429 16 : table->Flush();
430 16 : return true;
431 : }
432 :
433 2 : void AgentInit::DeleteVhost() {
434 2 : DBRequest req(DBRequest::DB_ENTRY_DELETE);
435 2 : req.key.reset(new VmInterfaceKey(AgentKey::ADD_DEL_CHANGE,
436 2 : boost::uuids::nil_uuid(),
437 2 : agent_->vhost_interface_name()));
438 2 : VmInterfaceConfigData *data = new VmInterfaceConfigData(agent_.get(), NULL);
439 2 : req.data.reset(data);
440 2 : agent_->interface_table()->Enqueue(&req);
441 2 : }
442 :
443 2 : void AgentInit::DeleteDBEntriesBase() {
444 2 : int task_id = agent_->task_scheduler()->GetTaskId(AGENT_SHUTDOWN_TASKNAME);
445 :
446 2 : RunInTaskContext(this, task_id, boost::bind(&DeleteRoutesInternal, this));
447 2 : agent_->vrf_table()->DeleteStaticVrf(agent_->fabric_policy_vrf_name());
448 :
449 2 : agent_->vrf_table()->DeleteStaticVrf(agent_->fabric_policy_vrf_name());
450 :
451 2 : DeleteVhost();
452 :
453 2 : RunInTaskContext(this, task_id,
454 : boost::bind(&FlushTable, agent_->interface_table()));
455 2 : agent_->set_vhost_interface(NULL);
456 :
457 2 : RunInTaskContext(this, task_id,
458 : boost::bind(&FlushTable, agent_->vm_table()));
459 :
460 2 : RunInTaskContext(this, task_id,
461 : boost::bind(&FlushTable, agent_->vn_table()));
462 :
463 :
464 2 : agent_->vrf_table()->DeleteStaticVrf(agent_->fabric_vrf_name());
465 2 : RunInTaskContext(this, task_id,
466 : boost::bind(&FlushTable, agent_->vrf_table()));
467 :
468 2 : RunInTaskContext(this, task_id,
469 : boost::bind(&FlushTable, agent_->nexthop_table()));
470 2 : agent_->nexthop_table()->set_discard_nh(NULL);
471 :
472 :
473 2 : RunInTaskContext(this, task_id,
474 : boost::bind(&FlushTable, agent_->sg_table()));
475 :
476 2 : RunInTaskContext(this, task_id,
477 : boost::bind(&FlushTable, agent_->acl_table()));
478 :
479 2 : RunInTaskContext(this, task_id,
480 : boost::bind(&FlushTable, agent_->mp_table()));
481 2 : }
482 :
483 16 : static bool WaitForDbCount(DBTableBase *table, AgentInit *init,
484 : uint32_t count, int msec) {
485 20016 : while ((table->Size() > count) && (msec > 0)) {
486 20000 : init->WaitForIdle();
487 20000 : usleep(1000);
488 20000 : msec -= 1;
489 : }
490 :
491 16 : return (table->Size() == count);
492 : }
493 :
494 2 : void AgentInit::WaitForDBEmpty() {
495 2 : WaitForDbCount(agent_->interface_table(), this, 0, 10000);
496 2 : WaitForDbCount(agent_->vrf_table(), this, 0, 10000);
497 2 : WaitForDbCount(agent_->nexthop_table(), this, 0, 10000);
498 2 : WaitForDbCount(agent_->vm_table(), this, 0, 10000);
499 2 : WaitForDbCount(agent_->vn_table(), this, 0, 10000);
500 2 : WaitForDbCount(agent_->mpls_table(), this, 2, 10000);
501 2 : WaitForDbCount(agent_->acl_table(), this, 0, 10000);
502 2 : WaitForDbCount(agent_->mp_table(), this, 0, 10000);
503 2 : }
504 :
505 2 : void AgentInit::ServicesShutdownBase() {
506 2 : ServicesShutdown();
507 2 : return;
508 : }
509 :
510 2 : static bool ServicesShutdownInternal(AgentInit *init) {
511 2 : init->ServicesShutdownBase();
512 2 : return true;
513 : }
514 :
515 2 : void AgentInit::PktShutdownBase() {
516 2 : PktShutdown();
517 2 : return;
518 : }
519 :
520 2 : static bool PktShutdownInternal(AgentInit *init) {
521 2 : init->PktShutdownBase();
522 2 : return true;
523 : }
524 :
525 2 : void AgentInit::ProfileShutdownBase() {
526 2 : if (agent_->oper_db() && agent_->oper_db()->agent_profile()) {
527 2 : agent_->oper_db()->agent_profile()->Shutdown();
528 : }
529 2 : }
530 :
531 2 : static bool ProfileShutdownInternal(AgentInit *init) {
532 2 : init->ProfileShutdownBase();
533 2 : return true;
534 : }
535 :
536 2 : void AgentInit::ModulesShutdownBase() {
537 2 : ModulesShutdown();
538 2 : if (agent_->oper_db()) {
539 2 : agent_->oper_db()->Shutdown();
540 : }
541 :
542 2 : if (agent_->cfg()) {
543 2 : agent_->cfg()->Shutdown();
544 : }
545 2 : return;
546 : }
547 :
548 2 : static bool ModulesShutdownInternal(AgentInit *init) {
549 2 : init->ModulesShutdownBase();
550 2 : return true;
551 : }
552 :
553 2 : void AgentInit::UveShutdownBase() {
554 2 : UveShutdown();
555 2 : return;
556 : }
557 :
558 2 : void AgentInit::StatsCollectorShutdownBase() {
559 2 : StatsCollectorShutdown();
560 2 : return;
561 : }
562 :
563 2 : void AgentInit::FlowStatsCollectorShutdownBase() {
564 2 : FlowStatsCollectorShutdown();
565 2 : return;
566 : }
567 :
568 2 : static bool UveShutdownInternal(AgentInit *init) {
569 2 : init->UveShutdownBase();
570 2 : return true;
571 : }
572 :
573 2 : static bool StatsCollectorShutdownInternal(AgentInit *init) {
574 2 : init->StatsCollectorShutdownBase();
575 2 : return true;
576 : }
577 :
578 2 : static bool FlowStatsCollectorShutdownInternal(AgentInit *init) {
579 2 : init->FlowStatsCollectorShutdownBase();
580 2 : return true;
581 : }
582 :
583 2 : void AgentInit::KSyncShutdownBase() {
584 2 : KSyncShutdown();
585 2 : return;
586 : }
587 :
588 2 : static bool KSyncShutdownInternal(AgentInit *init) {
589 2 : init->KSyncShutdownBase();
590 2 : return true;
591 : }
592 :
593 2 : void AgentInit::Shutdown() {
594 2 : int task_id = agent_->task_scheduler()->GetTaskId(AGENT_SHUTDOWN_TASKNAME);
595 :
596 2 : DeleteDBEntriesBase();
597 2 : RunInTaskContext(this, task_id, boost::bind(&IoShutdownInternal, this));
598 2 : RunInTaskContext(this, task_id, boost::bind(&ProfileShutdownInternal, this));
599 2 : RunInTaskContext(this, task_id, boost::bind(&FlushFlowsInternal, this));
600 2 : RunInTaskContext(this, task_id, boost::bind(&VgwShutdownInternal, this));
601 2 : WaitForDBEmpty();
602 2 : RunInTaskContext(this, task_id, boost::bind(&ServicesShutdownInternal,
603 : this));
604 2 : RunInTaskContext(this, task_id, boost::bind
605 : (&FlowStatsCollectorShutdownInternal, this));
606 2 : RunInTaskContext(this, task_id, boost::bind(&StatsCollectorShutdownInternal,
607 : this));
608 2 : RunInTaskContext(this, task_id, boost::bind(&UveShutdownInternal, this));
609 2 : RunInTaskContext(this, task_id, boost::bind(&PktShutdownInternal, this));
610 2 : RunInTaskContext(this, task_id, boost::bind(&ModulesShutdownInternal,
611 : this));
612 2 : RunInTaskContext(this, task_id, boost::bind(&KSyncShutdownInternal, this));
613 :
614 2 : Sandesh::Uninit();
615 2 : WaitForIdle();
616 :
617 2 : agent_->event_manager()->Shutdown();
618 2 : WaitForIdle();
619 2 : }
|