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