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