Kea  2.5.2
netconf.cc
Go to the documentation of this file.
1 // Copyright (C) 2018-2023 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
9 
10 #include <config.h>
11 
12 #include <cc/command_interpreter.h>
13 #include <netconf/netconf.h>
15 #include <netconf/netconf_log.h>
16 #include <yang/translator_config.h>
17 #include <yang/yang_revisions.h>
18 
19 #include <sstream>
20 #include <vector>
21 
22 using namespace std;
23 using namespace isc::config;
24 using namespace isc::data;
25 using namespace isc::netconf;
26 using namespace isc::yang;
27 using namespace libyang;
28 using namespace sysrepo;
29 
30 namespace {
31 
33 class NetconfAgentCallback {
34 public:
38  NetconfAgentCallback(const CfgServersMapPair& service_pair)
39  : service_pair_(service_pair) {
40  }
41 
43  CfgServersMapPair const service_pair_;
44 
55  sysrepo::ErrorCode module_change(Session sess,
56  uint32_t /* subscription_id */,
57  string_view module_name,
58  optional<string_view> /* sub_xpath */,
59  Event event,
60  uint32_t /* request_id */) {
61  ostringstream event_type;
62  switch (event) {
63  case Event::Update:
64  // This could potentially be a hook point for mid-flight
65  // configuration changes.
66  event_type << "Event::Update";
67  break;
68  case Event::Change:
69  event_type << "Event::Change";
70  break;
71  case Event::Done:
72  event_type << "Event::Done";
73  break;
74  case Event::Abort:
75  event_type << "Event::Abort";
76  break;
77  case Event::Enabled:
78  event_type << "Event::Enabled";
79  break;
80  case Event::RPC:
81  event_type << "Event::RPC";
82  break;
83  default:
84  event_type << "UNKNOWN (" << event << ")";
85  break;
86  }
88  .arg(event_type.str());
89  NetconfAgent::logChanges(sess, module_name);
90  switch (event) {
91  case Event::Change:
92  return (NetconfAgent::change(sess, service_pair_));
93  case Event::Done:
94  return (NetconfAgent::done(sess, service_pair_));
95  default:
96  return (sysrepo::ErrorCode::Ok);
97  }
98  }
99 
100  void event_notif(Session /* session */,
101  uint32_t /* subscription_id */,
102  NotificationType const notification_type,
103  optional<DataNode> const notification_tree,
104  NotificationTimeStamp const /* timestamp */) {
105  string n;
106  switch (notification_type) {
107  case NotificationType::Realtime:
108  n = "NotificationType::Realtime";
109  break;
110  case NotificationType::Replay:
111  n = "NotificationType::Replay";
112  break;
113  case NotificationType::ReplayComplete:
114  n = "NotificationType::ReplayComplete";
115  break;
116  case NotificationType::Terminated:
117  n = "NotificationType::Terminated";
118  break;
119  case NotificationType::Modified:
120  n = "NotificationType::Modified";
121  break;
122  case NotificationType::Suspended:
123  n = "NotificationType::Suspended";
124  break;
125  case NotificationType::Resumed:
126  n = "NotificationType::Resumed";
127  break;
128  }
129 
130  optional<string> const str(
131  notification_tree->printStr(DataFormat::JSON, PrintFlags::WithDefaultsExplicit));
132  string const tree(str ? *str : string());
134  .arg(n)
135  .arg(service_pair_.first)
136  .arg(tree);
137  }
138 }; // NetconfAgentCallback
139 
140 } //anonymous namespace
141 
142 namespace isc {
143 namespace netconf {
144 
145 NetconfAgent::~NetconfAgent() {
146  clear();
147 }
148 
149 void
150 NetconfAgent::init(NetconfCfgMgrPtr cfg_mgr) {
151  // Check for a configuration manager.
152  if (!cfg_mgr) {
153  isc_throw(Unexpected, "missing configuration manager");
154  return;
155  }
156 
157  // Retrieve configuration from existing running DHCP daemons.
158  const CfgServersMapPtr& servers =
159  cfg_mgr->getNetconfConfig()->getCfgServersMap();
160  for (auto const& pair : *servers) {
161  keaConfig(pair);
162  }
163 
164  // Initialize sysrepo.
165  initSysrepo();
166 
167  // Check modules / revisions.
168  checkModules(servers);
169 
170  for (auto const& pair : *servers) {
171  yangConfig(pair);
172  subscribeToDataChanges(pair);
173  subscribeToNotifications(pair);
174  }
175 }
176 
177 void
178 NetconfAgent::clear() {
179  subscriptions_.clear();
180  running_sess_.reset();
181  startup_sess_.reset();
182 }
183 
184 void
185 NetconfAgent::keaConfig(const CfgServersMapPair& service_pair) {
186  string const& server(service_pair.first);
187  CfgServerPtr const& configuration(service_pair.second);
188 
189  // If the boot-update flag is not set.
190  if (!configuration->getBootUpdate()) {
191  return;
192  }
193  CfgControlSocketPtr ctrl_sock = configuration->getCfgControlSocket();
194  if (!ctrl_sock) {
195  return;
196  }
198  try {
199  comm = controlSocketFactory(ctrl_sock);
200  } catch (exception const& ex) {
201  ostringstream msg;
202  msg << "createControlSocket failed with " << ex.what();
204  .arg(server)
205  .arg(msg.str());
206  return;
207  }
208  ConstElementPtr answer;
209  int rcode;
210  ConstElementPtr config;
212  .arg(server);
213  try {
214  answer = comm->configGet(server);
215  config = parseAnswer(rcode, answer);
216  } catch (exception const& ex) {
217  ostringstream msg;
218  msg << "config-get command failed with " << ex.what();
220  .arg(server)
221  .arg(msg.str());
222  return;
223  }
224  if (rcode != CONTROL_RESULT_SUCCESS) {
225  ostringstream msg;
226  msg << "config-get command returned " << answerToText(answer);
228  .arg(server)
229  .arg(msg.str());
230  return;
231  }
232  if (!config) {
234  .arg(server)
235  .arg("config-get command returned an empty configuration");
236  return;
237  }
240  .arg(server)
241  .arg(prettyPrint(config));
242 }
243 
244 void
245 NetconfAgent::initSysrepo() {
246  try {
247  running_sess_ = Connection{}.sessionStart();
248  running_sess_->switchDatastore(Datastore::Running);
249  startup_sess_ = Connection{}.sessionStart();
250  startup_sess_->switchDatastore(Datastore::Startup);
251  } catch (exception const& ex) {
252  isc_throw(Unexpected, "Can't establish a sysrepo session: "
253  << ex.what());
254  }
255 
256  // Retrieve names and revisions of installed modules from sysrepo.
257  getModules();
258 }
259 
260 void NetconfAgent::getModules() {
261  vector<Module> modules;
262  try {
263  Context context(running_sess_->getContext());
264  modules = context.modules();
265  } catch (Error const& ex) {
266  isc_throw(Unexpected, "can't retrieve available modules: " << ex.what());
267  }
268 
269  for (Module const& module : modules) {
270  string const name(module.name());
271  if (!module.revision()) {
273  "could not retrieve module revision for module " << name);
274  }
275  string const revision(*module.revision());
276  modules_.emplace(name, revision);
277  }
278 }
279 
280 bool
281 NetconfAgent::checkModule(const string& module_name) const {
282  auto module = modules_.find(module_name);
283  if (module == modules_.end()) {
285  .arg(module_name);
286  return (false);
287  }
288  auto modrev = YANG_REVISIONS.find(module_name);
289  if (modrev == YANG_REVISIONS.end()) {
290  // Can't check revision?!
291  // It can happen only with a module which is not in
292  // YANG_REVISIONS but installed so likely on purpose.
293  return (true);
294  }
295  if (modrev->second != module->second) {
297  .arg(module_name)
298  .arg(modrev->second)
299  .arg(module->second);
300  return (false);
301  }
302  return (true);
303 }
304 
305 void
306 NetconfAgent::checkModules(CfgServersMapPtr const& servers /* = {} */) const {
307  bool faulty_model(false);
308  if (servers) {
309  for (auto pair : *servers) {
310  if (!checkModule(pair.second->getModel())) {
311  faulty_model = true;
312  }
313  }
314  }
315 
316  if (faulty_model) {
317  isc_throw(Unexpected, "YANG module is missing or its revision is not "
318  "supported. Check logs for details.");
319  }
320 
321  for (auto modrev : YANG_REVISIONS) {
322  auto module = modules_.find(modrev.first);
323  if (module == modules_.end()) {
325  .arg(modrev.first);
326  continue;
327  }
328  if (modrev.second != module->second) {
330  .arg(modrev.first)
331  .arg(modrev.second)
332  .arg(module->second);
333  }
334  }
335 }
336 
337 void
338 NetconfAgent::yangConfig(const CfgServersMapPair& service_pair) {
339  string const& server(service_pair.first);
340  CfgServerPtr const& configuration(service_pair.second);
341 
342  // If we're shutting down, or the boot-update flag is not set or the model
343  // associated with it is not specified.
344  if (!configuration->getBootUpdate() ||
345  configuration->getModel().empty()) {
346  return;
347  }
348 
349  // First we need a way to reach the actual servers.
350  CfgControlSocketPtr ctrl_sock = configuration->getCfgControlSocket();
351  if (!ctrl_sock) {
352  return;
353  }
354 
356  .arg(server);
357  ElementPtr config;
358  try {
359  // Retrieve configuration from Sysrepo.
360  TranslatorConfig tc(*startup_sess_, configuration->getModel());
361  config = tc.getConfig();
362  if (!config) {
363  ostringstream msg;
364  msg << "YANG configuration for "
365  << configuration->getModel()
366  << " is empty";
368  .arg(server)
369  .arg(msg.str());
370  return;
371  } else {
374  .arg(server)
375  .arg(prettyPrint(config));
376  }
377  } catch (exception const& ex) {
378  ostringstream msg;
379  msg << "get YANG configuration for " << server
380  << " failed with " << ex.what();
382  .arg(server)
383  .arg(msg.str());
384  return;
385  }
387  try {
388  comm = controlSocketFactory(ctrl_sock);
389  } catch (exception const& ex) {
390  ostringstream msg;
391  msg << "control socket creation failed with " << ex.what();
393  .arg(server)
394  .arg(msg.str());
395  return;
396  }
397  ConstElementPtr answer;
398  int rcode;
399  try {
400  answer = comm->configSet(config, server);
401  parseAnswer(rcode, answer);
402  } catch (exception const& ex) {
403  ostringstream msg;
404  msg << "config-set command failed with " << ex.what();
406  .arg(server)
407  .arg(msg.str());
408  return;
409  }
410  if (rcode != CONTROL_RESULT_SUCCESS) {
411  ostringstream msg;
412  msg << "config-set command returned " << answerToText(answer);
414  .arg(server)
415  .arg(msg.str());
416  return;
417  }
419  .arg(server);
420 }
421 
422 void
423 NetconfAgent::subscribeToDataChanges(const CfgServersMapPair& service_pair) {
424  string const& server(service_pair.first);
425  CfgServerPtr const& configuration(service_pair.second);
426  string const& model(configuration->getModel());
427 
428  // If we're shutting down, or the subscribe-changes flag is not set or
429  // the model is not specified, give up on subscribing.
430  if (!configuration->getSubscribeChanges() || model.empty()) {
431  return;
432  }
434  .arg(server)
435  .arg(model);
436  auto callback = [=](Session session,
437  uint32_t subscription_id,
438  string_view module_name,
439  optional<string_view> sub_xpath,
440  Event event,
441  uint32_t request_id) {
442  NetconfAgentCallback agent(service_pair);
443  return agent.module_change(session, subscription_id, module_name, sub_xpath, event, request_id);
444  };
445  try {
446  SubscribeOptions options(SubscribeOptions::Default);
447  if (!configuration->getValidateChanges()) {
448  options = options | SubscribeOptions::DoneOnly;
449  }
450  Subscription subscription(
451  running_sess_->onModuleChange(model, callback, nullopt, 0, options));
452  subscriptions_.emplace(server, std::forward<Subscription>(subscription));
453  } catch (exception const& ex) {
454  ostringstream msg;
455  msg << "module change subscribe failed with " << ex.what();
456  msg << "change subscription for model " << model <<
457  " failed with: " << ex.what();
459  .arg(server)
460  .arg(configuration->getModel())
461  .arg(msg.str());
462  return;
463  }
464 }
465 
466 void
467 NetconfAgent::subscribeToNotifications(const CfgServersMapPair& service_pair) {
468  string const& server(service_pair.first);
469  CfgServerPtr const& configuration(service_pair.second);
470  string const& model(configuration->getModel());
471 
472  // If we're shutting down, or the subscribe-changes flag is not set or
473  // the model is not specified, give up on subscribing.
474  if (!configuration->getSubscribeNotifications() || model.empty()) {
475  return;
476  }
478  .arg(server)
479  .arg(model);
480 
481  auto callback = [=](Session session,
482  uint32_t subscription_id,
483  NotificationType const notification_type,
484  optional<DataNode> const notification_tree,
485  NotificationTimeStamp const timestamp) {
486  NetconfAgentCallback agent(service_pair);
487  return agent.event_notif(session, subscription_id, notification_type, notification_tree, timestamp);
488  };
489  try {
490  Subscription subscription(running_sess_->onNotification(model, callback));
491  subscriptions_.emplace(server, std::forward<Subscription>(subscription));
492  } catch (exception const& ex) {
493  ostringstream msg;
494  msg << "event notification subscription for model " << model <<
495  " failed with: " << ex.what();
497  .arg(server)
498  .arg(configuration->getModel())
499  .arg(msg.str());
500  return;
501  }
502 }
503 
504 sysrepo::ErrorCode
505 NetconfAgent::change(Session sess, const CfgServersMapPair& service_pair) {
506  string const& server(service_pair.first);
507  CfgServerPtr const& configuration(service_pair.second);
508 
509  // If we're shutting down, or the subscribe-changes or the
510  // validate-changes flag is not set or the model associated with
511  // it is not specified.
512  if (!configuration->getSubscribeChanges() ||
513  !configuration->getValidateChanges() ||
514  configuration->getModel().empty()) {
515  return (sysrepo::ErrorCode::Ok);
516  }
517  CfgControlSocketPtr ctrl_sock = configuration->getCfgControlSocket();
518  if (!ctrl_sock) {
519  return (sysrepo::ErrorCode::Ok);
520  }
522  .arg(server);
523  ElementPtr config;
524  try {
525  TranslatorConfig tc(sess, configuration->getModel());
526  config = tc.getConfig();
527  if (!config) {
528  ostringstream msg;
529  msg << "YANG configuration for "
530  << configuration->getModel()
531  << " is empty";
533  .arg(server)
534  .arg(msg.str());
535  return (sysrepo::ErrorCode::OperationFailed);
536  } else {
539  .arg(server)
540  .arg(prettyPrint(config));
541  }
542  } catch (exception const& ex) {
543  ostringstream msg;
544  msg << "get YANG configuration for " << server
545  << " failed with " << ex.what();
547  .arg(server)
548  .arg(msg.str());
549  return (sysrepo::ErrorCode::ValidationFailed);
550  }
552  try {
553  comm = controlSocketFactory(ctrl_sock);
554  } catch (exception const& ex) {
555  ostringstream msg;
556  msg << "createControlSocket failed with " << ex.what();
558  .arg(server)
559  .arg(msg.str());
560  return (sysrepo::ErrorCode::Ok);
561  }
562  ConstElementPtr answer;
563  int rcode;
564  try {
565  answer = comm->configTest(config, server);
566  parseAnswer(rcode, answer);
567  } catch (exception const& ex) {
568  stringstream msg;
569  msg << "configTest failed with " << ex.what();
571  .arg(server)
572  .arg(msg.str());
573  return (sysrepo::ErrorCode::ValidationFailed);
574  }
575  if (rcode != CONTROL_RESULT_SUCCESS) {
576  stringstream msg;
577  msg << "configTest returned " << answerToText(answer);
579  .arg(server)
580  .arg(msg.str());
581  return (sysrepo::ErrorCode::ValidationFailed);
582  }
584  .arg(server);
585  return (sysrepo::ErrorCode::Ok);
586 }
587 
588 sysrepo::ErrorCode
589 NetconfAgent::done(Session sess, const CfgServersMapPair& service_pair) {
590  string const& server(service_pair.first);
591  CfgServerPtr const& configuration(service_pair.second);
592 
593  // Check if we should and can process this update.
594  if (!configuration->getSubscribeChanges() ||
595  configuration->getModel().empty()) {
596  return (sysrepo::ErrorCode::Ok);
597  }
598  CfgControlSocketPtr ctrl_sock = configuration->getCfgControlSocket();
599  if (!ctrl_sock) {
600  return (sysrepo::ErrorCode::Ok);
601  }
602 
603  // All looks good, let's get started. Print an info that we're about
604  // to update the configuration.
606  .arg(server);
607 
608  // Retrieve the configuration from SYSREPO first.
609  ElementPtr config;
610  try {
611  TranslatorConfig tc(sess, configuration->getModel());
612  config = tc.getConfig();
613  if (!config) {
614  ostringstream msg;
615  msg << "YANG configuration for "
616  << configuration->getModel()
617  << " is empty";
619  .arg(server)
620  .arg(msg.str());
621  return (sysrepo::ErrorCode::ValidationFailed);
622  } else {
625  .arg(server)
626  .arg(prettyPrint(config));
627  }
628  } catch (exception const& ex) {
629  ostringstream msg;
630  msg << "get YANG configuration for " << server
631  << " failed with " << ex.what();
633  .arg(server)
634  .arg(msg.str());
635  return (sysrepo::ErrorCode::ValidationFailed);
636  }
637 
638  // Ok, now open the control socket. We need this to send the config to
639  // the server.
641  try {
642  comm = controlSocketFactory(ctrl_sock);
643  } catch (exception const& ex) {
644  ostringstream msg;
645  msg << "createControlSocket failed with " << ex.what();
647  .arg(server)
648  .arg(msg.str());
649  return (sysrepo::ErrorCode::Ok);
650  }
651 
652  // Now apply the config using config-set command.
653  ConstElementPtr answer;
654  int rcode;
655  try {
656  answer = comm->configSet(config, server);
657  parseAnswer(rcode, answer);
658  } catch (exception const& ex) {
659  stringstream msg;
660  msg << "configSet failed with " << ex.what();
662  .arg(server)
663  .arg(msg.str());
664  return (sysrepo::ErrorCode::ValidationFailed);
665  }
666 
667  // rcode == CONTROL_RESULT_SUCCESS, unless the docs say otherwise :).
668  if (rcode != CONTROL_RESULT_SUCCESS) {
669  stringstream msg;
670  msg << "configSet returned " << answerToText(answer);
672  .arg(server)
673  .arg(msg.str());
674  return (sysrepo::ErrorCode::ValidationFailed);
675  }
677  .arg(server);
678  return (sysrepo::ErrorCode::Ok);
679 }
680 
681 void
682 NetconfAgent::logChanges(Session sess, string_view const& model) {
683  ostringstream stream;
684  stream << "/" << model << ":*//.";
685  string const xpath(stream.str());
686  ChangeCollection const changes(sess.getChanges(xpath));
687  for (Change const& change : changes) {
688  ostringstream msg;
689  switch (change.operation) {
690  case sysrepo::ChangeOperation::Created:
691  msg << "created: ";
692  break;
693  case sysrepo::ChangeOperation::Deleted:
694  msg << "deleted: ";
695  break;
696  case sysrepo::ChangeOperation::Modified:
697  msg << "modified: ";
698  break;
699  case sysrepo::ChangeOperation::Moved:
700  msg << "moved: ";
701  break;
702  default:
703  msg << "unknown operation (" << change.operation << "): ";
704  }
705  string const path(change.node.path());
706  msg << path;
707  SchemaNode const& schema(change.node.schema());
708  NodeType const node_type(schema.nodeType());
709  if (node_type == NodeType::Container) {
710  msg << " (container)";
711  } else if (node_type == NodeType::List) {
712  msg << " (list)";
713  } else {
714  optional<string> const str(
715  Translator::translateToYang(Translator::translateFromYang(change.node),
716  LeafBaseType::Unknown));
717  if (str) {
718  msg << " = " << *str;
719  }
720  }
721 
724  .arg(msg.str());
725  }
726 }
727 
728 void
729 NetconfAgent::announceShutdown() const {
730  isc::process::DControllerBasePtr& controller(NetconfController::instance());
731  if (controller) {
732  boost::dynamic_pointer_cast<NetconfController>(controller)
733  ->getNetconfProcess()
734  ->setShutdownFlag(true);
735  }
736 }
737 
738 bool NetconfAgent::shouldShutdown() const {
739  return boost::dynamic_pointer_cast<NetconfController>(NetconfController::instance())
740  ->getNetconfProcess()
741  ->shouldShutdown();
742 }
743 
744 } // namespace netconf
745 } // namespace isc
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
DHCP configuration translation between YANG and JSON.
isc::data::ElementPtr getConfig()
Translate the whole DHCP server configuration from YANG to JSON.
This file contains several functions and constants that are used for handling commands and responses ...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition: macros.h:32
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
std::string answerToText(const ConstElementPtr &msg)
void prettyPrint(ConstElementPtr element, std::ostream &out, unsigned indent, unsigned step)
Pretty prints the data into stream.
Definition: data.cc:1522
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:29
boost::shared_ptr< Element > ElementPtr
Definition: data.h:26
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_FAILED
const int NETCONF_DBG_TRACE_DETAIL_DATA
Additional information.
Definition: netconf_log.h:41
const isc::log::MessageID NETCONF_GET_CONFIG_STARTED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_REJECTED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_CONFIG_CHANGE_EVENT
isc::log::Logger netconf_logger(NETCONF_LOGGER_NAME)
Base logger for the netconf agent.
Definition: netconf_log.h:49
const isc::log::MessageID NETCONF_VALIDATE_CONFIG
const isc::log::MessageID NETCONF_GET_CONFIG_FAILED
const isc::log::MessageID NETCONF_MODULE_REVISION_WARN
const isc::log::MessageID NETCONF_GET_CONFIG
std::shared_ptr< CfgServersMap > CfgServersMapPtr
Defines a pointer to map of CfgServers.
const isc::log::MessageID NETCONF_CONFIG_CHANGED_DETAIL
std::pair< std::string, CfgServerPtr > CfgServersMapPair
Defines a iterator pairing of name and CfgServer.
const isc::log::MessageID NETCONF_SET_CONFIG_FAILED
std::shared_ptr< CfgServer > CfgServerPtr
Defines a pointer for CfgServer instances.
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_STARTED
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG
const isc::log::MessageID NETCONF_MODULE_MISSING_ERR
std::shared_ptr< CfgControlSocket > CfgControlSocketPtr
Defines a pointer for CfgControlSocket instances.
const isc::log::MessageID NETCONF_NOTIFICATION_RECEIVED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_MODULE_REVISION_ERR
const isc::log::MessageID NETCONF_SUBSCRIBE_NOTIFICATIONS
const isc::log::MessageID NETCONF_SET_CONFIG_STARTED
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG_FAILED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_FAILED
const isc::log::MessageID NETCONF_BOOT_UPDATE_COMPLETED
const isc::log::MessageID NETCONF_SET_CONFIG
const isc::log::MessageID NETCONF_UPDATE_CONFIG
const isc::log::MessageID NETCONF_UPDATE_CONFIG_STARTED
ControlSocketBasePtr controlSocketFactory(CfgControlSocketPtr ctrl_sock)
Factory function for control sockets.
std::shared_ptr< ControlSocketBase > ControlSocketBasePtr
Type definition for the pointer to the ControlSocketBase.
const isc::log::MessageID NETCONF_MODULE_MISSING_WARN
const isc::log::MessageID NETCONF_NOT_SUBSCRIBED_TO_NOTIFICATIONS
boost::shared_ptr< NetconfCfgMgr > NetconfCfgMgrPtr
Defines a shared pointer to NetconfCfgMgr.
boost::shared_ptr< DControllerBase > DControllerBasePtr
Definition: d_controller.h:77
LabeledValue Event
Define an Event.
Definition: state_model.h:31
Defines the logger used by the top-level component of kea-lfc.
Contains declarations for loggers used by the Kea netconf agent.