Kea: netconf.cc Source File

| Kea 2.2.0

netconf.cc
Go to the documentation of this file.
1// Copyright (C) 2018-2022 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 <netconf/netconf.h>
13#include <netconf/netconf_controller.h>
14#include <netconf/netconf_log.h>
15#include <cc/command_interpreter.h>
16#include <yang/translator_config.h>
17#include <yang/yang_revisions.h>
18
19#include <boost/algorithm/string.hpp>
20
21#include <sstream>
22
23using namespace std;
24using namespace isc::config;
25using namespace isc::data;
26using namespace isc::netconf;
27using namespace isc::yang;
28using namespace sysrepo;
29
30using libyang::S_Context;
31using libyang::S_Module;
32
33namespace {
34
36class NetconfAgentCallback {
37public:
41 NetconfAgentCallback(const CfgServersMapPair& service_pair)
42 : service_pair_(service_pair) {
43 }
44
46 CfgServersMapPair const service_pair_;
47
58 sr_error_t module_change(S_Session sess,
59 const char* module_name,
60 const char* /* xpath */,
61 sr_event_t event,
62 void* /* private_ctx */) {
63 ostringstream event_type;
64 switch (event) {
65 case SR_EV_UPDATE:
66 // This could potentially be a hook point for mid-flight
67 // configuration changes.
68 event_type << "SR_EV_UPDATE";
69 break;
70 case SR_EV_CHANGE:
71 event_type << "SR_EV_CHANGE";
72 break;
73 case SR_EV_DONE:
74 event_type << "SR_EV_DONE";
75 break;
76 case SR_EV_ABORT:
77 event_type << "SR_EV_ABORT";
78 break;
79 case SR_EV_ENABLED:
80 event_type << "SR_EV_ENABLED";
81 break;
82 case SR_EV_RPC:
83 event_type << "SR_EV_RPC";
84 break;
85 default:
86 event_type << "UNKNOWN (" << event << ")";
87 break;
88 }
89 LOG_INFO(netconf_logger, NETCONF_CONFIG_CHANGE_EVENT)
90 .arg(event_type.str());
91 NetconfAgent::logChanges(sess, module_name);
92 switch (event) {
93 case SR_EV_CHANGE:
94 return (NetconfAgent::change(sess, service_pair_));
95 case SR_EV_DONE:
96 return (NetconfAgent::done(sess, service_pair_));
97 default:
98 return (SR_ERR_OK);
99 }
100 }
101
102 void event_notif(sysrepo::S_Session /* session */,
103 sr_ev_notif_type_t const notification_type,
104 char const* /* path */,
105 sysrepo::S_Vals const vals,
106 time_t /* timestamp */,
107 void* /* private_data */) {
108 string n;
109 switch (notification_type) {
110 case SR_EV_NOTIF_REALTIME:
111 n = "SR_EV_NOTIF_REALTIME";
112 break;
113 case SR_EV_NOTIF_REPLAY:
114 n = "SR_EV_NOTIF_REPLAY";
115 break;
116 case SR_EV_NOTIF_REPLAY_COMPLETE:
117 n = "SR_EV_NOTIF_REPLAY_COMPLETE";
118 break;
119 case SR_EV_NOTIF_STOP:
120 n = "SR_EV_NOTIF_STOP";
121 break;
122 case SR_EV_NOTIF_SUSPENDED:
123 n = "SR_EV_NOTIF_SUSPENDED";
124 break;
125 case SR_EV_NOTIF_RESUMED:
126 n = "SR_EV_NOTIF_RESUMED";
127 break;
128 }
129
130 stringstream s;
131 for (size_t i(0); i < vals->val_cnt(); ++i) {
132 if (i != 0) {
133 s << ", ";
134 }
135 s << vals->val(i)->to_string();
136 }
137
138 LOG_INFO(netconf_logger, NETCONF_NOTIFICATION_RECEIVED)
139 .arg(n)
140 .arg(service_pair_.first)
141 .arg(s.str());
142 }
143};
144
145} // end of anonymous namespace
146
147namespace isc {
148namespace netconf {
149
150NetconfAgent::~NetconfAgent() {
151 clear();
152}
153
154void
155NetconfAgent::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 subscribeConfig(pair);
178 subscribeToNotifications(pair);
179 }
180}
181
182void
183NetconfAgent::clear() {
184 for (auto subs : subscriptions_) {
185 subs.second.reset();
186 }
187 subscriptions_.clear();
188 running_sess_.reset();
189 startup_sess_.reset();
190 conn_.reset();
191}
192
193void
194NetconfAgent::keaConfig(const CfgServersMapPair& service_pair) {
195 // If the boot-update flag is not set.
196 if (!service_pair.second->getBootUpdate()) {
197 return;
198 }
199 CfgControlSocketPtr ctrl_sock = service_pair.second->getCfgControlSocket();
200 if (!ctrl_sock) {
201 return;
202 }
203 ControlSocketBasePtr comm;
204 try {
205 comm = controlSocketFactory(ctrl_sock);
206 } catch (const std::exception& ex) {
207 ostringstream msg;
208 msg << "createControlSocket failed with " << ex.what();
209 LOG_ERROR(netconf_logger, NETCONF_GET_CONFIG_FAILED)
210 .arg(service_pair.first)
211 .arg(msg.str());
212 return;
213 }
214 ConstElementPtr answer;
215 int rcode;
216 ConstElementPtr config;
217 LOG_INFO(netconf_logger, NETCONF_GET_CONFIG_STARTED)
218 .arg(service_pair.first);
219 try {
220 answer = comm->configGet(service_pair.first);
221 config = parseAnswer(rcode, answer);
222 } catch (const std::exception& ex) {
223 ostringstream msg;
224 msg << "config-get command failed with " << ex.what();
225 LOG_ERROR(netconf_logger, NETCONF_GET_CONFIG_FAILED)
226 .arg(service_pair.first)
227 .arg(msg.str());
228 return;
229 }
230 if (rcode != CONTROL_RESULT_SUCCESS) {
231 ostringstream msg;
232 msg << "config-get command returned " << answerToText(answer);
233 LOG_ERROR(netconf_logger, NETCONF_GET_CONFIG_FAILED)
234 .arg(service_pair.first)
235 .arg(msg.str());
236 return;
237 }
238 if (!config) {
239 LOG_ERROR(netconf_logger, NETCONF_GET_CONFIG_FAILED)
240 .arg(service_pair.first)
241 .arg("config-get command returned an empty configuration");
242 return;
243 }
244 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
245 NETCONF_GET_CONFIG)
246 .arg(service_pair.first)
247 .arg(prettyPrint(config));
248}
249
250void
251NetconfAgent::initSysrepo() {
252 try {
253 conn_ = make_shared<Connection>();
254 } catch (const std::exception& ex) {
255 isc_throw(Unexpected, "Can't connect to sysrepo: " << ex.what());
256 }
257
258 try {
259 startup_sess_.reset(new Session(conn_, SR_DS_STARTUP));
260 running_sess_.reset(new Session(conn_, SR_DS_RUNNING));
261 } catch (const std::exception& ex) {
262 isc_throw(Unexpected, "Can't establish a sysrepo session: "
263 << ex.what());
264 }
265
266 // Retrieve names and revisions of installed modules from sysrepo.
267 getModules();
268}
269
270 void NetconfAgent::getModules() {
271 vector<S_Module> modules;
272 try {
273 S_Context context(running_sess_->get_context());
274 modules = context->get_module_iter();
275 } catch (const sysrepo_exception& ex) {
276 isc_throw(Unexpected, "can't retrieve available modules: " << ex.what());
277 }
278
279 for (S_Module const& module : modules) {
280 if (!module->name()) {
281 isc_throw(Unexpected, "could not retrieve module name");
282 }
283 string const name(module->name());
284 if (!module->rev() || !module->rev()->date()) {
285 isc_throw(Unexpected,
286 "could not retrieve module revision for module " << name);
287 }
288 string const revision(module->rev()->date());
289 modules_.emplace(name, revision);
290 }
291}
292
293bool
294NetconfAgent::checkModule(const string& module_name) const {
295 auto module = modules_.find(module_name);
296 if (module == modules_.end()) {
297 LOG_ERROR(netconf_logger, NETCONF_MODULE_MISSING_ERR)
298 .arg(module_name);
299 return (false);
300 }
301 auto modrev = YANG_REVISIONS.find(module_name);
302 if (modrev == YANG_REVISIONS.end()) {
303 // Can't check revision?!
304 // It can happen only with a module which is not in
305 // YANG_REVISIONS but installed so likely on purpose.
306 return (true);
307 }
308 if (modrev->second != module->second) {
309 LOG_ERROR(netconf_logger, NETCONF_MODULE_REVISION_ERR)
310 .arg(module_name)
311 .arg(modrev->second)
312 .arg(module->second);
313 return (false);
314 }
315 return (true);
316}
317
318void
319NetconfAgent::checkModules(CfgServersMapPtr const& servers /* = {} */) const {
320 bool faulty_model(false);
321 if (servers) {
322 for (auto pair : *servers) {
323 if (!checkModule(pair.second->getModel())) {
324 faulty_model = true;
325 }
326 }
327 }
328
329 if (faulty_model) {
330 isc_throw(Unexpected, "YANG module is missing or its revision is not "
331 "supported. Check logs for details.");
332 }
333
334 for (auto modrev : YANG_REVISIONS) {
335 auto module = modules_.find(modrev.first);
336 if (module == modules_.end()) {
337 LOG_WARN(netconf_logger, NETCONF_MODULE_MISSING_WARN)
338 .arg(modrev.first);
339 continue;
340 }
341 if (modrev.second != module->second) {
342 LOG_WARN(netconf_logger, NETCONF_MODULE_REVISION_WARN)
343 .arg(modrev.first)
344 .arg(modrev.second)
345 .arg(module->second);
346 }
347 }
348}
349
350void
351NetconfAgent::yangConfig(const CfgServersMapPair& service_pair) {
352 // If we're shutting down, or the boot-update flag is not set or the model
353 // associated with it is not specified.
354 if (!service_pair.second->getBootUpdate() ||
355 service_pair.second->getModel().empty()) {
356 return;
357 }
358
359 // First we need a way to reach the actual servers.
360 CfgControlSocketPtr ctrl_sock = service_pair.second->getCfgControlSocket();
361 if (!ctrl_sock) {
362 return;
363 }
364
365 LOG_INFO(netconf_logger, NETCONF_SET_CONFIG_STARTED)
366 .arg(service_pair.first);
367 ConstElementPtr config;
368 try {
369 // Retrieve configuration from Sysrepo.
370 TranslatorConfig tc(startup_sess_, service_pair.second->getModel());
371 config = tc.getConfig();
372 if (!config) {
373 ostringstream msg;
374 msg << "YANG configuration for "
375 << service_pair.second->getModel()
376 << " is empty";
377 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
378 .arg(service_pair.first)
379 .arg(msg.str());
380 return;
381 } else {
382 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
383 NETCONF_SET_CONFIG)
384 .arg(service_pair.first)
385 .arg(prettyPrint(config));
386 }
387 } catch (const std::exception& ex) {
388 ostringstream msg;
389 msg << "get YANG configuration for " << service_pair.first
390 << " failed with " << ex.what();
391 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
392 .arg(service_pair.first)
393 .arg(msg.str());
394 return;
395 }
396 ControlSocketBasePtr comm;
397 try {
398 comm = controlSocketFactory(ctrl_sock);
399 } catch (const std::exception& ex) {
400 ostringstream msg;
401 msg << "control socket creation failed with " << ex.what();
402 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
403 .arg(service_pair.first)
404 .arg(msg.str());
405 return;
406 }
407 ConstElementPtr answer;
408 int rcode;
409 try {
410 answer = comm->configSet(config, service_pair.first);
411 parseAnswer(rcode, answer);
412 } catch (const std::exception& ex) {
413 ostringstream msg;
414 msg << "config-set command failed with " << ex.what();
415 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
416 .arg(service_pair.first)
417 .arg(msg.str());
418 return;
419 }
420 if (rcode != CONTROL_RESULT_SUCCESS) {
421 ostringstream msg;
422 msg << "config-set command returned " << answerToText(answer);
423 LOG_ERROR(netconf_logger, NETCONF_SET_CONFIG_FAILED)
424 .arg(service_pair.first)
425 .arg(msg.str());
426 return;
427 }
428 LOG_INFO(netconf_logger, NETCONF_BOOT_UPDATE_COMPLETED)
429 .arg(service_pair.first);
430}
431
432void
433NetconfAgent::subscribeConfig(const CfgServersMapPair& service_pair) {
434 std::string const& model(service_pair.second->getModel());
435
436 // If we're shutting down, or the subscribe-changes flag is not set or
437 // the model associated with it is not specified.
438 if (!service_pair.second->getSubscribeChanges() ||
439 model.empty()) {
440 return;
441 }
442 LOG_INFO(netconf_logger, NETCONF_SUBSCRIBE_CONFIG)
443 .arg(service_pair.first)
444 .arg(model);
445 S_Subscribe subs(new Subscribe(running_sess_));
446 auto callback = [=](sysrepo::S_Session sess, const char* module_name,
447 const char* xpath, sr_event_t event,
448 uint32_t /* request_id */) {
449 NetconfAgentCallback agent(service_pair);
450 return agent.module_change(sess, module_name, xpath, event, nullptr);
451 };
452 try {
453 sr_subscr_options_t options = SR_SUBSCR_DEFAULT;
454 if (!service_pair.second->getValidateChanges()) {
455 options |= SR_SUBSCR_DONE_ONLY;
456 }
457 // Note the API stores the module name so do not put it
458 // in a short lifetime variable!
459 subs->module_change_subscribe(model.c_str(), callback, nullptr, 0,
460 options);
461 } catch (const std::exception& ex) {
462 ostringstream msg;
463 msg << "module change subscribe failed with " << ex.what();
464 msg << "change subscription for model " << model <<
465 " failed with: " << ex.what();
466 LOG_ERROR(netconf_logger, NETCONF_SUBSCRIBE_CONFIG_FAILED)
467 .arg(service_pair.first)
468 .arg(service_pair.second->getModel())
469 .arg(msg.str());
470 return;
471 }
472 subscriptions_.insert(make_pair(service_pair.first, subs));
473}
474
475
476void
477NetconfAgent::subscribeToNotifications(const CfgServersMapPair& service_pair) {
478 std::string const& model(service_pair.second->getModel());
479 // If we're shutting down, or the subscribe-changes flag is not set or
480 // the model associated with it is not specified.
481 if (!service_pair.second->getSubscribeNotifications() ||
482 model.empty()) {
483 return;
484 }
485 LOG_INFO(netconf_logger, NETCONF_SUBSCRIBE_NOTIFICATIONS)
486 .arg(service_pair.first)
487 .arg(model);
488
489 S_Subscribe subscription(std::make_shared<Subscribe>(running_sess_));
490 auto callback = [=](sysrepo::S_Session session,
491 sr_ev_notif_type_t const notification_type,
492 char const* path,
493 sysrepo::S_Vals const vals,
494 time_t timestamp) {
495 NetconfAgentCallback agent(service_pair);
496 return agent.event_notif(session, notification_type, path, vals, timestamp, nullptr);
497 };
498 try {
499 subscription->event_notif_subscribe(model.c_str(), callback);
500 } catch (const std::exception& ex) {
501 ostringstream msg;
502 msg << "event notification subscription for model " << model <<
503 " failed with: " << ex.what();
504 LOG_ERROR(netconf_logger, NETCONF_SUBSCRIBE_NOTIFICATIONS_FAILED)
505 .arg(service_pair.first)
506 .arg(service_pair.second->getModel())
507 .arg(msg.str());
508 return;
509 }
510 subscriptions_.emplace(service_pair.first, subscription);
511}
512
513sr_error_t
514NetconfAgent::change(S_Session sess, const CfgServersMapPair& service_pair) {
515 // If we're shutting down, or the subscribe-changes or the
516 // validate-changes flag is not set or the model associated with
517 // it is not specified.
518 if (!service_pair.second->getSubscribeChanges() ||
519 !service_pair.second->getValidateChanges() ||
520 service_pair.second->getModel().empty()) {
521 return (SR_ERR_OK);
522 }
523 CfgControlSocketPtr ctrl_sock = service_pair.second->getCfgControlSocket();
524 if (!ctrl_sock) {
525 return (SR_ERR_OK);
526 }
527 LOG_INFO(netconf_logger, NETCONF_VALIDATE_CONFIG_STARTED)
528 .arg(service_pair.first);
529 ConstElementPtr config;
530 try {
531 TranslatorConfig tc(sess, service_pair.second->getModel());
532 config = tc.getConfig();
533 if (!config) {
534 ostringstream msg;
535 msg << "YANG configuration for "
536 << service_pair.second->getModel()
537 << " is empty";
538 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_FAILED)
539 .arg(service_pair.first)
540 .arg(msg.str());
541 return (SR_ERR_OPERATION_FAILED);
542 } else {
543 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
544 NETCONF_VALIDATE_CONFIG)
545 .arg(service_pair.first)
546 .arg(prettyPrint(config));
547 }
548 } catch (const std::exception& ex) {
549 ostringstream msg;
550 msg << "get YANG configuration for " << service_pair.first
551 << " failed with " << ex.what();
552 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_FAILED)
553 .arg(service_pair.first)
554 .arg(msg.str());
555 return (SR_ERR_VALIDATION_FAILED);;
556 }
557 ControlSocketBasePtr comm;
558 try {
559 comm = controlSocketFactory(ctrl_sock);
560 } catch (const std::exception& ex) {
561 ostringstream msg;
562 msg << "createControlSocket failed with " << ex.what();
563 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_FAILED)
564 .arg(service_pair.first)
565 .arg(msg.str());
566 return (SR_ERR_OK);
567 }
568 ConstElementPtr answer;
569 int rcode;
570 try {
571 answer = comm->configTest(config, service_pair.first);
572 parseAnswer(rcode, answer);
573 } catch (const std::exception& ex) {
574 stringstream msg;
575 msg << "configTest failed with " << ex.what();
576 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_FAILED)
577 .arg(service_pair.first)
578 .arg(msg.str());
579 return (SR_ERR_VALIDATION_FAILED);
580 }
581 if (rcode != CONTROL_RESULT_SUCCESS) {
582 stringstream msg;
583 msg << "configTest returned " << answerToText(answer);
584 LOG_ERROR(netconf_logger, NETCONF_VALIDATE_CONFIG_REJECTED)
585 .arg(service_pair.first)
586 .arg(msg.str());
587 return (SR_ERR_VALIDATION_FAILED);
588 }
589 LOG_INFO(netconf_logger, NETCONF_VALIDATE_CONFIG_COMPLETED)
590 .arg(service_pair.first);
591 return (SR_ERR_OK);
592}
593
594sr_error_t
595NetconfAgent::done(S_Session sess, const CfgServersMapPair& service_pair) {
596 // Check if we should and can process this update.
597 if (!service_pair.second->getSubscribeChanges() ||
598 service_pair.second->getModel().empty()) {
599 return (SR_ERR_OK);
600 }
601 CfgControlSocketPtr ctrl_sock = service_pair.second->getCfgControlSocket();
602 if (!ctrl_sock) {
603 return (SR_ERR_OK);
604 }
605
606 // All looks good, let's get started. Print an info that we're about
607 // to update the configuration.
608 LOG_INFO(netconf_logger, NETCONF_UPDATE_CONFIG_STARTED)
609 .arg(service_pair.first);
610
611 // Retrieve the configuration from SYSREPO first.
612 ConstElementPtr config;
613 try {
614 TranslatorConfig tc(sess, service_pair.second->getModel());
615 config = tc.getConfig();
616 if (!config) {
617 ostringstream msg;
618 msg << "YANG configuration for "
619 << service_pair.second->getModel()
620 << " is empty";
621 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
622 .arg(service_pair.first)
623 .arg(msg.str());
624 return (SR_ERR_VALIDATION_FAILED);
625 } else {
626 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
627 NETCONF_UPDATE_CONFIG)
628 .arg(service_pair.first)
629 .arg(prettyPrint(config));
630 }
631 } catch (const std::exception& ex) {
632 ostringstream msg;
633 msg << "get YANG configuration for " << service_pair.first
634 << " failed with " << ex.what();
635 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
636 .arg(service_pair.first)
637 .arg(msg.str());
638 return (SR_ERR_VALIDATION_FAILED);
639 }
640
641 // Ok, now open the control socket. We need this to send the config to
642 // the server.
643 ControlSocketBasePtr comm;
644 try {
645 comm = controlSocketFactory(ctrl_sock);
646 } catch (const std::exception& ex) {
647 ostringstream msg;
648 msg << "createControlSocket failed with " << ex.what();
649 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
650 .arg(service_pair.first)
651 .arg(msg.str());
652 return (SR_ERR_OK);
653 }
654
655 // Now apply the config using config-set command.
656 ConstElementPtr answer;
657 int rcode;
658 try {
659 answer = comm->configSet(config, service_pair.first);
660 parseAnswer(rcode, answer);
661 } catch (const std::exception& ex) {
662 stringstream msg;
663 msg << "configSet failed with " << ex.what();
664 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
665 .arg(service_pair.first)
666 .arg(msg.str());
667 return (SR_ERR_VALIDATION_FAILED);
668 }
669
670 // rcode == CONTROL_RESULT_SUCCESS, unless the docs say otherwise :).
671 if (rcode != CONTROL_RESULT_SUCCESS) {
672 stringstream msg;
673 msg << "configSet returned " << answerToText(answer);
674 LOG_ERROR(netconf_logger, NETCONF_UPDATE_CONFIG_FAILED)
675 .arg(service_pair.first)
676 .arg(msg.str());
677 return (SR_ERR_VALIDATION_FAILED);
678 }
679 LOG_INFO(netconf_logger, NETCONF_UPDATE_CONFIG_COMPLETED)
680 .arg(service_pair.first);
681 return (SR_ERR_OK);
682}
683
684void
685NetconfAgent::logChanges(S_Session sess, const string& model) {
686 ostringstream stream;
687 stream << "/" << model << ":*//.";
688 std::string const xpath(stream.str());
689 S_Iter_Change iter = sess->get_changes_iter(xpath.c_str());
690 if (!iter) {
691 LOG_WARN(netconf_logger, NETCONF_LOG_CHANGE_FAIL)
692 .arg("no iterator");
693 return;
694 }
695 for (;;) {
696 S_Change change;
697 ostringstream msg;
698 try {
699 change = sess->get_change_next(iter);
700 } catch (const sysrepo_exception& ex) {
701 msg << "get change iterator next failed: " << ex.what();
702 LOG_WARN(netconf_logger, NETCONF_LOG_CHANGE_FAIL)
703 .arg(msg.str());
704 return;
705 }
706 if (!change) {
707 // End of changes, not an error.
708 return;
709 }
710 S_Val new_val = change->new_val();
711 S_Val old_val = change->old_val();
712 string report;
713 switch (change->oper()) {
714 case SR_OP_CREATED:
715 if (!new_val) {
716 LOG_WARN(netconf_logger, NETCONF_LOG_CHANGE_FAIL)
717 .arg("created but without a new value");
718 break;
719 }
720 msg << "created: " << new_val->to_string();
721 report = msg.str();
722 boost::erase_all(report, "\n");
723 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
724 NETCONF_CONFIG_CHANGED_DETAIL)
725 .arg(report);
726 break;
727 case SR_OP_MODIFIED:
728 if (!old_val || !new_val) {
729 LOG_WARN(netconf_logger, NETCONF_LOG_CHANGE_FAIL)
730 .arg("modified but without an old or new value");
731 break;
732 }
733 msg << "modified: " << old_val->to_string()
734 << " => " << new_val->to_string();
735 report = msg.str();
736 boost::erase_all(report, "\n");
737 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
738 NETCONF_CONFIG_CHANGED_DETAIL)
739 .arg(report);
740 break;
741 case SR_OP_DELETED:
742 if (!old_val) {
743 LOG_WARN(netconf_logger, NETCONF_LOG_CHANGE_FAIL)
744 .arg("deleted but without an old value");
745 break;
746 }
747 msg << "deleted: " << old_val->to_string();
748 report = msg.str();
749 boost::erase_all(report, "\n");
750 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
751 NETCONF_CONFIG_CHANGED_DETAIL)
752 .arg(report);
753 break;
754 case SR_OP_MOVED:
755 if (!new_val) {
756 LOG_WARN(netconf_logger, NETCONF_LOG_CHANGE_FAIL)
757 .arg("moved but without a new value");
758 break;
759 }
760 msg << "moved: " << new_val->xpath();
761 if (!old_val) {
762 msg << " first";
763 } else {
764 msg << " after " << old_val->xpath();
765 }
766 report = msg.str();
767 boost::erase_all(report, "\n");
768 LOG_DEBUG(netconf_logger, NETCONF_DBG_TRACE_DETAIL_DATA,
769 NETCONF_CONFIG_CHANGED_DETAIL)
770 .arg(report);
771 break;
772 default:
773 msg << "unknown operation (" << change->oper() << ")";
774 LOG_WARN(netconf_logger, NETCONF_LOG_CHANGE_FAIL)
775 .arg(msg.str());
776 }
777 }
778}
779
780void
781NetconfAgent::announceShutdown() const {
782 isc::process::DControllerBasePtr& controller(NetconfController::instance());
783 if (controller) {
784 boost::dynamic_pointer_cast<NetconfController>(controller)
785 ->getNetconfProcess()
786 ->setShutdownFlag(true);
787 }
788}
789
790 bool NetconfAgent::shouldShutdown() const {
791 return boost::dynamic_pointer_cast<NetconfController>(NetconfController::instance())
792 ->getNetconfProcess()
793 ->shouldShutdown();
794}
795
796} // namespace netconf
797} // 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::NetconfAgent::getModules
void getModules()
Retrieve names and revisions of installed modules through the sysrepo API.
Definition: netconf.cc:270
isc::netconf::NetconfAgent::running_sess_
sysrepo::S_Session running_sess_
Sysrepo running datastore session.
Definition: netconf.h:171
isc::netconf::NetconfAgent::startup_sess_
sysrepo::S_Session startup_sess_
Sysrepo startup datastore session.
Definition: netconf.h:168
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:351
isc::netconf::NetconfAgent::~NetconfAgent
virtual ~NetconfAgent()
Destructor (call clear).
Definition: netconf.cc:150
isc::netconf::NetconfAgent::done
static sr_error_t done(sysrepo::S_Session sess, const CfgServersMapPair &service_pair)
SR_EV_DONE callback.
Definition: netconf.cc:595
isc::netconf::NetconfAgent::subscribeConfig
void subscribeConfig(const CfgServersMapPair &service_pair)
Subscribe changes for a module in YANG datastore.
Definition: netconf.cc:433
isc::netconf::NetconfAgent::initSysrepo
void initSysrepo()
Initialize sysrepo sessions.
Definition: netconf.cc:251
isc::netconf::NetconfAgent::subscriptions_
std::map< const std::string, sysrepo::S_Subscribe > subscriptions_
Subscription map.
Definition: netconf.h:177
isc::netconf::NetconfAgent::keaConfig
void keaConfig(const CfgServersMapPair &service_pair)
Get and display Kea server configuration.
Definition: netconf.cc:194
isc::netconf::NetconfAgent::change
static sr_error_t change(sysrepo::S_Session sess, const CfgServersMapPair &service_pair)
SR_EV_CHANGE callback.
Definition: netconf.cc:514
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:781
isc::netconf::NetconfAgent::conn_
sysrepo::S_Connection conn_
Sysrepo connection.
Definition: netconf.h:165
isc::netconf::NetconfAgent::logChanges
static void logChanges(sysrepo::S_Session sess, const std::string &model)
Log changes.
Definition: netconf.cc:685
isc::netconf::NetconfAgent::checkModules
void checkModules(CfgServersMapPtr const &servers={}) const
Check module availability.
Definition: netconf.cc:319
isc::netconf::NetconfAgent::shouldShutdown
bool shouldShutdown() const
Check the shutdown flag of the process.
Definition: netconf.cc:790
isc::netconf::NetconfAgent::clear
void clear()
Clear.
Definition: netconf.cc:183
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:477
isc::netconf::NetconfAgent::checkModule
bool checkModule(const std::string &module_name) const
Check essential module availability.
Definition: netconf.cc:294
isc::netconf::NetconfAgent::modules_
std::map< const std::string, const std::string > modules_
Available modules and revisions in Sysrepo.
Definition: netconf.h:174
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:409
isc::yang::TranslatorConfig::getConfig
isc::data::ElementPtr getConfig()
Get and translate the whole DHCP server configuration from YANG to JSON.
Definition: translator_config.cc:50
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::config
Definition: command_interpreter.cc:23
isc::config::parseAnswer
ConstElementPtr parseAnswer(int &rcode, const ConstElementPtr &msg)
Definition: command_interpreter.cc:69
isc::config::CONTROL_RESULT_SUCCESS
const int CONTROL_RESULT_SUCCESS
Status code indicating a successful operation.
Definition: command_interpreter.h:42
isc::config::answerToText
std::string answerToText(const ConstElementPtr &msg)
Definition: command_interpreter.cc:101
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:1487
isc::data::ConstElementPtr
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
isc::netconf
Definition: control_socket.cc:20
isc::netconf::NETCONF_VALIDATE_CONFIG_FAILED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_FAILED
Definition: netconf_messages.h:42
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:43
isc::netconf::NETCONF_VALIDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_COMPLETED
Definition: netconf_messages.h:41
isc::netconf::NETCONF_CONFIG_CHANGE_EVENT
const isc::log::MessageID NETCONF_CONFIG_CHANGE_EVENT
Definition: netconf_messages.h:13
isc::netconf::NETCONF_SUBSCRIBE_NOTIFICATIONS_FAILED
const isc::log::MessageID NETCONF_SUBSCRIBE_NOTIFICATIONS_FAILED
Definition: netconf_messages.h:35
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::ControlSocketBasePtr
boost::shared_ptr< ControlSocketBase > ControlSocketBasePtr
Type definition for the pointer to the ControlSocketBase.
Definition: control_socket.h:107
isc::netconf::NETCONF_VALIDATE_CONFIG
const isc::log::MessageID NETCONF_VALIDATE_CONFIG
Definition: netconf_messages.h:40
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::NETCONF_LOG_CHANGE_FAIL
const isc::log::MessageID NETCONF_LOG_CHANGE_FAIL
Definition: netconf_messages.h:21
isc::netconf::CfgControlSocketPtr
boost::shared_ptr< CfgControlSocket > CfgControlSocketPtr
Defines a pointer for CfgControlSocket instances.
Definition: netconf_config.h:144
isc::netconf::NETCONF_CONFIG_CHANGED_DETAIL
const isc::log::MessageID NETCONF_CONFIG_CHANGED_DETAIL
Definition: netconf_messages.h:12
isc::netconf::NETCONF_SET_CONFIG_FAILED
const isc::log::MessageID NETCONF_SET_CONFIG_FAILED
Definition: netconf_messages.h:29
isc::netconf::NETCONF_VALIDATE_CONFIG_STARTED
const isc::log::MessageID NETCONF_VALIDATE_CONFIG_STARTED
Definition: netconf_messages.h:44
isc::netconf::NetconfCfgMgrPtr
boost::shared_ptr< NetconfCfgMgr > NetconfCfgMgrPtr
Defines a shared pointer to NetconfCfgMgr.
Definition: netconf_cfg_mgr.h:181
isc::netconf::NETCONF_SUBSCRIBE_CONFIG
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG
Definition: netconf_messages.h:32
isc::netconf::CfgServersMapPtr
boost::shared_ptr< CfgServersMap > CfgServersMapPtr
Defines a pointer to map of CfgServers.
Definition: netconf_config.h:282
isc::netconf::NETCONF_MODULE_MISSING_ERR
const isc::log::MessageID NETCONF_MODULE_MISSING_ERR
Definition: netconf_messages.h:22
isc::netconf::NETCONF_NOTIFICATION_RECEIVED
const isc::log::MessageID NETCONF_NOTIFICATION_RECEIVED
Definition: netconf_messages.h:26
isc::netconf::NETCONF_UPDATE_CONFIG_COMPLETED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_COMPLETED
Definition: netconf_messages.h:37
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:34
isc::netconf::NETCONF_SET_CONFIG_STARTED
const isc::log::MessageID NETCONF_SET_CONFIG_STARTED
Definition: netconf_messages.h:30
isc::netconf::NETCONF_SUBSCRIBE_CONFIG_FAILED
const isc::log::MessageID NETCONF_SUBSCRIBE_CONFIG_FAILED
Definition: netconf_messages.h:33
isc::netconf::NETCONF_UPDATE_CONFIG_FAILED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_FAILED
Definition: netconf_messages.h:38
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:28
isc::netconf::NETCONF_UPDATE_CONFIG
const isc::log::MessageID NETCONF_UPDATE_CONFIG
Definition: netconf_messages.h:36
isc::netconf::NETCONF_UPDATE_CONFIG_STARTED
const isc::log::MessageID NETCONF_UPDATE_CONFIG_STARTED
Definition: netconf_messages.h:39
isc::netconf::controlSocketFactory
ControlSocketBasePtr controlSocketFactory(CfgControlSocketPtr ctrl_sock)
Factory function for control sockets.
Definition: control_socket.cc:23
isc::netconf::CfgServersMapPair
std::pair< std::string, CfgServerPtr > CfgServersMapPair
Defines a iterator pairing of name and CfgServer.
Definition: netconf_config.h:279
isc::netconf::NETCONF_MODULE_MISSING_WARN
const isc::log::MessageID NETCONF_MODULE_MISSING_WARN
Definition: netconf_messages.h:23
isc::process::DControllerBasePtr
boost::shared_ptr< DControllerBase > DControllerBasePtr
Definition: d_controller.h:78
isc::yang
Definition: adaptor.cc:18
isc
Defines the logger used by the top-level component of kea-lfc.
Definition: agent_parser.cc:143
netconf.h
netconf_controller.h
netconf_log.h
Contains declarations for loggers used by the Kea netconf agent.
translator_config.h
yang_revisions.h