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