| Kea 3.0.2-git

netconf.cc
Go to the documentation of this file.
1// Copyright (C) 2018-2024 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>
14#include <netconf/netconf_controller.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 moduleChange(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 }
87 LOG_INFO(netconf_logger, NETCONF_CONFIG_CHANGE_EVENT)
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 eventNotif(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 string tree;
131 if (notification_tree) {
132 optional<string> const str(
133 notification_tree->printStr(DataFormat::JSON, PrintFlags::WithDefaultsExplicit));
134 if (str) {
135 tree = *str;
136 }
137 }
138 LOG_INFO(netconf_logger, NETCONF_NOTIFICATION_RECEIVED)
139 .arg(n)
140 .arg(service_pair_.first)
141 .arg(tree);
142 }
143}; // NetconfAgentCallback
144
145} // anonymous namespace
146
147 namespace isc {
148 namespace netconf {
149
150 NetconfAgent::~NetconfAgent() {
151 clear();
152}
153
154 void
155 NetconfAgent::init(NetconfCfgMgrPtr cfg_mgr) {
156 // Check for a configuration manager.
157 if (!cfg_mgr) {
158 isc_throw(Unexpected, "missing configuration manager");
159 return;
160 }
161
162 // Retrieve configuration from existing running DHCP daemons.
163 const CfgServersMapPtr& servers =
164 cfg_mgr->getNetconfConfig()->getCfgServersMap();
165 for (auto const& pair : *servers) {
166 keaConfig(pair);
167 }
168
169 // Initialize sysrepo.
170 initSysrepo();
171
172 // Check modules / revisions.
173 checkModules(servers);
174
175 for (auto const& pair : *servers) {
176 yangConfig(pair);
177 subscribeToDataChanges(pair);
178 subscribeToNotifications(pair);
179 }
180}
181
182 void
183 NetconfAgent::clear() {
184 subscriptions_.clear();
185 running_sess_.reset();
186 startup_sess_.reset();
187}
188
189 void
190 NetconfAgent::keaConfig(const CfgServersMapPair& service_pair) {
191 string const& server(service_pair.first);
192 CfgServerPtr const& configuration(service_pair.second);
193
194 // If the boot-update flag is not set.
195 if (!configuration->getBootUpdate()) {
196 return;
197 }
198 CfgControlSocketPtr ctrl_sock = configuration->getCfgControlSocket();
199 if (!ctrl_sock) {
200 return;
201 }
202 ControlSocketBasePtr comm;
203 try {
204 comm = controlSocketFactory(ctrl_sock);
205 } catch (exception const& ex) {
206 ostringstream msg;
207 msg << "createControlSocket failed with " << ex.what();
208 LOG_ERROR(netconf_logger, NETCONF_GET_CONFIG_FAILED)
209 .arg(server)
210 .arg(msg.str());
211 return;
212 }
213 ConstElementPtr answer;
214 int rcode;
215 ConstElementPtr config;
216 LOG_INFO(netconf_logger, NETCONF_GET_CONFIG_STARTED)
217 .arg(server);
218 try {
219 answer = comm->configGet(server);
220 config = parseAnswer(rcode, answer);
221 } catch (exception const& ex) {
222 ostringstream msg;
223 msg << "config-get command failed with " << ex.what();
224 LOG_ERROR(netconf_logger, NETCONF_GET_CONFIG_FAILED)
225 .arg(server)
226 .arg(msg.str());
227 return;
228 }
229 if (rcode != CONTROL_RESULT_SUCCESS) {
230 ostringstream msg;
231 msg << "config-get command returned " << answerToText(answer);
232 LOG_ERROR(netconf_logger, NETCONF_GET_CONFIG_FAILED)
233 .arg(server)
234 .arg(msg.str());
235 return;
236 }
237 if (!config) {
238 LOG_ERROR(netconf_logger, NETCONF_GET_CONFIG_FAILED)
239 .arg(server)
240 .arg("config-get command returned an empty configuration");
241 return;
242 }
243 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
244 NETCONF_GET_CONFIG)
245 .arg(server)
246 .arg(prettyPrint(config));
247}
248
249 void
250 NetconfAgent::initSysrepo() {
251 try {
252 running_sess_ = Connection{}.sessionStart();
253 running_sess_->switchDatastore(Datastore::Running);
254 startup_sess_ = Connection{}.sessionStart();
255 startup_sess_->switchDatastore(Datastore::Startup);
256 } catch (exception const& ex) {
257 isc_throw(Unexpected, "Can't establish a sysrepo session: " << ex.what());
258 }
259
260 // Retrieve names and revisions of installed modules from sysrepo.
261 getModules();
262}
263
264 void
265 NetconfAgent::getModules() {
266 vector<Module> modules;
267 try {
268 Context context(running_sess_->getContext());
269 modules = context.modules();
270 } catch (Error const& ex) {
271 isc_throw(Unexpected, "can't retrieve available modules: " << ex.what());
272 }
273
274 for (Module const& module : modules) {
275 string const name(module.name());
276 if (!module.revision()) {
277 isc_throw(Unexpected, "could not retrieve module revision for module " << name);
278 }
279 string const revision(*module.revision());
280 modules_.emplace(name, revision);
281 }
282}
283
284 bool
285 NetconfAgent::checkModule(const string& module_name) const {
286 auto module = modules_.find(module_name);
287 if (module == modules_.end()) {
288 LOG_ERROR(netconf_logger, NETCONF_MODULE_MISSING_ERR)
289 .arg(module_name);
290 return (false);
291 }
292 auto modrev = YANG_REVISIONS.find(module_name);
293 if (modrev == YANG_REVISIONS.end()) {
294 // Can't check revision?!
295 // It can happen only with a module which is not in
296 // YANG_REVISIONS but installed so likely on purpose.
297 return (true);
298 }
299 if (modrev->second != module->second) {
300 LOG_ERROR(netconf_logger, NETCONF_MODULE_REVISION_ERR)
301 .arg(module_name)
302 .arg(modrev->second)
303 .arg(module->second);
304 return (false);
305 }
306 return (true);
307}
308
309 void
310 NetconfAgent::checkModules(CfgServersMapPtr const& servers /* = {} */) const {
311 bool faulty_model(false);
312 if (servers) {
313 for (auto const& pair : *servers) {
314 if (!checkModule(pair.second->getModel())) {
315 faulty_model = true;
316 }
317 }
318 }
319
320 if (faulty_model) {
321 isc_throw(Unexpected, "YANG module is missing or its revision is not "
322 "supported. Check logs for details.");
323 }
324
325 for (auto const& modrev : YANG_REVISIONS) {
326 auto module = modules_.find(modrev.first);
327 if (module == modules_.end()) {
328 LOG_WARN(netconf_logger, NETCONF_MODULE_MISSING_WARN)
329 .arg(modrev.first);
330 continue;
331 }
332 if (modrev.second != module->second) {
333 LOG_WARN(netconf_logger, NETCONF_MODULE_REVISION_WARN)
334 .arg(modrev.first)
335 .arg(modrev.second)
336 .arg(module->second);
337 }
338 }
339}
340
341 void
342 NetconfAgent::yangConfig(const CfgServersMapPair& service_pair) {
343 string const& server(service_pair.first);
344 CfgServerPtr const& configuration(service_pair.second);
345
346 // If we're shutting down, or the boot-update flag is not set or the model
347 // associated with it is not specified.
348 if (!configuration->getBootUpdate() ||
349 configuration->getModel().empty()) {
350 return;
351 }
352
353 // First we need a way to reach the actual servers.
354 CfgControlSocketPtr ctrl_sock = configuration->getCfgControlSocket();
355 if (!ctrl_sock) {
356 return;
357 }
358
359 LOG_INFO(netconf_logger, NETCONF_SET_CONFIG_STARTED)
360 .arg(server);
361 ElementPtr config;
362 try {
363 // Retrieve configuration from Sysrepo.
364 TranslatorConfig tc(*startup_sess_, configuration->getModel());
365 config = tc.getConfig();
366 if (!config) {
367 ostringstream msg;
368 msg << "YANG configuration for "
369 << configuration->getModel()
370 << " is empty";
371 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
372 .arg(server)
373 .arg(msg.str());
374 return;
375 } else {
376 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
377 NETCONF_SET_CONFIG)
378 .arg(server)
379 .arg(prettyPrint(config));
380 }
381 } catch (exception const& ex) {
382 ostringstream msg;
383 msg << "get YANG configuration for " << server
384 << " failed with " << ex.what();
385 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
386 .arg(server)
387 .arg(msg.str());
388 return;
389 }
390 ControlSocketBasePtr comm;
391 try {
392 comm = controlSocketFactory(ctrl_sock);
393 } catch (exception const& ex) {
394 ostringstream msg;
395 msg << "control socket creation failed with " << ex.what();
396 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
397 .arg(server)
398 .arg(msg.str());
399 return;
400 }
401 ConstElementPtr answer;
402 int rcode;
403 try {
404 answer = comm->configSet(config, server);
405 parseAnswer(rcode, answer);
406 } catch (exception const& ex) {
407 ostringstream msg;
408 msg << "config-set command failed with " << ex.what();
409 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
410 .arg(server)
411 .arg(msg.str());
412 return;
413 }
414 if (rcode != CONTROL_RESULT_SUCCESS) {
415 ostringstream msg;
416 msg << "config-set command returned " << answerToText(answer);
417 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
418 .arg(server)
419 .arg(msg.str());
420 return;
421 }
422 LOG_INFO(netconf_logger, NETCONF_BOOT_UPDATE_COMPLETED)
423 .arg(server);
424}
425
426 void
427 NetconfAgent::subscribeToDataChanges(const CfgServersMapPair& service_pair) {
428 string const& server(service_pair.first);
429 CfgServerPtr const& configuration(service_pair.second);
430 string const& model(configuration->getModel());
431
432 // If we're shutting down, or the subscribe-changes flag is not set or
433 // the model is not specified, give up on subscribing.
434 if (!configuration->getSubscribeChanges() || model.empty()) {
435 return;
436 }
437 LOG_INFO(netconf_logger, NETCONF_SUBSCRIBE_CONFIG)
438 .arg(server)
439 .arg(model);
440 auto callback = [=](Session session,
441 uint32_t subscription_id,
442 string_view module_name,
443 optional<string_view> sub_xpath,
444 Event event,
445 uint32_t request_id) {
446 NetconfAgentCallback agent(service_pair);
447 return agent.moduleChange(session, subscription_id, module_name, sub_xpath, event,
448 request_id);
449 };
450 try {
451 SubscribeOptions options(SubscribeOptions::Default);
452 if (!configuration->getValidateChanges()) {
453 options = options | SubscribeOptions::DoneOnly;
454 }
455 auto exception_handler = [model](std::exception& ex) {
456 LOG_ERROR(netconf_logger, NETCONF_MODULE_CHANGE_INTERNAL_ERROR)
457 .arg(model)
458 .arg(ex.what());
459 };
460 Subscription subscription(
461 running_sess_->onModuleChange(model, callback, nullopt, 0, options, exception_handler));
462 subscriptions_.emplace(server, std::forward<Subscription>(subscription));
463 } catch (exception const& ex) {
464 ostringstream msg;
465 msg << "module change subscribe failed with " << ex.what();
466 msg << "change subscription for model " << model << " failed with: " << ex.what();
467 LOG_ERROR(netconf_logger, NETCONF_SUBSCRIBE_CONFIG_FAILED)
468 .arg(server)
469 .arg(configuration->getModel())
470 .arg(msg.str());
471 return;
472 }
473}
474
475 void
476 NetconfAgent::subscribeToNotifications(const CfgServersMapPair& service_pair) {
477 string const& server(service_pair.first);
478 CfgServerPtr const& configuration(service_pair.second);
479 string const& model(configuration->getModel());
480
481 // If we're shutting down, or the subscribe-changes flag is not set or
482 // the model is not specified, give up on subscribing.
483 if (!configuration->getSubscribeNotifications() || model.empty()) {
484 return;
485 }
486 LOG_INFO(netconf_logger, NETCONF_SUBSCRIBE_NOTIFICATIONS)
487 .arg(server)
488 .arg(model);
489
490 auto callback = [=](Session session,
491 uint32_t subscription_id,
492 NotificationType const notification_type,
493 optional<DataNode> const notification_tree,
494 NotificationTimeStamp const timestamp) {
495 NetconfAgentCallback agent(service_pair);
496 return agent.eventNotif(session, subscription_id, notification_type, notification_tree,
497 timestamp);
498 };
499 try {
500 auto exception_handler = [model](std::exception& ex) {
501 LOG_ERROR(netconf_logger, NETCONF_NOTIFICATION_INTERNAL_ERROR)
502 .arg(model)
503 .arg(ex.what());
504 };
505 Subscription subscription(running_sess_->onNotification(model, callback, nullopt, nullopt,
506 nullopt, SubscribeOptions::Default,
507 exception_handler));
508 subscriptions_.emplace(server, std::forward<Subscription>(subscription));
509 } catch (exception const& ex) {
510 ostringstream msg;
511 msg << "event notification subscription for model " << model <<
512 " failed with: " << ex.what();
513 LOG_WARN(netconf_logger, NETCONF_NOT_SUBSCRIBED_TO_NOTIFICATIONS)
514 .arg(server)
515 .arg(configuration->getModel())
516 .arg(msg.str());
517 return;
518 }
519}
520
521sysrepo::ErrorCode
522 NetconfAgent::change(Session sess, const CfgServersMapPair& service_pair) {
523 string const& server(service_pair.first);
524 CfgServerPtr const& configuration(service_pair.second);
525
526 // If we're shutting down, or the subscribe-changes or the
527 // validate-changes flag is not set or the model associated with
528 // it is not specified.
529 if (!configuration->getSubscribeChanges() ||
530 !configuration->getValidateChanges() ||
531 configuration->getModel().empty()) {
532 return (sysrepo::ErrorCode::Ok);
533 }
534 CfgControlSocketPtr ctrl_sock = configuration->getCfgControlSocket();
535 if (!ctrl_sock) {
536 return (sysrepo::ErrorCode::Ok);
537 }
538 LOG_INFO(netconf_logger, NETCONF_VALIDATE_CONFIG_STARTED)
539 .arg(server);
540 ElementPtr config;
541 try {
542 TranslatorConfig tc(sess, configuration->getModel());
543 config = tc.getConfig();
544 if (!config) {
545 ostringstream msg;
546 msg << "YANG configuration for "
547 << configuration->getModel()
548 << " is empty";
549 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_FAILED)
550 .arg(server)
551 .arg(msg.str());
552 return (sysrepo::ErrorCode::OperationFailed);
553 } else {
554 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
555 NETCONF_VALIDATE_CONFIG)
556 .arg(server)
557 .arg(prettyPrint(config));
558 }
559 } catch (exception const& ex) {
560 ostringstream msg;
561 msg << "get YANG configuration for " << server
562 << " failed with " << ex.what();
563 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_FAILED)
564 .arg(server)
565 .arg(msg.str());
566 return (sysrepo::ErrorCode::ValidationFailed);
567 }
568 ControlSocketBasePtr comm;
569 try {
570 comm = controlSocketFactory(ctrl_sock);
571 } catch (exception const& ex) {
572 ostringstream msg;
573 msg << "createControlSocket failed with " << ex.what();
574 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_FAILED)
575 .arg(server)
576 .arg(msg.str());
577 return (sysrepo::ErrorCode::Ok);
578 }
579 ConstElementPtr answer;
580 int rcode;
581 try {
582 answer = comm->configTest(config, server);
583 parseAnswer(rcode, answer);
584 } catch (exception const& ex) {
585 stringstream msg;
586 msg << "configTest failed with " << ex.what();
587 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_FAILED)
588 .arg(server)
589 .arg(msg.str());
590 return (sysrepo::ErrorCode::ValidationFailed);
591 }
592 if (rcode != CONTROL_RESULT_SUCCESS) {
593 stringstream msg;
594 msg << "configTest returned " << answerToText(answer);
595 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_REJECTED)
596 .arg(server)
597 .arg(msg.str());
598 return (sysrepo::ErrorCode::ValidationFailed);
599 }
600 LOG_INFO(netconf_logger, NETCONF_VALIDATE_CONFIG_COMPLETED)
601 .arg(server);
602 return (sysrepo::ErrorCode::Ok);
603}
604
605sysrepo::ErrorCode
606 NetconfAgent::done(Session sess, const CfgServersMapPair& service_pair) {
607 string const& server(service_pair.first);
608 CfgServerPtr const& configuration(service_pair.second);
609
610 // Check if we should and can process this update.
611 if (!configuration->getSubscribeChanges() ||
612 configuration->getModel().empty()) {
613 return (sysrepo::ErrorCode::Ok);
614 }
615 CfgControlSocketPtr ctrl_sock = configuration->getCfgControlSocket();
616 if (!ctrl_sock) {
617 return (sysrepo::ErrorCode::Ok);
618 }
619
620 // All looks good, let's get started. Print an info that we're about
621 // to update the configuration.
622 LOG_INFO(netconf_logger, NETCONF_UPDATE_CONFIG_STARTED)
623 .arg(server);
624
625 // Retrieve the configuration from SYSREPO first.
626 ElementPtr config;
627 try {
628 TranslatorConfig tc(sess, configuration->getModel());
629 config = tc.getConfig();
630 if (!config) {
631 ostringstream msg;
632 msg << "YANG configuration for "
633 << configuration->getModel()
634 << " is empty";
635 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
636 .arg(server)
637 .arg(msg.str());
638 return (sysrepo::ErrorCode::ValidationFailed);
639 } else {
640 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
641 NETCONF_UPDATE_CONFIG)
642 .arg(server)
643 .arg(prettyPrint(config));
644 }
645 } catch (exception const& ex) {
646 ostringstream msg;
647 msg << "get YANG configuration for " << server
648 << " failed with " << ex.what();
649 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
650 .arg(server)
651 .arg(msg.str());
652 return (sysrepo::ErrorCode::ValidationFailed);
653 }
654
655 // Ok, now open the control socket. We need this to send the config to
656 // the server.
657 ControlSocketBasePtr comm;
658 try {
659 comm = controlSocketFactory(ctrl_sock);
660 } catch (exception const& ex) {
661 ostringstream msg;
662 msg << "createControlSocket failed with " << ex.what();
663 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
664 .arg(server)
665 .arg(msg.str());
666 return (sysrepo::ErrorCode::Ok);
667 }
668
669 // Now apply the config using config-set command.
670 ConstElementPtr answer;
671 int rcode;
672 try {
673 answer = comm->configSet(config, server);
674 parseAnswer(rcode, answer);
675 } catch (exception const& ex) {
676 stringstream msg;
677 msg << "configSet failed with " << ex.what();
678 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
679 .arg(server)
680 .arg(msg.str());
681 return (sysrepo::ErrorCode::ValidationFailed);
682 }
683
684 // rcode == CONTROL_RESULT_SUCCESS, unless the docs say otherwise :).
685 if (rcode != CONTROL_RESULT_SUCCESS) {
686 stringstream msg;
687 msg << "configSet returned " << answerToText(answer);
688 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
689 .arg(server)
690 .arg(msg.str());
691 return (sysrepo::ErrorCode::ValidationFailed);
692 }
693 LOG_INFO(netconf_logger, NETCONF_UPDATE_CONFIG_COMPLETED)
694 .arg(server);
695 return (sysrepo::ErrorCode::Ok);
696}
697
698 void
699 NetconfAgent::logChanges(Session sess, string_view const& model) {
700 ostringstream stream;
701 stream << "/" << model << ":*//.";
702 string const xpath(stream.str());
703 ChangeCollection const changes(sess.getChanges(xpath));
704 for (Change const& change : changes) {
705 ostringstream msg;
706 switch (change.operation) {
707 case sysrepo::ChangeOperation::Created:
708 msg << "created: ";
709 break;
710 case sysrepo::ChangeOperation::Deleted:
711 msg << "deleted: ";
712 break;
713 case sysrepo::ChangeOperation::Modified:
714 msg << "modified: ";
715 break;
716 case sysrepo::ChangeOperation::Moved:
717 msg << "moved: ";
718 break;
719 default:
720 msg << "unknown operation (" << change.operation << "): ";
721 }
722 string const path(change.node.path());
723 msg << path;
724 SchemaNode const& schema(change.node.schema());
725 NodeType const node_type(schema.nodeType());
726 if (node_type == NodeType::Container) {
727 msg << " (container)";
728 } else if (node_type == NodeType::List) {
729 msg << " (list)";
730 } else {
731 optional<string> const str(
732 Translator::translateToYang(Translator::translateFromYang(change.node),
733 LeafBaseType::Unknown));
734 if (str) {
735 msg << " = " << *str;
736 }
737 }
738
739 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
740 NETCONF_CONFIG_CHANGED_DETAIL)
741 .arg(msg.str());
742 }
743}
744
745 void
746 NetconfAgent::announceShutdown() const {
747 isc::process::DControllerBasePtr& controller(NetconfController::instance());
748 if (controller) {
749 boost::dynamic_pointer_cast<NetconfController>(controller)
750 ->getNetconfProcess()
751 ->setShutdownFlag(true);
752 }
753}
754
755 bool
756 NetconfAgent::shouldShutdown() const {
757 return boost::dynamic_pointer_cast<NetconfController>(NetconfController::instance())
758 ->getNetconfProcess()
759 ->shouldShutdown();
760}
761
762} // namespace netconf
763} // namespace isc
isc::Exception::what
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Definition exceptions/exceptions.cc:32
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition exceptions/exceptions.h:153
isc::netconf::CfgServer::getValidateChanges
bool getValidateChanges() const
Getter which returns the validate-changes flag.
Definition netconf_config.h:219
isc::netconf::CfgServer::getBootUpdate
bool getBootUpdate() const
Getter which returns the boot-update flag.
Definition netconf_config.h:177
isc::netconf::CfgServer::getSubscribeNotifications
bool getSubscribeNotifications() const
Getter which returns the subscribe-changes flag.
Definition netconf_config.h:198
isc::netconf::CfgServer::getSubscribeChanges
bool getSubscribeChanges() const
Getter which returns the subscribe-changes flag.
Definition netconf_config.h:191
isc::netconf::CfgServer::getCfgControlSocket
const CfgControlSocketPtr & getCfgControlSocket() const
Getter which returns the control socket.
Definition netconf_config.h:170
isc::netconf::CfgServer::getModel
const std::string getModel() const
Getter which returns the model name.
Definition netconf_config.h:163
isc::netconf::ControlSocketBase::configTest
virtual data::ConstElementPtr configTest(data::ElementPtr config, const std::string &service)=0
Test configuration.
isc::netconf::ControlSocketBase::configSet
virtual data::ConstElementPtr configSet(data::ElementPtr config, const std::string &service)=0
Set configuration.
isc::netconf::ControlSocketBase::configGet
virtual data::ConstElementPtr configGet(const std::string &service)=0
Get configuration.
isc::netconf::NetconfAgent::subscribeToDataChanges
void subscribeToDataChanges(const CfgServersMapPair &service_pair)
Subscribe changes for a module in YANG datastore.
Definition netconf.cc:427
isc::netconf::NetconfAgent::running_sess_
std::optional< sysrepo::Session > running_sess_
Sysrepo running datastore session.
Definition netconf.h:166
isc::netconf::NetconfAgent::getModules
void getModules()
Retrieve names and revisions of installed modules through the sysrepo API.
Definition netconf.cc:265
isc::netconf::NetconfAgent::logChanges
static void logChanges(sysrepo::Session sess, std::string_view const &model)
Log changes.
Definition netconf.cc:699
isc::netconf::NetconfAgent::yangConfig
void yangConfig(const CfgServersMapPair &service_pair)
Retrieve Kea server configuration from the YANG startup datastore and applies it to servers.
Definition netconf.cc:342
isc::netconf::NetconfAgent::~NetconfAgent
virtual ~NetconfAgent()
Destructor (call clear).
Definition netconf.cc:150
isc::netconf::NetconfAgent::initSysrepo
void initSysrepo()
Initialize sysrepo sessions.
Definition netconf.cc:250
isc::netconf::NetconfAgent::keaConfig
void keaConfig(const CfgServersMapPair &service_pair)
Get and display Kea server configuration.
Definition netconf.cc:190
isc::netconf::NetconfAgent::announceShutdown
void announceShutdown() const
Set the shutdown flag of the process to true so that it can exit at the earliest convenient time.
Definition netconf.cc:746
isc::netconf::NetconfAgent::checkModules
void checkModules(CfgServersMapPtr const &servers={}) const
Check module availability.
Definition netconf.cc:310
isc::netconf::NetconfAgent::subscriptions_
std::map< const std::string, sysrepo::Subscription > subscriptions_
Subscription map.
Definition netconf.h:172
isc::netconf::NetconfAgent::shouldShutdown
bool shouldShutdown() const
Check the shutdown flag of the process.
Definition netconf.cc:756
isc::netconf::NetconfAgent::clear
void clear()
Clear.
Definition netconf.cc:183
isc::netconf::NetconfAgent::change
static sysrepo::ErrorCode change(sysrepo::Session sess, const CfgServersMapPair &service_pair)
Event::Change callback.
Definition netconf.cc:522
isc::netconf::NetconfAgent::startup_sess_
std::optional< sysrepo::Session > startup_sess_
Sysrepo startup datastore session.
Definition netconf.h:163
isc::netconf::NetconfAgent::done
static sysrepo::ErrorCode done(sysrepo::Session sess, const CfgServersMapPair &service_pair)
Event::Done callback.
Definition netconf.cc:606
isc::netconf::NetconfAgent::init
void init(NetconfCfgMgrPtr cfg_mgr)
Initialization.
Definition netconf.cc:155
isc::netconf::NetconfAgent::subscribeToNotifications
void subscribeToNotifications(const CfgServersMapPair &service_pair)
Subscribe to notifications for a given YANG module.
Definition netconf.cc:476
isc::netconf::NetconfAgent::checkModule
bool checkModule(const std::string &module_name) const
Check essential module availability.
Definition netconf.cc:285
isc::netconf::NetconfAgent::modules_
std::map< const std::string, const std::string > modules_
Available modules and revisions in Sysrepo.
Definition netconf.h:169
isc::netconf::NetconfController::instance
static process::DControllerBasePtr & instance()
Static singleton instance method.
Definition netconf_controller.cc:29
isc::yang::TranslatorConfig
DHCP configuration translation between YANG and JSON.
Definition translator_config.h:404
isc::yang::TranslatorConfig::getConfig
isc::data::ElementPtr getConfig()
Translate the whole DHCP server configuration from YANG to JSON.
Definition translator_config.cc:49
isc::yang::Translator::translateFromYang
static isc::data::ElementPtr translateFromYang(std::optional< libyang::DataNode > data_node)
Translate basic value from the given YANG data node to JSON element.
Definition translator.cc:270
isc::yang::Translator::translateToYang
static std::optional< std::string > translateToYang(isc::data::ConstElementPtr const &elem, libyang::LeafBaseType const type)
Translate basic value from JSON to YANG.
Definition translator.cc:288
command_interpreter.h
This file contains several functions and constants that are used for handling commands and responses ...
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
LOG_ERROR
#define LOG_ERROR(LOGGER, MESSAGE)
Macro to conveniently test error output and log it.
Definition macros.h:32
LOG_INFO
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
LOG_WARN
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition macros.h:14
isc::agent
Definition agent_parser.cc:148
isc::config
Definition command_interpreter.cc:23
isc::config::answerToText
std::string answerToText(const ConstElementPtr &msg)
Converts answer to printable text.
Definition command_interpreter.cc:130
isc::config::parseAnswer
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Parses a standard config/command level answer and returns arguments or text status code.
Definition command_interpreter.cc:96
isc::config::CONTROL_RESULT_SUCCESS
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
Definition command_interpreter.h:42
isc::data
Definition base_stamped_element.cc:12
isc::data::prettyPrint
void prettyPrint(ConstElementPtr element, std::ostream &out, unsigned indent, unsigned step)
Pretty prints the data into stream.
Definition data.cc:1547
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
isc::data::ElementPtr
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
isc::netconf
Definition control_socket.cc:20
isc::netconf::CfgServersMapPair
std::pair< std::string, CfgServerPtr > CfgServersMapPair
Defines a iterator pairing of name and CfgServer.
Definition netconf_config.h:278
isc::netconf::NETCONF_VALIDATE_CONFIG_FAILED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_FAILED
Definition netconf_messages.h:43
isc::netconf::NETCONF_DBG_TRACE_DETAIL_DATA
const int NETCONF_DBG_TRACE_DETAIL_DATA
Additional information.
Definition netconf_log.h:41
isc::netconf::NETCONF_GET_CONFIG_STARTED
const isc::log::MessageID NETCONF_GET_CONFIG_STARTED
Definition netconf_messages.h:20
isc::netconf::NETCONF_VALIDATE_CONFIG_REJECTED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_REJECTED
Definition netconf_messages.h:44
isc::netconf::NETCONF_VALIDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_COMPLETED
Definition netconf_messages.h:42
isc::netconf::NETCONF_CONFIG_CHANGE_EVENT
const isc::log::MessageID NETCONF_CONFIG_CHANGE_EVENT
Definition netconf_messages.h:13
isc::netconf::netconf_logger
isc::log::Logger netconf_logger(NETCONF_LOGGER_NAME)
Base logger for the netconf agent.
Definition netconf_log.h:49
isc::netconf::NETCONF_VALIDATE_CONFIG
const isc::log::MessageID NETCONF_VALIDATE_CONFIG
Definition netconf_messages.h:41
isc::netconf::NETCONF_GET_CONFIG_FAILED
const isc::log::MessageID NETCONF_GET_CONFIG_FAILED
Definition netconf_messages.h:19
isc::netconf::NETCONF_MODULE_REVISION_WARN
const isc::log::MessageID NETCONF_MODULE_REVISION_WARN
Definition netconf_messages.h:25
isc::netconf::NETCONF_GET_CONFIG
const isc::log::MessageID NETCONF_GET_CONFIG
Definition netconf_messages.h:18
isc::netconf::ControlSocketBasePtr
std::shared_ptr< ControlSocketBase > ControlSocketBasePtr
Type definition for the pointer to the ControlSocketBase.
Definition control_socket.h:106
isc::netconf::NETCONF_CONFIG_CHANGED_DETAIL
const isc::log::MessageID NETCONF_CONFIG_CHANGED_DETAIL
Definition netconf_messages.h:12
isc::netconf::NETCONF_NOTIFICATION_INTERNAL_ERROR
const isc::log::MessageID NETCONF_NOTIFICATION_INTERNAL_ERROR
Definition netconf_messages.h:26
isc::netconf::NETCONF_SET_CONFIG_FAILED
const isc::log::MessageID NETCONF_SET_CONFIG_FAILED
Definition netconf_messages.h:31
isc::netconf::NETCONF_VALIDATE_CONFIG_STARTED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_STARTED
Definition netconf_messages.h:45
isc::netconf::NETCONF_SUBSCRIBE_CONFIG
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG
Definition netconf_messages.h:34
isc::netconf::NETCONF_MODULE_MISSING_ERR
const isc::log::MessageID NETCONF_MODULE_MISSING_ERR
Definition netconf_messages.h:22
isc::netconf::CfgServerPtr
std::shared_ptr< CfgServer > CfgServerPtr
Defines a pointer for CfgServer instances.
Definition netconf_config.h:272
isc::netconf::NetconfCfgMgrPtr
boost::shared_ptr< NetconfCfgMgr > NetconfCfgMgrPtr
Defines a shared pointer to NetconfCfgMgr.
Definition netconf_cfg_mgr.h:176
isc::netconf::NETCONF_NOTIFICATION_RECEIVED
const isc::log::MessageID NETCONF_NOTIFICATION_RECEIVED
Definition netconf_messages.h:27
isc::netconf::NETCONF_MODULE_CHANGE_INTERNAL_ERROR
const isc::log::MessageID NETCONF_MODULE_CHANGE_INTERNAL_ERROR
Definition netconf_messages.h:21
isc::netconf::NETCONF_UPDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_COMPLETED
Definition netconf_messages.h:38
isc::netconf::CfgControlSocketPtr
std::shared_ptr< CfgControlSocket > CfgControlSocketPtr
Defines a pointer for CfgControlSocket instances.
Definition netconf_config.h:143
isc::netconf::NETCONF_MODULE_REVISION_ERR
const isc::log::MessageID NETCONF_MODULE_REVISION_ERR
Definition netconf_messages.h:24
isc::netconf::NETCONF_SUBSCRIBE_NOTIFICATIONS
const isc::log::MessageID NETCONF_SUBSCRIBE_NOTIFICATIONS
Definition netconf_messages.h:36
isc::netconf::NETCONF_SET_CONFIG_STARTED
const isc::log::MessageID NETCONF_SET_CONFIG_STARTED
Definition netconf_messages.h:32
isc::netconf::NETCONF_SUBSCRIBE_CONFIG_FAILED
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG_FAILED
Definition netconf_messages.h:35
isc::netconf::NETCONF_UPDATE_CONFIG_FAILED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_FAILED
Definition netconf_messages.h:39
isc::netconf::NETCONF_BOOT_UPDATE_COMPLETED
const isc::log::MessageID NETCONF_BOOT_UPDATE_COMPLETED
Definition netconf_messages.h:11
isc::netconf::NETCONF_SET_CONFIG
const isc::log::MessageID NETCONF_SET_CONFIG
Definition netconf_messages.h:30
isc::netconf::NETCONF_UPDATE_CONFIG
const isc::log::MessageID NETCONF_UPDATE_CONFIG
Definition netconf_messages.h:37
isc::netconf::NETCONF_UPDATE_CONFIG_STARTED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_STARTED
Definition netconf_messages.h:40
isc::netconf::controlSocketFactory
ControlSocketBasePtr controlSocketFactory(CfgControlSocketPtr ctrl_sock)
Factory function for control sockets.
Definition control_socket.cc:23
isc::netconf::CfgServersMapPtr
std::shared_ptr< CfgServersMap > CfgServersMapPtr
Defines a pointer to map of CfgServers.
Definition netconf_config.h:281
isc::netconf::NETCONF_MODULE_MISSING_WARN
const isc::log::MessageID NETCONF_MODULE_MISSING_WARN
Definition netconf_messages.h:23
isc::netconf::NETCONF_NOT_SUBSCRIBED_TO_NOTIFICATIONS
const isc::log::MessageID NETCONF_NOT_SUBSCRIBED_TO_NOTIFICATIONS
Definition netconf_messages.h:28
isc::process::DControllerBasePtr
boost::shared_ptr< DControllerBase > DControllerBasePtr
Definition d_controller.h:78
isc::yang
Definition adaptor.cc:17
isc
Defines the logger used by the top-level component of kea-lfc.
Definition agent_parser.cc:148
netconf.h
netconf_controller.h
netconf_log.h
Contains declarations for loggers used by the Kea netconf agent.
translator_config.h
yang_revisions.h