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