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