summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--bfdd/bfd.c47
-rw-r--r--bfdd/bfd.h35
-rw-r--r--bfdd/bfd_packet.c3
-rw-r--r--bfdd/bfdd.c1
-rw-r--r--bfdd/bfdd_cli.c1
-rw-r--r--bfdd/bfdd_nb.c388
-rw-r--r--bfdd/bfdd_nb.h217
-rw-r--r--bfdd/bfdd_nb_config.c520
-rw-r--r--bfdd/bfdd_nb_state.c383
-rw-r--r--bfdd/bfdd_northbound.c1236
-rw-r--r--bfdd/control.c4
-rw-r--r--bfdd/ptm_adapter.c13
-rw-r--r--bfdd/subdir.am5
-rw-r--r--bgpd/bgp_bfd.c3
-rw-r--r--bgpd/bgp_mpath.c2
-rw-r--r--bgpd/bgp_route.c30
-rw-r--r--bgpd/bgpd.c4
-rw-r--r--bgpd/rfapi/rfapi.c8
-rw-r--r--bgpd/rfapi/rfapi_vty.c2
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c2
-rw-r--r--isisd/isis_adjacency.c15
-rw-r--r--isisd/isis_adjacency.h1
-rw-r--r--isisd/isis_bfd.c3
-rw-r--r--isisd/isis_circuit.c1
-rw-r--r--isisd/isis_cli.c2
-rw-r--r--isisd/isis_cli.h127
-rw-r--r--isisd/isis_lsp.c1
-rw-r--r--isisd/isis_main.c1
-rw-r--r--isisd/isis_nb.c815
-rw-r--r--isisd/isis_nb.h548
-rw-r--r--isisd/isis_nb_config.c2236
-rw-r--r--isisd/isis_nb_notifications.c491
-rw-r--r--isisd/isis_nb_state.c386
-rw-r--r--isisd/isis_northbound.c3932
-rw-r--r--isisd/isis_pdu.c1
-rw-r--r--isisd/isisd.c1
-rw-r--r--isisd/isisd.h46
-rw-r--r--isisd/subdir.am7
-rw-r--r--lib/bfd.c2
-rw-r--r--lib/bfd.h14
-rw-r--r--lib/if.c14
-rw-r--r--lib/if.h1
-rw-r--r--ospf6d/ospf6_bfd.c2
-rw-r--r--ospfd/ospf_bfd.c2
-rw-r--r--pimd/pim_bfd.c2
-rw-r--r--pimd/pim_cmd.c4
-rw-r--r--ripd/rip_cli.c2
-rw-r--r--ripd/rip_cli.h86
-rw-r--r--ripd/rip_main.c1
-rw-r--r--ripd/rip_nb.c369
-rw-r--r--ripd/rip_nb.h265
-rw-r--r--ripd/rip_nb_config.c1099
-rw-r--r--ripd/rip_nb_notifications.c73
-rw-r--r--ripd/rip_nb_rpcs.c105
-rw-r--r--ripd/rip_nb_state.c284
-rw-r--r--ripd/rip_northbound.c1823
-rw-r--r--ripd/ripd.c1
-rw-r--r--ripd/ripd.h9
-rw-r--r--ripd/subdir.am8
-rw-r--r--ripngd/ripng_cli.c2
-rw-r--r--ripngd/ripng_cli.h58
-rw-r--r--ripngd/ripng_main.c1
-rw-r--r--ripngd/ripng_nb.c252
-rw-r--r--ripngd/ripng_nb.h179
-rw-r--r--ripngd/ripng_nb_config.c714
-rw-r--r--ripngd/ripng_nb_rpcs.c107
-rw-r--r--ripngd/ripng_nb_state.c236
-rw-r--r--ripngd/ripng_northbound.c1234
-rw-r--r--ripngd/ripngd.h3
-rw-r--r--ripngd/subdir.am7
-rw-r--r--tests/topotests/Dockerfile20
-rw-r--r--tools/gen_northbound_callbacks.c55
-rw-r--r--vrrpd/vrrp.c24
-rw-r--r--zebra/rt_netlink.c9
-rw-r--r--zebra/zebra_nhg.c3
-rw-r--r--zebra/zebra_vxlan.c14
77 files changed, 9924 insertions, 8682 deletions
diff --git a/README.md b/README.md
index bb13481cf2..937728c9e6 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+<p align="center">
+<img src="http://docs.frrouting.org/en/latest/_static/frr-icon.svg" alt="Icon" width="20%"/>
+</p>
+
FRRouting
=========
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index 90287114fc..6e956aa929 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -49,6 +49,8 @@ static void bs_admin_down_handler(struct bfd_session *bs, int nstate);
static void bs_down_handler(struct bfd_session *bs, int nstate);
static void bs_init_handler(struct bfd_session *bs, int nstate);
static void bs_up_handler(struct bfd_session *bs, int nstate);
+static void bs_neighbour_admin_down_handler(struct bfd_session *bfd,
+ uint8_t diag);
/* Zeroed array with the size of an IPv6 address. */
struct in6_addr zero_addr;
@@ -159,6 +161,7 @@ int bfd_session_enable(struct bfd_session *bs)
bs->vrf = vrf;
if (bs->vrf == NULL)
bs->vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ assert(bs->vrf);
if (bs->key.ifname[0]
&& BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
@@ -311,7 +314,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd)
/* Start sending control packets with poll bit immediately. */
ptm_bfd_snd(bfd, 0);
- control_notify(bfd);
+ control_notify(bfd, bfd->ses_state);
if (old_state != bfd->ses_state) {
bfd->stats.session_up++;
@@ -346,7 +349,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag)
/* only signal clients when going from up->down state */
if (old_state == PTM_BFD_UP)
- control_notify(bfd);
+ control_notify(bfd, PTM_BFD_DOWN);
/* Stop echo packet transmission if they are active */
if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
@@ -581,7 +584,7 @@ skip_echo:
/* Change and notify state change. */
bs->ses_state = PTM_BFD_ADM_DOWN;
- control_notify(bs);
+ control_notify(bs, bs->ses_state);
/* Don't try to send packets with a disabled session. */
if (bs->sock != -1)
@@ -595,7 +598,7 @@ skip_echo:
/* Change and notify state change. */
bs->ses_state = PTM_BFD_DOWN;
- control_notify(bs);
+ control_notify(bs, bs->ses_state);
/* Enable all timers. */
bfd_recvtimer_update(bs);
@@ -867,10 +870,46 @@ static void bs_init_handler(struct bfd_session *bs, int nstate)
}
}
+static void bs_neighbour_admin_down_handler(struct bfd_session *bfd,
+ uint8_t diag)
+{
+ int old_state = bfd->ses_state;
+
+ bfd->local_diag = diag;
+ bfd->discrs.remote_discr = 0;
+ bfd->ses_state = PTM_BFD_DOWN;
+ bfd->polling = 0;
+ bfd->demand_mode = 0;
+ monotime(&bfd->downtime);
+
+ /* Slow down the control packets, the connection is down. */
+ bs_set_slow_timers(bfd);
+
+ /* only signal clients when going from up->down state */
+ if (old_state == PTM_BFD_UP)
+ control_notify(bfd, PTM_BFD_ADM_DOWN);
+
+ /* Stop echo packet transmission if they are active */
+ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
+ ptm_bfd_echo_stop(bfd);
+
+ if (old_state != bfd->ses_state) {
+ bfd->stats.session_down++;
+
+ log_info("state-change: [%s] %s -> %s reason:%s",
+ bs_to_string(bfd), state_list[old_state].str,
+ state_list[bfd->ses_state].str,
+ get_diag_str(bfd->local_diag));
+ }
+}
+
static void bs_up_handler(struct bfd_session *bs, int nstate)
{
switch (nstate) {
case PTM_BFD_ADM_DOWN:
+ bs_neighbour_admin_down_handler(bs, BD_ADMIN_DOWN);
+ break;
+
case PTM_BFD_DOWN:
/* Peer lost or asked to shutdown connection. */
ptm_bfd_sess_dn(bs, BD_NEIGHBOR_DOWN);
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index a9c8bd183a..220dd6e0a8 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -365,7 +365,7 @@ TAILQ_HEAD(bcslist, bfd_control_socket);
int control_init(const char *path);
void control_shutdown(void);
-int control_notify(struct bfd_session *bs);
+int control_notify(struct bfd_session *bs, uint8_t notify_state);
int control_notify_config(const char *op, struct bfd_session *bs);
int control_accept(struct thread *t);
@@ -593,29 +593,6 @@ void bfdd_vty_init(void);
*/
void bfdd_cli_init(void);
-void bfd_cli_show_header(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void bfd_cli_show_header_end(struct vty *vty, struct lyd_node *dnode);
-void bfd_cli_show_single_hop_peer(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-void bfd_cli_show_multi_hop_peer(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-void bfd_cli_show_peer_end(struct vty *vty, struct lyd_node *dnode);
-void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-
/*
* ptm_adapter.c
@@ -628,14 +605,6 @@ void bfdd_sessions_enable_vrf(struct vrf *vrf);
void bfdd_sessions_disable_vrf(struct vrf *vrf);
void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf);
-int ptm_bfd_notify(struct bfd_session *bs);
-
-
-/*
- * bfdd_northbound.c
- *
- * BFD northbound callbacks.
- */
-extern const struct frr_yang_module_info frr_bfdd_info;
+int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state);
#endif /* _BFD_H_ */
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 7fbe6db163..ed36bb742e 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -529,8 +529,7 @@ int bfd_recv_cb(struct thread *t)
uint8_t msgbuf[1516];
struct bfd_vrf_global *bvrf = THREAD_ARG(t);
- if (bvrf)
- vrfid = bvrf->vrf->vrf_id;
+ vrfid = bvrf->vrf->vrf_id;
/* Schedule next read. */
bfd_sd_reschedule(bvrf, sd);
diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c
index 5657744f75..a91fa3d047 100644
--- a/bfdd/bfdd.c
+++ b/bfdd/bfdd.c
@@ -23,6 +23,7 @@
#include "filter.h"
#include "bfd.h"
+#include "bfdd_nb.h"
#include "lib/version.h"
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index acb1801cc4..3e44fcb22a 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -31,6 +31,7 @@
#endif /* VTYSH_EXTRACT_PL */
#include "bfd.h"
+#include "bfdd_nb.h"
/*
* Definitions.
diff --git a/bfdd/bfdd_nb.c b/bfdd/bfdd_nb.c
new file mode 100644
index 0000000000..8d46742337
--- /dev/null
+++ b/bfdd/bfdd_nb.c
@@ -0,0 +1,388 @@
+/*
+ * BFD daemon northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/log.h"
+#include "lib/northbound.h"
+
+#include "bfdd_nb.h"
+
+/* clang-format off */
+const struct frr_yang_module_info frr_bfdd_info = {
+ .name = "frr-bfdd",
+ .nodes = {
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd",
+ .cbs = {
+ .create = bfdd_bfd_create,
+ .destroy = bfdd_bfd_destroy,
+ .cli_show = bfd_cli_show_header,
+ .cli_show_end = bfd_cli_show_header_end,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop",
+ .cbs = {
+ .create = bfdd_bfd_sessions_single_hop_create,
+ .destroy = bfdd_bfd_sessions_single_hop_destroy,
+ .get_next = bfdd_bfd_sessions_single_hop_get_next,
+ .get_keys = bfdd_bfd_sessions_single_hop_get_keys,
+ .lookup_entry = bfdd_bfd_sessions_single_hop_lookup_entry,
+ .cli_show = bfd_cli_show_single_hop_peer,
+ .cli_show_end = bfd_cli_show_peer_end,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/source-addr",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_source_addr_modify,
+ .destroy = bfdd_bfd_sessions_single_hop_source_addr_destroy,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_detection_multiplier_modify,
+ .cli_show = bfd_cli_show_mult,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-transmission-interval",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify,
+ .cli_show = bfd_cli_show_tx,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/required-receive-interval",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_required_receive_interval_modify,
+ .cli_show = bfd_cli_show_rx,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/administrative-down",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_administrative_down_modify,
+ .cli_show = bfd_cli_show_shutdown,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_echo_mode_modify,
+ .cli_show = bfd_cli_show_echo,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify,
+ .cli_show = bfd_cli_show_echo_interval,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-discriminator",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-state",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_local_state_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-diagnostic",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-multiplier",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-discriminator",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-state",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-diagnostic",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-multiplier",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-transmission-interval",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-receive-interval",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/detection-mode",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-down-time",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-up-time",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-down-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-up-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-input-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-output-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-echo-transmission-interval",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-input-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-output-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop",
+ .cbs = {
+ .create = bfdd_bfd_sessions_multi_hop_create,
+ .destroy = bfdd_bfd_sessions_multi_hop_destroy,
+ .get_next = bfdd_bfd_sessions_multi_hop_get_next,
+ .get_keys = bfdd_bfd_sessions_multi_hop_get_keys,
+ .lookup_entry = bfdd_bfd_sessions_multi_hop_lookup_entry,
+ .cli_show = bfd_cli_show_multi_hop_peer,
+ .cli_show_end = bfd_cli_show_peer_end,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/detection-multiplier",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_detection_multiplier_modify,
+ .cli_show = bfd_cli_show_mult,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/desired-transmission-interval",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify,
+ .cli_show = bfd_cli_show_tx,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/required-receive-interval",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_required_receive_interval_modify,
+ .cli_show = bfd_cli_show_rx,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/administrative-down",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_administrative_down_modify,
+ .cli_show = bfd_cli_show_shutdown,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-discriminator",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-state",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_local_state_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-diagnostic",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-multiplier",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-discriminator",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-state",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-diagnostic",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-multiplier",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-transmission-interval",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-receive-interval",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/detection-mode",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/last-down-time",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/last-up-time",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/session-down-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/session-up-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/control-packet-input-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/control-packet-output-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-echo-transmission-interval",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/echo-packet-input-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/echo-packet-output-count",
+ .cbs = {
+ .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h
new file mode 100644
index 0000000000..8377c87bb7
--- /dev/null
+++ b/bfdd/bfdd_nb.h
@@ -0,0 +1,217 @@
+/*
+ * BFD daemon northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#ifndef _FRR_BFDD_NB_H_
+#define _FRR_BFDD_NB_H_
+
+extern const struct frr_yang_module_info frr_bfdd_info;
+
+/* Mandatory callbacks. */
+int bfdd_bfd_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_destroy(enum nb_event event, const struct lyd_node *dnode);
+int bfdd_bfd_sessions_single_hop_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_single_hop_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+const void *bfdd_bfd_sessions_single_hop_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int bfdd_bfd_sessions_single_hop_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *
+bfdd_bfd_sessions_single_hop_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+int bfdd_bfd_sessions_single_hop_source_addr_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_single_hop_source_addr_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_single_hop_administrative_down_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_single_hop_echo_mode_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_local_state_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem(
+ const char *xpath, const void *list_entry);
+int bfdd_bfd_sessions_multi_hop_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_multi_hop_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+const void *bfdd_bfd_sessions_multi_hop_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int bfdd_bfd_sessions_multi_hop_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *
+bfdd_bfd_sessions_multi_hop_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+int bfdd_bfd_sessions_multi_hop_detection_multiplier_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_multi_hop_desired_transmission_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_multi_hop_required_receive_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int bfdd_bfd_sessions_multi_hop_administrative_down_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_local_discriminator_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_local_state_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_multi_hop_stats_local_diagnostic_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_multi_hop_stats_local_multiplier_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_remote_discriminator_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_remote_state_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_multi_hop_stats_remote_diagnostic_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_multi_hop_stats_remote_multiplier_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_negotiated_transmission_interval_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_negotiated_receive_interval_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_multi_hop_stats_detection_mode_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_multi_hop_stats_last_down_time_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_last_up_time_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_multi_hop_stats_session_down_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *bfdd_bfd_sessions_multi_hop_stats_session_up_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_control_packet_input_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_control_packet_output_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_negotiated_echo_transmission_interval_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_echo_packet_input_count_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+bfdd_bfd_sessions_multi_hop_stats_echo_packet_output_count_get_elem(
+ const char *xpath, const void *list_entry);
+
+/* Optional 'cli_show' callbacks. */
+void bfd_cli_show_header(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_header_end(struct vty *vty, struct lyd_node *dnode);
+void bfd_cli_show_single_hop_peer(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_multi_hop_peer(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_peer_end(struct vty *vty, struct lyd_node *dnode);
+void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+
+#endif /* _FRR_BFDD_NB_H_ */
diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c
new file mode 100644
index 0000000000..50f953115c
--- /dev/null
+++ b/bfdd/bfdd_nb_config.c
@@ -0,0 +1,520 @@
+/*
+ * BFD daemon northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/log.h"
+#include "lib/northbound.h"
+
+#include "bfd.h"
+#include "bfdd_nb.h"
+
+/*
+ * Helpers.
+ */
+static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode,
+ struct bfd_key *bk)
+{
+ const char *ifname = NULL, *vrfname = NULL;
+ struct sockaddr_any psa, lsa;
+
+ /* Required destination parameter. */
+ strtosa(yang_dnode_get_string(dnode, "./dest-addr"), &psa);
+
+ /* Get optional source address. */
+ memset(&lsa, 0, sizeof(lsa));
+ if (yang_dnode_exists(dnode, "./source-addr"))
+ strtosa(yang_dnode_get_string(dnode, "./source-addr"), &lsa);
+
+ /* Get optional interface and vrf names. */
+ if (yang_dnode_exists(dnode, "./interface"))
+ ifname = yang_dnode_get_string(dnode, "./interface");
+ if (yang_dnode_exists(dnode, "./vrf"))
+ vrfname = yang_dnode_get_string(dnode, "./vrf");
+
+ /* Generate the corresponding key. */
+ gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname);
+}
+
+static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource, bool mhop)
+{
+ struct bfd_session *bs;
+ const char *ifname;
+ struct bfd_key bk;
+ struct prefix p;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /*
+ * When `dest-addr` is IPv6 and link-local we must
+ * require interface name, otherwise we can't figure
+ * which interface to use to send the packets.
+ */
+ yang_dnode_get_prefix(&p, dnode, "./dest-addr");
+
+ /*
+ * To support old FRR versions we must allow empty
+ * interface to be specified, however that should
+ * change in the future.
+ */
+ if (yang_dnode_exists(dnode, "./interface"))
+ ifname = yang_dnode_get_string(dnode, "./interface");
+ else
+ ifname = "";
+
+ if (p.family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)
+ && strlen(ifname) == 0) {
+ zlog_warn(
+ "%s: when using link-local you must specify "
+ "an interface.",
+ __func__);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+
+ case NB_EV_PREPARE:
+ bfd_session_get_key(mhop, dnode, &bk);
+ bs = bfd_key_lookup(bk);
+
+ /* This session was already configured by another daemon. */
+ if (bs != NULL) {
+ /* Now it is configured also by CLI. */
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
+ bs->refcount++;
+
+ resource->ptr = bs;
+ break;
+ }
+
+ bs = bfd_session_new();
+ if (bs == NULL)
+ return NB_ERR_RESOURCE;
+
+ /* Fill the session key. */
+ bfd_session_get_key(mhop, dnode, &bs->key);
+
+ /* Set configuration flags. */
+ bs->refcount = 1;
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
+ if (mhop)
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_MH);
+ if (bs->key.family == AF_INET6)
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
+
+ resource->ptr = bs;
+ break;
+
+ case NB_EV_APPLY:
+ bs = resource->ptr;
+
+ /* Only attempt to registrate if freshly allocated. */
+ if (bs->discrs.my_discr == 0 && bs_registrate(bs) == NULL)
+ return NB_ERR_RESOURCE;
+
+ nb_running_set_entry(dnode, bs);
+ break;
+
+ case NB_EV_ABORT:
+ bs = resource->ptr;
+ if (bs->refcount <= 1)
+ bfd_session_free(resource->ptr);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int bfd_session_destroy(enum nb_event event,
+ const struct lyd_node *dnode, bool mhop)
+{
+ struct bfd_session *bs;
+ struct bfd_key bk;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ bfd_session_get_key(mhop, dnode, &bk);
+ if (bfd_key_lookup(bk) == NULL)
+ return NB_ERR_INCONSISTENCY;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ bs = nb_running_unset_entry(dnode);
+ /* CLI is not using this session anymore. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) == 0)
+ break;
+
+ BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
+ bs->refcount--;
+ /* There are still daemons using it. */
+ if (bs->refcount > 0)
+ break;
+
+ bfd_session_free(bs);
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd
+ */
+int bfdd_bfd_create(enum nb_event event,
+ const struct lyd_node *dnode __attribute__((__unused__)),
+ union nb_resource *resource __attribute__((__unused__)))
+{
+ /* NOTHING */
+ return NB_OK;
+}
+
+int bfdd_bfd_destroy(enum nb_event event, const struct lyd_node *dnode)
+{
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* NOTHING */
+ return NB_OK;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ return NB_OK;
+
+ case NB_EV_APPLY:
+ bfd_sessions_remove_manual();
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ return NB_OK;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop
+ */
+int bfdd_bfd_sessions_single_hop_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return bfd_session_create(event, dnode, resource, false);
+}
+
+int bfdd_bfd_sessions_single_hop_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return bfd_session_destroy(event, dnode, false);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/source-addr
+ */
+int bfdd_bfd_sessions_single_hop_source_addr_modify(enum nb_event event
+ __attribute__((__unused__)),
+ const struct lyd_node *dnode
+ __attribute__((__unused__)),
+ union nb_resource *resource
+ __attribute__((__unused__)))
+{
+ return NB_OK;
+}
+
+int bfdd_bfd_sessions_single_hop_source_addr_destroy(
+ enum nb_event event __attribute__((__unused__)),
+ const struct lyd_node *dnode __attribute__((__unused__)))
+{
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier
+ */
+int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource __attribute__((__unused__)))
+{
+ uint8_t detection_multiplier = yang_dnode_get_uint8(dnode, NULL);
+ struct bfd_session *bs;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ bs = nb_running_get_entry(dnode, NULL, true);
+ bs->detect_mult = detection_multiplier;
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-transmission-interval
+ */
+int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource __attribute__((__unused__)))
+{
+ uint32_t tx_interval = yang_dnode_get_uint32(dnode, NULL);
+ struct bfd_session *bs;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ if (tx_interval < 10000 || tx_interval > 60000000)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ bs = nb_running_get_entry(dnode, NULL, true);
+ if (tx_interval == bs->timers.desired_min_tx)
+ return NB_OK;
+
+ bs->timers.desired_min_tx = tx_interval;
+ bfd_set_polling(bs);
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/required-receive-interval
+ */
+int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource __attribute__((__unused__)))
+{
+ uint32_t rx_interval = yang_dnode_get_uint32(dnode, NULL);
+ struct bfd_session *bs;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ if (rx_interval < 10000 || rx_interval > 60000000)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ bs = nb_running_get_entry(dnode, NULL, true);
+ if (rx_interval == bs->timers.required_min_rx)
+ return NB_OK;
+
+ bs->timers.required_min_rx = rx_interval;
+ bfd_set_polling(bs);
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/administrative-down
+ */
+int bfdd_bfd_sessions_single_hop_administrative_down_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource __attribute__((__unused__)))
+{
+ bool shutdown = yang_dnode_get_bool(dnode, NULL);
+ struct bfd_session *bs;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ return NB_OK;
+
+ case NB_EV_APPLY:
+ break;
+
+ case NB_EV_ABORT:
+ return NB_OK;
+ }
+
+ bs = nb_running_get_entry(dnode, NULL, true);
+
+ if (shutdown == false) {
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return NB_OK;
+
+ BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ /* Change and notify state change. */
+ bs->ses_state = PTM_BFD_DOWN;
+ control_notify(bs, bs->ses_state);
+
+ /* Enable all timers. */
+ bfd_recvtimer_update(bs);
+ bfd_xmttimer_update(bs, bs->xmt_TO);
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
+ bfd_echo_recvtimer_update(bs);
+ bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
+ }
+ } else {
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return NB_OK;
+
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ /* Disable all events. */
+ bfd_recvtimer_delete(bs);
+ bfd_echo_recvtimer_delete(bs);
+ bfd_xmttimer_delete(bs);
+ bfd_echo_xmttimer_delete(bs);
+
+ /* Change and notify state change. */
+ bs->ses_state = PTM_BFD_ADM_DOWN;
+ control_notify(bs, bs->ses_state);
+
+ ptm_bfd_snd(bs, 0);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode
+ */
+int bfdd_bfd_sessions_single_hop_echo_mode_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource
+ __attribute__((__unused__)))
+{
+ bool echo = yang_dnode_get_bool(dnode, NULL);
+ struct bfd_session *bs;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ return NB_OK;
+
+ case NB_EV_APPLY:
+ break;
+
+ case NB_EV_ABORT:
+ return NB_OK;
+ }
+
+ bs = nb_running_get_entry(dnode, NULL, true);
+
+ if (echo == false) {
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ return NB_OK;
+
+ BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+ ptm_bfd_echo_stop(bs);
+ } else {
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ return NB_OK;
+
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+ /* Apply setting immediately. */
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ bs_echo_timer_handler(bs);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval
+ */
+int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource __attribute__((__unused__)))
+{
+ uint32_t echo_interval = yang_dnode_get_uint32(dnode, NULL);
+ struct bfd_session *bs;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ if (echo_interval < 10000 || echo_interval > 60000000)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ bs = nb_running_get_entry(dnode, NULL, true);
+ if (echo_interval == bs->timers.required_min_echo)
+ return NB_OK;
+
+ bs->timers.required_min_echo = echo_interval;
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/multi-hop
+ */
+int bfdd_bfd_sessions_multi_hop_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return bfd_session_create(event, dnode, resource, true);
+}
+
+int bfdd_bfd_sessions_multi_hop_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ return bfd_session_destroy(event, dnode, true);
+}
diff --git a/bfdd/bfdd_nb_state.c b/bfdd/bfdd_nb_state.c
new file mode 100644
index 0000000000..dfca3d1417
--- /dev/null
+++ b/bfdd/bfdd_nb_state.c
@@ -0,0 +1,383 @@
+/*
+ * BFD daemon northbound implementation.
+ *
+ * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
+ * Rafael Zalamena
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/log.h"
+#include "lib/northbound.h"
+
+#include "bfd.h"
+#include "bfdd_nb.h"
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop
+ */
+const void *bfdd_bfd_sessions_single_hop_get_next(const void *parent_list_entry
+ __attribute__((__unused__)),
+ const void *list_entry)
+{
+ return bfd_session_next(list_entry, false);
+}
+
+int bfdd_bfd_sessions_single_hop_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct bfd_session *bs = list_entry;
+ char dstbuf[INET6_ADDRSTRLEN];
+
+ inet_ntop(bs->key.family, &bs->key.peer, dstbuf, sizeof(dstbuf));
+
+ keys->num = 3;
+ strlcpy(keys->key[0], dstbuf, sizeof(keys->key[0]));
+ strlcpy(keys->key[1], bs->key.ifname, sizeof(keys->key[1]));
+ strlcpy(keys->key[2], bs->key.vrfname, sizeof(keys->key[2]));
+
+ return NB_OK;
+}
+
+const void *
+bfdd_bfd_sessions_single_hop_lookup_entry(const void *parent_list_entry
+ __attribute__((__unused__)),
+ const struct yang_list_keys *keys)
+{
+ const char *dest_addr = keys->key[0];
+ const char *ifname = keys->key[1];
+ const char *vrf = keys->key[2];
+ struct sockaddr_any psa, lsa;
+ struct bfd_key bk;
+
+ strtosa(dest_addr, &psa);
+ memset(&lsa, 0, sizeof(lsa));
+ gen_bfd_key(&bk, &psa, &lsa, false, ifname, vrf);
+
+ return bfd_key_lookup(bk);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-discriminator
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint32(xpath, bs->discrs.my_discr);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-state
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_local_state_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_enum(xpath, bs->ses_state);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-diagnostic
+ */
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_enum(xpath, bs->local_diag);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-multiplier
+ */
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_int8(xpath, bs->detect_mult);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-discriminator
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ if (bs->discrs.remote_discr == 0)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, bs->discrs.remote_discr);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-state
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_enum(xpath, bs->ses_state);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-diagnostic
+ */
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_enum(xpath, bs->remote_diag);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-multiplier
+ */
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_int8(xpath, bs->remote_detect_mult);
+}
+
+/*
+ * XPath:
+ * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-transmission-interval
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint32(xpath, bs->remote_timers.desired_min_tx);
+}
+
+/*
+ * XPath:
+ * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-receive-interval
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint32(xpath, bs->remote_timers.required_min_rx);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/detection-mode
+ */
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+ int detection_mode;
+
+ /*
+ * Detection mode:
+ * 1. Async with echo
+ * 2. Async without echo
+ * 3. Demand with echo
+ * 4. Demand without echo
+ *
+ * TODO: support demand mode.
+ */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ detection_mode = 1;
+ else
+ detection_mode = 2;
+
+ return yang_data_new_enum(xpath, detection_mode);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-down-time
+ */
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem(
+ const char *xpath __attribute__((__unused__)),
+ const void *list_entry __attribute__((__unused__)))
+{
+ /*
+ * TODO: implement me.
+ *
+ * No yang support for time elements yet.
+ */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-up-time
+ */
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem(
+ const char *xpath __attribute__((__unused__)),
+ const void *list_entry __attribute__((__unused__)))
+{
+ /*
+ * TODO: implement me.
+ *
+ * No yang support for time elements yet.
+ */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-down-count
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint64(xpath, bs->stats.session_down);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-up-count
+ */
+struct yang_data *bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint64(xpath, bs->stats.session_up);
+}
+
+/*
+ * XPath:
+ * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-input-count
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint64(xpath, bs->stats.rx_ctrl_pkt);
+}
+
+/*
+ * XPath:
+ * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-output-count
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint64(xpath, bs->stats.tx_ctrl_pkt);
+}
+
+/*
+ * XPath:
+ * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-echo-transmission-interval
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint32(xpath, bs->remote_timers.required_min_echo);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-input-count
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint64(xpath, bs->stats.rx_echo_pkt);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-output-count
+ */
+struct yang_data *
+bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct bfd_session *bs = list_entry;
+
+ return yang_data_new_uint64(xpath, bs->stats.tx_echo_pkt);
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/multi-hop
+ */
+const void *bfdd_bfd_sessions_multi_hop_get_next(const void *parent_list_entry
+ __attribute__((__unused__)),
+ const void *list_entry)
+{
+ return bfd_session_next(list_entry, true);
+}
+
+int bfdd_bfd_sessions_multi_hop_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct bfd_session *bs = list_entry;
+ char dstbuf[INET6_ADDRSTRLEN], srcbuf[INET6_ADDRSTRLEN];
+
+ inet_ntop(bs->key.family, &bs->key.peer, dstbuf, sizeof(dstbuf));
+ inet_ntop(bs->key.family, &bs->key.local, srcbuf, sizeof(srcbuf));
+
+ keys->num = 4;
+ strlcpy(keys->key[0], srcbuf, sizeof(keys->key[0]));
+ strlcpy(keys->key[1], dstbuf, sizeof(keys->key[1]));
+ strlcpy(keys->key[2], bs->key.ifname, sizeof(keys->key[2]));
+ strlcpy(keys->key[3], bs->key.vrfname, sizeof(keys->key[3]));
+
+ return NB_OK;
+}
+
+const void *
+bfdd_bfd_sessions_multi_hop_lookup_entry(const void *parent_list_entry
+ __attribute__((__unused__)),
+ const struct yang_list_keys *keys)
+{
+ const char *source_addr = keys->key[0];
+ const char *dest_addr = keys->key[1];
+ const char *ifname = keys->key[2];
+ const char *vrf = keys->key[3];
+ struct sockaddr_any psa, lsa;
+ struct bfd_key bk;
+
+ strtosa(dest_addr, &psa);
+ strtosa(source_addr, &lsa);
+ gen_bfd_key(&bk, &psa, &lsa, true, ifname, vrf);
+
+ return bfd_key_lookup(bk);
+}
diff --git a/bfdd/bfdd_northbound.c b/bfdd/bfdd_northbound.c
deleted file mode 100644
index 975fc7b31f..0000000000
--- a/bfdd/bfdd_northbound.c
+++ /dev/null
@@ -1,1236 +0,0 @@
-/*
- * BFD daemon northbound implementation.
- *
- * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
- * Rafael Zalamena
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA.
- */
-
-#include <zebra.h>
-
-#include "lib/log.h"
-#include "lib/northbound.h"
-
-#include "bfd.h"
-
-/*
- * Helpers.
- */
-static void bfd_session_get_key(bool mhop, const struct lyd_node *dnode,
- struct bfd_key *bk)
-{
- const char *ifname = NULL, *vrfname = NULL;
- struct sockaddr_any psa, lsa;
-
- /* Required destination parameter. */
- strtosa(yang_dnode_get_string(dnode, "./dest-addr"), &psa);
-
- /* Get optional source address. */
- memset(&lsa, 0, sizeof(lsa));
- if (yang_dnode_exists(dnode, "./source-addr"))
- strtosa(yang_dnode_get_string(dnode, "./source-addr"), &lsa);
-
- /* Get optional interface and vrf names. */
- if (yang_dnode_exists(dnode, "./interface"))
- ifname = yang_dnode_get_string(dnode, "./interface");
- if (yang_dnode_exists(dnode, "./vrf"))
- vrfname = yang_dnode_get_string(dnode, "./vrf");
-
- /* Generate the corresponding key. */
- gen_bfd_key(bk, &psa, &lsa, mhop, ifname, vrfname);
-}
-
-static int bfd_session_create(enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource, bool mhop)
-{
- struct bfd_session *bs;
- const char *ifname;
- struct bfd_key bk;
- struct prefix p;
-
- switch (event) {
- case NB_EV_VALIDATE:
- /*
- * When `dest-addr` is IPv6 and link-local we must
- * require interface name, otherwise we can't figure
- * which interface to use to send the packets.
- */
- yang_dnode_get_prefix(&p, dnode, "./dest-addr");
-
- /*
- * To support old FRR versions we must allow empty
- * interface to be specified, however that should
- * change in the future.
- */
- if (yang_dnode_exists(dnode, "./interface"))
- ifname = yang_dnode_get_string(dnode, "./interface");
- else
- ifname = "";
-
- if (p.family == AF_INET6
- && IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)
- && strlen(ifname) == 0) {
- zlog_warn("%s: when using link-local you must specify "
- "an interface.", __func__);
- return NB_ERR_VALIDATION;
- }
- break;
-
- case NB_EV_PREPARE:
- bfd_session_get_key(mhop, dnode, &bk);
- bs = bfd_key_lookup(bk);
-
- /* This session was already configured by another daemon. */
- if (bs != NULL) {
- /* Now it is configured also by CLI. */
- BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
- bs->refcount++;
-
- resource->ptr = bs;
- break;
- }
-
- bs = bfd_session_new();
- if (bs == NULL)
- return NB_ERR_RESOURCE;
-
- /* Fill the session key. */
- bfd_session_get_key(mhop, dnode, &bs->key);
-
- /* Set configuration flags. */
- bs->refcount = 1;
- BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
- if (mhop)
- BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_MH);
- if (bs->key.family == AF_INET6)
- BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_IPV6);
-
- resource->ptr = bs;
- break;
-
- case NB_EV_APPLY:
- bs = resource->ptr;
-
- /* Only attempt to registrate if freshly allocated. */
- if (bs->discrs.my_discr == 0 && bs_registrate(bs) == NULL)
- return NB_ERR_RESOURCE;
-
- nb_running_set_entry(dnode, bs);
- break;
-
- case NB_EV_ABORT:
- bs = resource->ptr;
- if (bs->refcount <= 1)
- bfd_session_free(resource->ptr);
- break;
- }
-
- return NB_OK;
-}
-
-static int bfd_session_destroy(enum nb_event event,
- const struct lyd_node *dnode, bool mhop)
-{
- struct bfd_session *bs;
- struct bfd_key bk;
-
- switch (event) {
- case NB_EV_VALIDATE:
- bfd_session_get_key(mhop, dnode, &bk);
- if (bfd_key_lookup(bk) == NULL)
- return NB_ERR_INCONSISTENCY;
- break;
-
- case NB_EV_PREPARE:
- /* NOTHING */
- break;
-
- case NB_EV_APPLY:
- bs = nb_running_unset_entry(dnode);
- /* CLI is not using this session anymore. */
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG) == 0)
- break;
-
- BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG);
- bs->refcount--;
- /* There are still daemons using it. */
- if (bs->refcount > 0)
- break;
-
- bfd_session_free(bs);
- break;
-
- case NB_EV_ABORT:
- /* NOTHING */
- break;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd
- */
-static int bfdd_bfd_create(enum nb_event event,
- const struct lyd_node *dnode
- __attribute__((__unused__)),
- union nb_resource *resource
- __attribute__((__unused__)))
-{
- /* NOTHING */
- return NB_OK;
-}
-
-static int bfdd_bfd_destroy(enum nb_event event, const struct lyd_node *dnode)
-{
- switch (event) {
- case NB_EV_VALIDATE:
- /* NOTHING */
- return NB_OK;
-
- case NB_EV_PREPARE:
- /* NOTHING */
- return NB_OK;
-
- case NB_EV_APPLY:
- bfd_sessions_remove_manual();
- break;
-
- case NB_EV_ABORT:
- /* NOTHING */
- return NB_OK;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop
- */
-static int bfdd_bfd_sessions_single_hop_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return bfd_session_create(event, dnode, resource, false);
-}
-
-static int bfdd_bfd_sessions_single_hop_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- return bfd_session_destroy(event, dnode, false);
-}
-
-static const void *
-bfdd_bfd_sessions_single_hop_get_next(const void *parent_list_entry
- __attribute__((__unused__)),
- const void *list_entry)
-{
- return bfd_session_next(list_entry, false);
-}
-
-static int bfdd_bfd_sessions_single_hop_get_keys(const void *list_entry,
- struct yang_list_keys *keys)
-{
- const struct bfd_session *bs = list_entry;
- char dstbuf[INET6_ADDRSTRLEN];
-
- inet_ntop(bs->key.family, &bs->key.peer, dstbuf, sizeof(dstbuf));
-
- keys->num = 3;
- strlcpy(keys->key[0], dstbuf, sizeof(keys->key[0]));
- strlcpy(keys->key[1], bs->key.ifname, sizeof(keys->key[1]));
- strlcpy(keys->key[2], bs->key.vrfname, sizeof(keys->key[2]));
-
- return NB_OK;
-}
-
-static const void *
-bfdd_bfd_sessions_single_hop_lookup_entry(const void *parent_list_entry
- __attribute__((__unused__)),
- const struct yang_list_keys *keys)
-{
- const char *dest_addr = keys->key[0];
- const char *ifname = keys->key[1];
- const char *vrf = keys->key[2];
- struct sockaddr_any psa, lsa;
- struct bfd_key bk;
-
- strtosa(dest_addr, &psa);
- memset(&lsa, 0, sizeof(lsa));
- gen_bfd_key(&bk, &psa, &lsa, false, ifname, vrf);
-
- return bfd_key_lookup(bk);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/source-addr
- */
-static int bfdd_bfd_sessions_single_hop_source_addr_modify(
- enum nb_event event __attribute__((__unused__)),
- const struct lyd_node *dnode __attribute__((__unused__)),
- union nb_resource *resource __attribute__((__unused__)))
-{
- return NB_OK;
-}
-
-static int bfdd_bfd_sessions_single_hop_source_addr_destroy(
- enum nb_event event __attribute__((__unused__)),
- const struct lyd_node *dnode __attribute__((__unused__)))
-{
- return NB_OK;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier
- */
-static int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource __attribute__((__unused__)))
-{
- uint8_t detection_multiplier = yang_dnode_get_uint8(dnode, NULL);
- struct bfd_session *bs;
-
- switch (event) {
- case NB_EV_VALIDATE:
- break;
-
- case NB_EV_PREPARE:
- /* NOTHING */
- break;
-
- case NB_EV_APPLY:
- bs = nb_running_get_entry(dnode, NULL, true);
- bs->detect_mult = detection_multiplier;
- break;
-
- case NB_EV_ABORT:
- /* NOTHING */
- break;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-transmission-interval
- */
-static int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource __attribute__((__unused__)))
-{
- uint32_t tx_interval = yang_dnode_get_uint32(dnode, NULL);
- struct bfd_session *bs;
-
- switch (event) {
- case NB_EV_VALIDATE:
- if (tx_interval < 10000 || tx_interval > 60000000)
- return NB_ERR_VALIDATION;
- break;
-
- case NB_EV_PREPARE:
- /* NOTHING */
- break;
-
- case NB_EV_APPLY:
- bs = nb_running_get_entry(dnode, NULL, true);
- if (tx_interval == bs->timers.desired_min_tx)
- return NB_OK;
-
- bs->timers.desired_min_tx = tx_interval;
- bfd_set_polling(bs);
- break;
-
- case NB_EV_ABORT:
- /* NOTHING */
- break;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/required-receive-interval
- */
-static int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource __attribute__((__unused__)))
-{
- uint32_t rx_interval = yang_dnode_get_uint32(dnode, NULL);
- struct bfd_session *bs;
-
- switch (event) {
- case NB_EV_VALIDATE:
- if (rx_interval < 10000 || rx_interval > 60000000)
- return NB_ERR_VALIDATION;
- break;
-
- case NB_EV_PREPARE:
- /* NOTHING */
- break;
-
- case NB_EV_APPLY:
- bs = nb_running_get_entry(dnode, NULL, true);
- if (rx_interval == bs->timers.required_min_rx)
- return NB_OK;
-
- bs->timers.required_min_rx = rx_interval;
- bfd_set_polling(bs);
- break;
-
- case NB_EV_ABORT:
- /* NOTHING */
- break;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/administrative-down
- */
-static int bfdd_bfd_sessions_single_hop_administrative_down_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource __attribute__((__unused__)))
-{
- bool shutdown = yang_dnode_get_bool(dnode, NULL);
- struct bfd_session *bs;
-
- switch (event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- return NB_OK;
-
- case NB_EV_APPLY:
- break;
-
- case NB_EV_ABORT:
- return NB_OK;
- }
-
- bs = nb_running_get_entry(dnode, NULL, true);
-
- if (shutdown == false) {
- if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
- return NB_OK;
-
- BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
-
- /* Change and notify state change. */
- bs->ses_state = PTM_BFD_DOWN;
- control_notify(bs);
-
- /* Enable all timers. */
- bfd_recvtimer_update(bs);
- bfd_xmttimer_update(bs, bs->xmt_TO);
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
- bfd_echo_recvtimer_update(bs);
- bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
- }
- } else {
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
- return NB_OK;
-
- BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
-
- /* Disable all events. */
- bfd_recvtimer_delete(bs);
- bfd_echo_recvtimer_delete(bs);
- bfd_xmttimer_delete(bs);
- bfd_echo_xmttimer_delete(bs);
-
- /* Change and notify state change. */
- bs->ses_state = PTM_BFD_ADM_DOWN;
- control_notify(bs);
-
- ptm_bfd_snd(bs, 0);
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode
- */
-static int bfdd_bfd_sessions_single_hop_echo_mode_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource __attribute__((__unused__)))
-{
- bool echo = yang_dnode_get_bool(dnode, NULL);
- struct bfd_session *bs;
-
- switch (event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- return NB_OK;
-
- case NB_EV_APPLY:
- break;
-
- case NB_EV_ABORT:
- return NB_OK;
- }
-
- bs = nb_running_get_entry(dnode, NULL, true);
-
- if (echo == false) {
- if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
- return NB_OK;
-
- BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
- ptm_bfd_echo_stop(bs);
- } else {
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
- return NB_OK;
-
- BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
- /* Apply setting immediately. */
- if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
- bs_echo_timer_handler(bs);
- }
-
- return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval
- */
-static int
-bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource __attribute__((__unused__)))
-{
- uint32_t echo_interval = yang_dnode_get_uint32(dnode, NULL);
- struct bfd_session *bs;
-
- switch (event) {
- case NB_EV_VALIDATE:
- if (echo_interval < 10000 || echo_interval > 60000000)
- return NB_ERR_VALIDATION;
- break;
-
- case NB_EV_PREPARE:
- /* NOTHING */
- break;
-
- case NB_EV_APPLY:
- bs = nb_running_get_entry(dnode, NULL, true);
- if (echo_interval == bs->timers.required_min_echo)
- return NB_OK;
-
- bs->timers.required_min_echo = echo_interval;
- break;
-
- case NB_EV_ABORT:
- /* NOTHING */
- break;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-discriminator
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint32(xpath, bs->discrs.my_discr);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-state
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_local_state_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_enum(xpath, bs->ses_state);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-diagnostic
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_enum(xpath, bs->local_diag);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-multiplier
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_int8(xpath, bs->detect_mult);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-discriminator
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- if (bs->discrs.remote_discr == 0)
- return NULL;
-
- return yang_data_new_uint32(xpath, bs->discrs.remote_discr);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-state
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_enum(xpath, bs->ses_state);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-diagnostic
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_enum(xpath, bs->remote_diag);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-multiplier
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_int8(xpath, bs->remote_detect_mult);
-}
-
-/*
- * XPath:
- * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-transmission-interval
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint32(xpath, bs->remote_timers.desired_min_tx);
-}
-
-/*
- * XPath:
- * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-receive-interval
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint32(xpath, bs->remote_timers.required_min_rx);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/detection-mode
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
- int detection_mode;
-
- /*
- * Detection mode:
- * 1. Async with echo
- * 2. Async without echo
- * 3. Demand with echo
- * 4. Demand without echo
- *
- * TODO: support demand mode.
- */
- if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
- detection_mode = 1;
- else
- detection_mode = 2;
-
- return yang_data_new_enum(xpath, detection_mode);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-down-time
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem(
- const char *xpath __attribute__((__unused__)),
- const void *list_entry __attribute__((__unused__)))
-{
- /*
- * TODO: implement me.
- *
- * No yang support for time elements yet.
- */
- return NULL;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-up-time
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem(
- const char *xpath __attribute__((__unused__)),
- const void *list_entry __attribute__((__unused__)))
-{
- /*
- * TODO: implement me.
- *
- * No yang support for time elements yet.
- */
- return NULL;
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-down-count
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint64(xpath, bs->stats.session_down);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-up-count
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint64(xpath, bs->stats.session_up);
-}
-
-/*
- * XPath:
- * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-input-count
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint64(xpath, bs->stats.rx_ctrl_pkt);
-}
-
-/*
- * XPath:
- * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-output-count
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint64(xpath, bs->stats.tx_ctrl_pkt);
-}
-
-/*
- * XPath:
- * /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-echo-transmission-interval
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint32(xpath, bs->remote_timers.required_min_echo);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-input-count
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint64(xpath, bs->stats.rx_echo_pkt);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-output-count
- */
-static struct yang_data *
-bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct bfd_session *bs = list_entry;
-
- return yang_data_new_uint64(xpath, bs->stats.tx_echo_pkt);
-}
-
-/*
- * XPath: /frr-bfdd:bfdd/bfd/sessions/multi-hop
- */
-static int bfdd_bfd_sessions_multi_hop_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return bfd_session_create(event, dnode, resource, true);
-}
-
-static int bfdd_bfd_sessions_multi_hop_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- return bfd_session_destroy(event, dnode, true);
-}
-
-static const void *
-bfdd_bfd_sessions_multi_hop_get_next(const void *parent_list_entry
- __attribute__((__unused__)),
- const void *list_entry)
-{
- return bfd_session_next(list_entry, true);
-}
-
-static int bfdd_bfd_sessions_multi_hop_get_keys(const void *list_entry,
- struct yang_list_keys *keys)
-{
- const struct bfd_session *bs = list_entry;
- char dstbuf[INET6_ADDRSTRLEN], srcbuf[INET6_ADDRSTRLEN];
-
- inet_ntop(bs->key.family, &bs->key.peer, dstbuf, sizeof(dstbuf));
- inet_ntop(bs->key.family, &bs->key.local, srcbuf, sizeof(srcbuf));
-
- keys->num = 4;
- strlcpy(keys->key[0], srcbuf, sizeof(keys->key[0]));
- strlcpy(keys->key[1], dstbuf, sizeof(keys->key[1]));
- strlcpy(keys->key[2], bs->key.ifname, sizeof(keys->key[2]));
- strlcpy(keys->key[3], bs->key.vrfname, sizeof(keys->key[3]));
-
- return NB_OK;
-}
-
-static const void *
-bfdd_bfd_sessions_multi_hop_lookup_entry(const void *parent_list_entry
- __attribute__((__unused__)),
- const struct yang_list_keys *keys)
-{
- const char *source_addr = keys->key[0];
- const char *dest_addr = keys->key[1];
- const char *ifname = keys->key[2];
- const char *vrf = keys->key[3];
- struct sockaddr_any psa, lsa;
- struct bfd_key bk;
-
- strtosa(dest_addr, &psa);
- strtosa(source_addr, &lsa);
- gen_bfd_key(&bk, &psa, &lsa, true, ifname, vrf);
-
- return bfd_key_lookup(bk);
-}
-
-/* clang-format off */
-const struct frr_yang_module_info frr_bfdd_info = {
- .name = "frr-bfdd",
- .nodes = {
- {
- .xpath = "/frr-bfdd:bfdd/bfd",
- .cbs = {
- .create = bfdd_bfd_create,
- .destroy = bfdd_bfd_destroy,
- .cli_show = bfd_cli_show_header,
- .cli_show_end = bfd_cli_show_header_end,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop",
- .cbs = {
- .create = bfdd_bfd_sessions_single_hop_create,
- .destroy = bfdd_bfd_sessions_single_hop_destroy,
- .get_next = bfdd_bfd_sessions_single_hop_get_next,
- .get_keys = bfdd_bfd_sessions_single_hop_get_keys,
- .lookup_entry = bfdd_bfd_sessions_single_hop_lookup_entry,
- .cli_show = bfd_cli_show_single_hop_peer,
- .cli_show_end = bfd_cli_show_peer_end,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/source-addr",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_source_addr_modify,
- .destroy = bfdd_bfd_sessions_single_hop_source_addr_destroy,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_detection_multiplier_modify,
- .cli_show = bfd_cli_show_mult,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-transmission-interval",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify,
- .cli_show = bfd_cli_show_tx,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/required-receive-interval",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_required_receive_interval_modify,
- .cli_show = bfd_cli_show_rx,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/administrative-down",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_administrative_down_modify,
- .cli_show = bfd_cli_show_shutdown,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/echo-mode",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_echo_mode_modify,
- .cli_show = bfd_cli_show_echo,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify,
- .cli_show = bfd_cli_show_echo_interval,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-discriminator",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-state",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_local_state_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-diagnostic",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/local-multiplier",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-discriminator",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-state",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-diagnostic",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/remote-multiplier",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-transmission-interval",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-receive-interval",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/detection-mode",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-down-time",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/last-up-time",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-down-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/session-up-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-input-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/control-packet-output-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/negotiated-echo-transmission-interval",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-input-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/stats/echo-packet-output-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop",
- .cbs = {
- .create = bfdd_bfd_sessions_multi_hop_create,
- .destroy = bfdd_bfd_sessions_multi_hop_destroy,
- .get_next = bfdd_bfd_sessions_multi_hop_get_next,
- .get_keys = bfdd_bfd_sessions_multi_hop_get_keys,
- .lookup_entry = bfdd_bfd_sessions_multi_hop_lookup_entry,
- .cli_show = bfd_cli_show_multi_hop_peer,
- .cli_show_end = bfd_cli_show_peer_end,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/detection-multiplier",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_detection_multiplier_modify,
- .cli_show = bfd_cli_show_mult,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/desired-transmission-interval",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify,
- .cli_show = bfd_cli_show_tx,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/required-receive-interval",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_required_receive_interval_modify,
- .cli_show = bfd_cli_show_rx,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/administrative-down",
- .cbs = {
- .modify = bfdd_bfd_sessions_single_hop_administrative_down_modify,
- .cli_show = bfd_cli_show_shutdown,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-discriminator",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-state",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_local_state_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-diagnostic",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_local_diagnostic_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/local-multiplier",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_local_multiplier_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-discriminator",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_discriminator_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-state",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_state_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-diagnostic",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_diagnostic_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/remote-multiplier",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_remote_multiplier_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-transmission-interval",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_transmission_interval_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-receive-interval",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_receive_interval_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/detection-mode",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_detection_mode_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/last-down-time",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_last_down_time_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/last-up-time",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_last_up_time_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/session-down-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_session_down_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/session-up-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_session_up_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/control-packet-input-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_input_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/control-packet-output-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_control_packet_output_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/negotiated-echo-transmission-interval",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_negotiated_echo_transmission_interval_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/echo-packet-input-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_input_count_get_elem,
- }
- },
- {
- .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/stats/echo-packet-output-count",
- .cbs = {
- .get_elem = bfdd_bfd_sessions_single_hop_stats_echo_packet_output_count_get_elem,
- }
- },
- {
- .xpath = NULL,
- },
- }
-};
diff --git a/bfdd/control.c b/bfdd/control.c
index c308d647d8..5c5421c041 100644
--- a/bfdd/control.c
+++ b/bfdd/control.c
@@ -774,13 +774,13 @@ static void _control_notify(struct bfd_control_socket *bcs,
control_queue_enqueue(bcs, bcm);
}
-int control_notify(struct bfd_session *bs)
+int control_notify(struct bfd_session *bs, uint8_t notify_state)
{
struct bfd_control_socket *bcs;
struct bfd_notify_peer *bnp;
/* Notify zebra listeners as well. */
- ptm_bfd_notify(bs);
+ ptm_bfd_notify(bs, notify_state);
/*
* PERFORMANCE: reuse the bfd_control_msg allocated data for
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
index df48bc2af0..dcca70b796 100644
--- a/bfdd/ptm_adapter.c
+++ b/bfdd/ptm_adapter.c
@@ -153,7 +153,7 @@ static int _ptm_msg_address(struct stream *msg, int family, const void *addr)
return 0;
}
-int ptm_bfd_notify(struct bfd_session *bs)
+int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state)
{
struct stream *msg;
@@ -204,12 +204,15 @@ int ptm_bfd_notify(struct bfd_session *bs)
_ptm_msg_address(msg, bs->key.family, &bs->key.peer);
/* BFD status */
- switch (bs->ses_state) {
+ switch (notify_state) {
case PTM_BFD_UP:
stream_putl(msg, BFD_STATUS_UP);
break;
case PTM_BFD_ADM_DOWN:
+ stream_putl(msg, BFD_STATUS_ADMIN_DOWN);
+ break;
+
case PTM_BFD_DOWN:
case PTM_BFD_INIT:
stream_putl(msg, BFD_STATUS_DOWN);
@@ -432,7 +435,7 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
return;
}
- ptm_bfd_notify(bs);
+ ptm_bfd_notify(bs, bs->ses_state);
}
static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
@@ -461,6 +464,10 @@ static void bfdd_dest_deregister(struct stream *msg, vrf_id_t vrf_id)
if (bs->refcount ||
BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CONFIG))
return;
+
+ bs->ses_state = PTM_BFD_ADM_DOWN;
+ ptm_bfd_snd(bs, 0);
+
ptm_bfd_sess_del(&bpc);
}
diff --git a/bfdd/subdir.am b/bfdd/subdir.am
index 5e3c3d4765..ed1d3962bf 100644
--- a/bfdd/subdir.am
+++ b/bfdd/subdir.am
@@ -13,7 +13,9 @@ endif
bfdd_libbfd_a_SOURCES = \
bfdd/bfd.c \
- bfdd/bfdd_northbound.c \
+ bfdd/bfdd_nb.c \
+ bfdd/bfdd_nb_config.c \
+ bfdd/bfdd_nb_state.c \
bfdd/bfdd_vty.c \
bfdd/bfdd_cli.c \
bfdd/bfd_packet.c \
@@ -32,6 +34,7 @@ bfdd/bfdd_cli.$(OBJEXT): bfdd/bfdd_cli_clippy.c
noinst_HEADERS += \
bfdd/bfdctl.h \
+ bfdd/bfdd_nb.h \
bfdd/bfd.h \
# end
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index 57fef8e913..0ed6057eac 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -282,7 +282,8 @@ static void bgp_bfd_peer_status_update(struct peer *peer, int status,
return;
old_status = bfd_info->status;
- bfd_info->status = status;
+ BFD_SET_CLIENT_STATUS(bfd_info->status, status);
+
bfd_info->last_update = bgp_clock();
if (status != old_status) {
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 648c3be47e..d37bf54734 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -614,8 +614,6 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
if ((mpath_count < maxpaths) && (new_mpath != new_best)
&& bgp_path_info_nexthop_cmp(prev_mpath,
new_mpath)) {
- if (new_mpath == next_mpath)
- bgp_path_info_mpath_next(new_mpath);
bgp_path_info_mpath_dequeue(new_mpath);
bgp_path_info_mpath_enqueue(prev_mpath,
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index de4f185ab2..77428bbb0f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1751,18 +1751,22 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
* if
* the peer (group) is configured to receive link-local nexthop
* unchanged
- * and it is available in the prefix OR we're not reflecting the route
- * and
+ * and it is available in the prefix OR we're not reflecting the route,
+ * link-local nexthop address is valid and
* the peer (group) to whom we're going to announce is on a shared
* network
* and this is either a self-originated route or the peer is EBGP.
+ * By checking if nexthop LL address is valid we are sure that
+ * we do not announce LL address as `::`.
*/
if (NEXTHOP_IS_V6) {
attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
if ((CHECK_FLAG(peer->af_flags[afi][safi],
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)
&& IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local))
- || (!reflect && peer->shared_network
+ || (!reflect
+ && IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local)
+ && peer->shared_network
&& (from == bgp->peer_self
|| peer->sort == BGP_PEER_EBGP))) {
attr->mp_nexthop_len =
@@ -7241,21 +7245,11 @@ void route_vty_out(struct vty *vty, struct prefix *p,
if (json_paths) {
json_nexthop_global = json_object_new_object();
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
- json_object_string_add(
- json_nexthop_global,
- nexthop_fqdn ? "fqdn" : "ip",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntoa(
- attr->mp_nexthop_global_in));
- else
- json_object_string_add(
- json_nexthop_global,
- nexthop_fqdn ? "fqdn" : "ip",
- nexthop_fqdn
- ? nexthop_fqdn
- : inet_ntoa(attr->nexthop));
+ json_object_string_add(json_nexthop_global,
+ nexthop_fqdn ? "fqdn" : "ip",
+ nexthop_fqdn
+ ? nexthop_fqdn
+ : inet_ntoa(attr->nexthop));
json_object_string_add(json_nexthop_global, "afi",
"ipv4");
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 1a3fa2c921..a2d4c0101e 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -7530,7 +7530,6 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
int bgp_config_write(struct vty *vty)
{
- int write = 0;
struct bgp *bgp;
struct peer_group *group;
struct peer *peer;
@@ -7541,9 +7540,6 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, "bgp route-map delay-timer %u\n",
bm->rmap_update_timer);
- if (write)
- vty_out(vty, "!\n");
-
/* BGP configuration. */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 83b05ce536..7c4f8eaa01 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -3190,12 +3190,8 @@ DEFUN (debug_rfapi_register_vn_un_l2o,
return CMD_WARNING_CONFIG_FAILED;
}
optary[opt_next].type = RFAPI_VN_OPTION_TYPE_L2ADDR;
- if (opt_next) {
- optary[opt_next - 1].next = optary + opt_next;
- } else {
- opt = optary;
- }
- ++opt_next;
+ opt = optary;
+
/* L2 option parsing END */
/* TBD fixme */
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index dc4a02e8b2..4fa64075c4 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -4708,8 +4708,6 @@ static int vnc_add_vrf_prefix(struct vty *vty, const char *arg_vrf,
rfapiQprefix2Rprefix(&pfx, &rpfx);
memset(optary, 0, sizeof(optary));
if (arg_rd) {
- if (opt != NULL)
- opt->next = &optary[cur_opt];
opt = &optary[cur_opt++];
opt->type = RFAPI_VN_OPTION_TYPE_INTERNAL_RD;
if (!str2prefix_rd(arg_rd, &opt->v.internal_rd)) {
diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c
index 51ec999764..df06105535 100644
--- a/bgpd/rfapi/vnc_import_bgp.c
+++ b/bgpd/rfapi/vnc_import_bgp.c
@@ -479,8 +479,6 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi(
encaptlvs = bpi->attr->vnc_subtlvs;
if (bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_RESERVED
&& bpi->attr->encap_tunneltype != BGP_ENCAP_TYPE_MPLS) {
- if (opt != NULL)
- opt->next = &optary[cur_opt];
opt = &optary[cur_opt++];
memset(opt, 0, sizeof(struct rfapi_un_option));
opt->type = RFAPI_UN_OPTION_TYPE_TUNNELTYPE;
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index d2ec6ff566..1d70521e68 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -48,6 +48,7 @@
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
#include "isisd/fabricd.h"
+#include "isisd/isis_nb.h"
extern struct isis *isis;
@@ -375,6 +376,20 @@ void isis_adj_print(struct isis_adjacency *adj)
return;
}
+const char *isis_adj_yang_state(enum isis_adj_state state)
+{
+ switch (state) {
+ case ISIS_ADJ_DOWN:
+ return "down";
+ case ISIS_ADJ_UP:
+ return "up";
+ case ISIS_ADJ_INITIALIZING:
+ return "init";
+ default:
+ return "failed";
+ }
+}
+
int isis_adj_expire(struct thread *thread)
{
struct isis_adjacency *adj;
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 2a4cb6e614..93583fc122 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -121,6 +121,7 @@ DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
void isis_adj_state_change(struct isis_adjacency *adj,
enum isis_adj_state state, const char *reason);
void isis_adj_print(struct isis_adjacency *adj);
+const char *isis_adj_yang_state(enum isis_adj_state state);
int isis_adj_expire(struct thread *thread);
void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
char detail);
diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c
index 8fc7997d79..cf4b841798 100644
--- a/isisd/isis_bfd.c
+++ b/isisd/isis_bfd.c
@@ -118,7 +118,8 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
int old_status = adj->bfd_session->status;
- adj->bfd_session->status = new_status;
+ BFD_SET_CLIENT_STATUS(adj->bfd_session->status, new_status);
+
if (old_status == new_status)
return;
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 29fb725b04..1d0e6549df 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -58,6 +58,7 @@
#include "isisd/isis_mt.h"
#include "isisd/isis_errors.h"
#include "isisd/isis_tx_queue.h"
+#include "isisd/isis_nb.h"
DEFINE_QOBJ_TYPE(isis_circuit)
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 37f4dcfabd..3144b3c28e 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -32,7 +32,7 @@
#include "yang.h"
#include "lib/linklist.h"
#include "isisd/isisd.h"
-#include "isisd/isis_cli.h"
+#include "isisd/isis_nb.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_csm.h"
diff --git a/isisd/isis_cli.h b/isisd/isis_cli.h
deleted file mode 100644
index 6621dc0fc0..0000000000
--- a/isisd/isis_cli.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2018 Volta Networks
- * Emanuele Di Pascale
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef ISISD_ISIS_CLI_H_
-#define ISISD_ISIS_CLI_H_
-
-/* add cli_show declarations here as externs */
-void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_bfd_monitoring(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_area_address(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_is_type(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_dynamic_hostname(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_attached(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_overload(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_metric_style(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_area_pwd(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_domain_pwd(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_lsp_gen_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_lsp_ref_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_lsp_max_lifetime(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_lsp_mtu(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_spf_min_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_purge_origin(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_mpls_te(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_mpls_te_router_addr(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_def_origin_ipv4(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_def_origin_ipv6(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_redistribute_ipv4(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_redistribute_ipv6(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_passive(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_password(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_metric(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_hello_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_hello_multi(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_threeway_shake(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_hello_padding(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_csnp_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_psnp_interval(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_mt_ipv4_unicast(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_network_type(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-
-#endif /* ISISD_ISIS_CLI_H_ */
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 061e758831..c0b90e8439 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -57,6 +57,7 @@
#include "isisd/isis_te.h"
#include "isisd/fabricd.h"
#include "isisd/isis_tx_queue.h"
+#include "isisd/isis_nb.h"
static int lsp_refresh(struct thread *thread);
static int lsp_l1_refresh_pseudo(struct thread *thread);
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 718924daf2..2ef0065180 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -57,6 +57,7 @@
#include "isisd/isis_lsp.h"
#include "isisd/isis_mt.h"
#include "isisd/fabricd.h"
+#include "isisd/isis_nb.h"
/* Default configuration file name */
#define ISISD_DEFAULT_CONFIG "isisd.conf"
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
new file mode 100644
index 0000000000..d84e533240
--- /dev/null
+++ b/isisd/isis_nb.c
@@ -0,0 +1,815 @@
+/*
+ * Copyright (C) 2018 Volta Networks
+ * Emanuele Di Pascale
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "isisd/isis_nb.h"
+
+/* clang-format off */
+const struct frr_yang_module_info frr_isisd_info = {
+ .name = "frr-isisd",
+ .nodes = {
+ {
+ .xpath = "/frr-isisd:isis/instance",
+ .cbs = {
+ .cli_show = cli_show_router_isis,
+ .create = isis_instance_create,
+ .destroy = isis_instance_destroy,
+ },
+ .priority = NB_DFLT_PRIORITY - 1,
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/is-type",
+ .cbs = {
+ .cli_show = cli_show_isis_is_type,
+ .modify = isis_instance_is_type_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/area-address",
+ .cbs = {
+ .cli_show = cli_show_isis_area_address,
+ .create = isis_instance_area_address_create,
+ .destroy = isis_instance_area_address_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/dynamic-hostname",
+ .cbs = {
+ .cli_show = cli_show_isis_dynamic_hostname,
+ .modify = isis_instance_dynamic_hostname_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/attached",
+ .cbs = {
+ .cli_show = cli_show_isis_attached,
+ .modify = isis_instance_attached_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/overload",
+ .cbs = {
+ .cli_show = cli_show_isis_overload,
+ .modify = isis_instance_overload_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/metric-style",
+ .cbs = {
+ .cli_show = cli_show_isis_metric_style,
+ .modify = isis_instance_metric_style_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/purge-originator",
+ .cbs = {
+ .cli_show = cli_show_isis_purge_origin,
+ .modify = isis_instance_purge_originator_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/mtu",
+ .cbs = {
+ .cli_show = cli_show_isis_lsp_mtu,
+ .modify = isis_instance_lsp_mtu_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/refresh-interval",
+ .cbs = {
+ .cli_show = cli_show_isis_lsp_ref_interval,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/refresh-interval/level-1",
+ .cbs = {
+ .modify = isis_instance_lsp_refresh_interval_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/refresh-interval/level-2",
+ .cbs = {
+ .modify = isis_instance_lsp_refresh_interval_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/maximum-lifetime",
+ .cbs = {
+ .cli_show = cli_show_isis_lsp_max_lifetime,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/maximum-lifetime/level-1",
+ .cbs = {
+ .modify = isis_instance_lsp_maximum_lifetime_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/maximum-lifetime/level-2",
+ .cbs = {
+ .modify = isis_instance_lsp_maximum_lifetime_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/generation-interval",
+ .cbs = {
+ .cli_show = cli_show_isis_lsp_gen_interval,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/generation-interval/level-1",
+ .cbs = {
+ .modify = isis_instance_lsp_generation_interval_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/lsp/generation-interval/level-2",
+ .cbs = {
+ .modify = isis_instance_lsp_generation_interval_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay",
+ .cbs = {
+ .apply_finish = ietf_backoff_delay_apply_finish,
+ .cli_show = cli_show_isis_spf_ietf_backoff,
+ .create = isis_instance_spf_ietf_backoff_delay_create,
+ .destroy = isis_instance_spf_ietf_backoff_delay_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/init-delay",
+ .cbs = {
+ .modify = isis_instance_spf_ietf_backoff_delay_init_delay_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/short-delay",
+ .cbs = {
+ .modify = isis_instance_spf_ietf_backoff_delay_short_delay_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/long-delay",
+ .cbs = {
+ .modify = isis_instance_spf_ietf_backoff_delay_long_delay_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/hold-down",
+ .cbs = {
+ .modify = isis_instance_spf_ietf_backoff_delay_hold_down_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/time-to-learn",
+ .cbs = {
+ .modify = isis_instance_spf_ietf_backoff_delay_time_to_learn_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/minimum-interval",
+ .cbs = {
+ .cli_show = cli_show_isis_spf_min_interval,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/minimum-interval/level-1",
+ .cbs = {
+ .modify = isis_instance_spf_minimum_interval_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/spf/minimum-interval/level-2",
+ .cbs = {
+ .modify = isis_instance_spf_minimum_interval_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/area-password",
+ .cbs = {
+ .apply_finish = area_password_apply_finish,
+ .cli_show = cli_show_isis_area_pwd,
+ .create = isis_instance_area_password_create,
+ .destroy = isis_instance_area_password_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/area-password/password",
+ .cbs = {
+ .modify = isis_instance_area_password_password_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/area-password/password-type",
+ .cbs = {
+ .modify = isis_instance_area_password_password_type_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/area-password/authenticate-snp",
+ .cbs = {
+ .modify = isis_instance_area_password_authenticate_snp_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/domain-password",
+ .cbs = {
+ .apply_finish = domain_password_apply_finish,
+ .cli_show = cli_show_isis_domain_pwd,
+ .create = isis_instance_domain_password_create,
+ .destroy = isis_instance_domain_password_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/domain-password/password",
+ .cbs = {
+ .modify = isis_instance_domain_password_password_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/domain-password/password-type",
+ .cbs = {
+ .modify = isis_instance_domain_password_password_type_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/domain-password/authenticate-snp",
+ .cbs = {
+ .modify = isis_instance_domain_password_authenticate_snp_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4",
+ .cbs = {
+ .apply_finish = default_info_origin_ipv4_apply_finish,
+ .cli_show = cli_show_isis_def_origin_ipv4,
+ .create = isis_instance_default_information_originate_ipv4_create,
+ .destroy = isis_instance_default_information_originate_ipv4_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/always",
+ .cbs = {
+ .modify = isis_instance_default_information_originate_ipv4_always_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/route-map",
+ .cbs = {
+ .destroy = isis_instance_default_information_originate_ipv4_route_map_destroy,
+ .modify = isis_instance_default_information_originate_ipv4_route_map_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/metric",
+ .cbs = {
+ .modify = isis_instance_default_information_originate_ipv4_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6",
+ .cbs = {
+ .apply_finish = default_info_origin_ipv6_apply_finish,
+ .cli_show = cli_show_isis_def_origin_ipv6,
+ .create = isis_instance_default_information_originate_ipv6_create,
+ .destroy = isis_instance_default_information_originate_ipv6_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/always",
+ .cbs = {
+ .modify = isis_instance_default_information_originate_ipv6_always_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/route-map",
+ .cbs = {
+ .destroy = isis_instance_default_information_originate_ipv6_route_map_destroy,
+ .modify = isis_instance_default_information_originate_ipv6_route_map_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/metric",
+ .cbs = {
+ .modify = isis_instance_default_information_originate_ipv6_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv4",
+ .cbs = {
+ .apply_finish = redistribute_ipv4_apply_finish,
+ .cli_show = cli_show_isis_redistribute_ipv4,
+ .create = isis_instance_redistribute_ipv4_create,
+ .destroy = isis_instance_redistribute_ipv4_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/route-map",
+ .cbs = {
+ .destroy = isis_instance_redistribute_ipv4_route_map_destroy,
+ .modify = isis_instance_redistribute_ipv4_route_map_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric",
+ .cbs = {
+ .modify = isis_instance_redistribute_ipv4_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv6",
+ .cbs = {
+ .apply_finish = redistribute_ipv6_apply_finish,
+ .cli_show = cli_show_isis_redistribute_ipv6,
+ .create = isis_instance_redistribute_ipv6_create,
+ .destroy = isis_instance_redistribute_ipv6_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/route-map",
+ .cbs = {
+ .destroy = isis_instance_redistribute_ipv6_route_map_destroy,
+ .modify = isis_instance_redistribute_ipv6_route_map_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric",
+ .cbs = {
+ .modify = isis_instance_redistribute_ipv6_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast",
+ .cbs = {
+ .cli_show = cli_show_isis_mt_ipv4_multicast,
+ .create = isis_instance_multi_topology_ipv4_multicast_create,
+ .destroy = isis_instance_multi_topology_ipv4_multicast_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast/overload",
+ .cbs = {
+ .modify = isis_instance_multi_topology_ipv4_multicast_overload_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-management",
+ .cbs = {
+ .cli_show = cli_show_isis_mt_ipv4_mgmt,
+ .create = isis_instance_multi_topology_ipv4_management_create,
+ .destroy = isis_instance_multi_topology_ipv4_management_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-management/overload",
+ .cbs = {
+ .modify = isis_instance_multi_topology_ipv4_management_overload_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-unicast",
+ .cbs = {
+ .cli_show = cli_show_isis_mt_ipv6_unicast,
+ .create = isis_instance_multi_topology_ipv6_unicast_create,
+ .destroy = isis_instance_multi_topology_ipv6_unicast_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-unicast/overload",
+ .cbs = {
+ .modify = isis_instance_multi_topology_ipv6_unicast_overload_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-multicast",
+ .cbs = {
+ .cli_show = cli_show_isis_mt_ipv6_multicast,
+ .create = isis_instance_multi_topology_ipv6_multicast_create,
+ .destroy = isis_instance_multi_topology_ipv6_multicast_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-multicast/overload",
+ .cbs = {
+ .modify = isis_instance_multi_topology_ipv6_multicast_overload_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-management",
+ .cbs = {
+ .cli_show = cli_show_isis_mt_ipv6_mgmt,
+ .create = isis_instance_multi_topology_ipv6_management_create,
+ .destroy = isis_instance_multi_topology_ipv6_management_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-management/overload",
+ .cbs = {
+ .modify = isis_instance_multi_topology_ipv6_management_overload_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-dstsrc",
+ .cbs = {
+ .cli_show = cli_show_isis_mt_ipv6_dstsrc,
+ .create = isis_instance_multi_topology_ipv6_dstsrc_create,
+ .destroy = isis_instance_multi_topology_ipv6_dstsrc_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-dstsrc/overload",
+ .cbs = {
+ .modify = isis_instance_multi_topology_ipv6_dstsrc_overload_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/log-adjacency-changes",
+ .cbs = {
+ .cli_show = cli_show_isis_log_adjacency,
+ .modify = isis_instance_log_adjacency_changes_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/mpls-te",
+ .cbs = {
+ .cli_show = cli_show_isis_mpls_te,
+ .create = isis_instance_mpls_te_create,
+ .destroy = isis_instance_mpls_te_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/mpls-te/router-address",
+ .cbs = {
+ .cli_show = cli_show_isis_mpls_te_router_addr,
+ .destroy = isis_instance_mpls_te_router_address_destroy,
+ .modify = isis_instance_mpls_te_router_address_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis",
+ .cbs = {
+ .create = lib_interface_isis_create,
+ .destroy = lib_interface_isis_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/area-tag",
+ .cbs = {
+ .modify = lib_interface_isis_area_tag_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/circuit-type",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_circ_type,
+ .modify = lib_interface_isis_circuit_type_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/ipv4-routing",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_ipv4,
+ .modify = lib_interface_isis_ipv4_routing_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/ipv6-routing",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_ipv6,
+ .modify = lib_interface_isis_ipv6_routing_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/bfd-monitoring",
+ .cbs = {
+ .modify = lib_interface_isis_bfd_monitoring_modify,
+ .cli_show = cli_show_ip_isis_bfd_monitoring,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_csnp_interval,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1",
+ .cbs = {
+ .modify = lib_interface_isis_csnp_interval_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2",
+ .cbs = {
+ .modify = lib_interface_isis_csnp_interval_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_psnp_interval,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1",
+ .cbs = {
+ .modify = lib_interface_isis_psnp_interval_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2",
+ .cbs = {
+ .modify = lib_interface_isis_psnp_interval_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/padding",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_hello_padding,
+ .modify = lib_interface_isis_hello_padding_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/interval",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_hello_interval,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1",
+ .cbs = {
+ .modify = lib_interface_isis_hello_interval_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2",
+ .cbs = {
+ .modify = lib_interface_isis_hello_interval_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_hello_multi,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1",
+ .cbs = {
+ .modify = lib_interface_isis_hello_multiplier_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2",
+ .cbs = {
+ .modify = lib_interface_isis_hello_multiplier_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/metric",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_metric,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1",
+ .cbs = {
+ .modify = lib_interface_isis_metric_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2",
+ .cbs = {
+ .modify = lib_interface_isis_metric_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/priority",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_priority,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/priority/level-1",
+ .cbs = {
+ .modify = lib_interface_isis_priority_level_1_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/priority/level-2",
+ .cbs = {
+ .modify = lib_interface_isis_priority_level_2_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/network-type",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_network_type,
+ .modify = lib_interface_isis_network_type_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/passive",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_passive,
+ .modify = lib_interface_isis_passive_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_password,
+ .create = lib_interface_isis_password_create,
+ .destroy = lib_interface_isis_password_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password/password",
+ .cbs = {
+ .modify = lib_interface_isis_password_password_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password/password-type",
+ .cbs = {
+ .modify = lib_interface_isis_password_password_type_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/disable-three-way-handshake",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_threeway_shake,
+ .modify = lib_interface_isis_disable_three_way_handshake_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-unicast",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_mt_ipv4_unicast,
+ .modify = lib_interface_isis_multi_topology_ipv4_unicast_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-multicast",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_mt_ipv4_multicast,
+ .modify = lib_interface_isis_multi_topology_ipv4_multicast_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-management",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_mt_ipv4_mgmt,
+ .modify = lib_interface_isis_multi_topology_ipv4_management_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-unicast",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_mt_ipv6_unicast,
+ .modify = lib_interface_isis_multi_topology_ipv6_unicast_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-multicast",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_mt_ipv6_multicast,
+ .modify = lib_interface_isis_multi_topology_ipv6_multicast_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-management",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_mt_ipv6_mgmt,
+ .modify = lib_interface_isis_multi_topology_ipv6_management_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-dstsrc",
+ .cbs = {
+ .cli_show = cli_show_ip_isis_mt_ipv6_dstsrc,
+ .modify = lib_interface_isis_multi_topology_ipv6_dstsrc_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency",
+ .cbs = {
+ .get_next = lib_interface_isis_adjacencies_adjacency_get_next,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state",
+ .cbs = {
+ .get_elem = lib_interface_isis_adjacencies_adjacency_state_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_adjacency_changes_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_adjacency_number_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_init_fails_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_adjacency_rejects_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_id_len_mismatch_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_authentication_type_fails_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails",
+ .cbs = {
+ .get_elem = lib_interface_isis_event_counters_authentication_fails_get_elem,
+ }
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
new file mode 100644
index 0000000000..29a2ded0de
--- /dev/null
+++ b/isisd/isis_nb.h
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2018 Volta Networks
+ * Emanuele Di Pascale
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ISISD_ISIS_NB_H_
+#define ISISD_ISIS_NB_H_
+
+extern const struct frr_yang_module_info frr_isisd_info;
+
+/* Forward declaration(s). */
+struct isis_area;
+struct isis_circuit;
+struct isis_adjacency;
+
+/* Mandatory callbacks. */
+int isis_instance_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_destroy(enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_is_type_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_area_address_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_area_address_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int isis_instance_dynamic_hostname_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_attached_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_overload_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_metric_style_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_purge_originator_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_lsp_mtu_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_lsp_refresh_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_lsp_refresh_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_lsp_maximum_lifetime_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_lsp_maximum_lifetime_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_lsp_generation_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_lsp_generation_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_spf_ietf_backoff_delay_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_spf_ietf_backoff_delay_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int isis_instance_spf_ietf_backoff_delay_init_delay_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_spf_ietf_backoff_delay_short_delay_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_spf_ietf_backoff_delay_long_delay_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_spf_ietf_backoff_delay_hold_down_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_spf_ietf_backoff_delay_time_to_learn_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_spf_minimum_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_spf_minimum_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_area_password_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_area_password_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int isis_instance_area_password_password_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_area_password_password_type_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_area_password_authenticate_snp_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_domain_password_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_domain_password_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int isis_instance_domain_password_password_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_domain_password_password_type_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_domain_password_authenticate_snp_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_default_information_originate_ipv4_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_default_information_originate_ipv4_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_default_information_originate_ipv4_always_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_default_information_originate_ipv4_route_map_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_default_information_originate_ipv4_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_default_information_originate_ipv4_metric_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_default_information_originate_ipv6_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_default_information_originate_ipv6_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_default_information_originate_ipv6_always_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_default_information_originate_ipv6_route_map_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_default_information_originate_ipv6_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_default_information_originate_ipv6_metric_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_redistribute_ipv4_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_redistribute_ipv4_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int isis_instance_redistribute_ipv4_route_map_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_redistribute_ipv4_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_redistribute_ipv4_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_redistribute_ipv6_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_redistribute_ipv6_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int isis_instance_redistribute_ipv6_route_map_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_redistribute_ipv6_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_redistribute_ipv6_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv4_multicast_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv4_multicast_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_multi_topology_ipv4_multicast_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv4_management_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv4_management_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_multi_topology_ipv4_management_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv6_unicast_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv6_unicast_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_multi_topology_ipv6_unicast_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv6_multicast_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv6_multicast_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_multi_topology_ipv6_multicast_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv6_management_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv6_management_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_multi_topology_ipv6_management_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv6_dstsrc_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_multi_topology_ipv6_dstsrc_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int isis_instance_multi_topology_ipv6_dstsrc_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_log_adjacency_changes_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_mpls_te_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_mpls_te_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int isis_instance_mpls_te_router_address_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int isis_instance_mpls_te_router_address_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_isis_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_isis_area_tag_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_ipv4_routing_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_ipv6_routing_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_circuit_type_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_bfd_monitoring_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_csnp_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_csnp_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_psnp_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_psnp_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_hello_padding_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_hello_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_hello_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_hello_multiplier_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_hello_multiplier_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_metric_level_1_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_metric_level_2_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_priority_level_1_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_priority_level_2_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_network_type_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_passive_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_password_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_password_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int lib_interface_isis_password_password_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_password_password_type_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_disable_three_way_handshake_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_multi_topology_ipv4_unicast_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_multi_topology_ipv4_multicast_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_multi_topology_ipv4_management_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_multi_topology_ipv6_unicast_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_multi_topology_ipv6_multicast_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_multi_topology_ipv6_management_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+const void *
+lib_interface_isis_adjacencies_adjacency_get_next(const void *parent_list_entry,
+ const void *list_entry);
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_state_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *lib_interface_isis_event_counters_adjacency_changes_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *lib_interface_isis_event_counters_adjacency_number_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_event_counters_init_fails_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *lib_interface_isis_event_counters_adjacency_rejects_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *lib_interface_isis_event_counters_id_len_mismatch_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_event_counters_authentication_type_fails_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+lib_interface_isis_event_counters_authentication_fails_get_elem(
+ const char *xpath, const void *list_entry);
+
+/* Optional 'apply_finish' callbacks. */
+void ietf_backoff_delay_apply_finish(const struct lyd_node *dnode);
+void area_password_apply_finish(const struct lyd_node *dnode);
+void domain_password_apply_finish(const struct lyd_node *dnode);
+void default_info_origin_apply_finish(const struct lyd_node *dnode, int family);
+void default_info_origin_ipv4_apply_finish(const struct lyd_node *dnode);
+void default_info_origin_ipv6_apply_finish(const struct lyd_node *dnode);
+void redistribute_apply_finish(const struct lyd_node *dnode, int family);
+void redistribute_ipv4_apply_finish(const struct lyd_node *dnode);
+void redistribute_ipv6_apply_finish(const struct lyd_node *dnode);
+
+/* Optional 'cli_show' callbacks. */
+void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_bfd_monitoring(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_area_address(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_is_type(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_dynamic_hostname(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_attached(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_overload(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_metric_style(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_area_pwd(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_domain_pwd(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_lsp_gen_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_lsp_ref_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_lsp_max_lifetime(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_lsp_mtu(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_spf_min_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_purge_origin(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mpls_te(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mpls_te_router_addr(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_def_origin_ipv4(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_def_origin_ipv6(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_redistribute_ipv4(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_redistribute_ipv6(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_passive(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_password(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_metric(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_hello_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_hello_multi(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_threeway_shake(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_hello_padding(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_csnp_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_psnp_interval(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_mt_ipv4_unicast(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_network_type(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+
+/* Notifications. */
+void isis_notif_db_overload(const struct isis_area *area, bool overload);
+void isis_notif_lsp_too_large(const struct isis_circuit *circuit,
+ uint32_t pdu_size, const char *lsp_id);
+void isis_notif_if_state_change(const struct isis_circuit *circuit, bool down);
+void isis_notif_corrupted_lsp(const struct isis_area *area,
+ const char *lsp_id); /* currently unused */
+void isis_notif_lsp_exceed_max(const struct isis_area *area,
+ const char *lsp_id);
+void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
+ uint8_t max_area_addrs,
+ const char *raw_pdu);
+void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
+ const char *raw_pdu);
+void isis_notif_authentication_failure(const struct isis_circuit *circuit,
+ const char *raw_pdu);
+void isis_notif_adj_state_change(const struct isis_adjacency *adj,
+ int new_state, const char *reason);
+void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
+ const char *reason, const char *raw_pdu);
+void isis_notif_area_mismatch(const struct isis_circuit *circuit,
+ const char *raw_pdu);
+void isis_notif_lsp_received(const struct isis_circuit *circuit,
+ const char *lsp_id, uint32_t seqno,
+ uint32_t timestamp, const char *sys_id);
+void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id,
+ uint32_t seqno, uint32_t timestamp);
+void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
+ uint8_t rcv_id_len, const char *raw_pdu);
+void isis_notif_version_skew(const struct isis_circuit *circuit,
+ uint8_t version, const char *raw_pdu);
+void isis_notif_lsp_error(const struct isis_circuit *circuit,
+ const char *lsp_id, const char *raw_pdu,
+ uint32_t offset, uint8_t tlv_type);
+void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
+ const char *lsp_id);
+void isis_notif_own_lsp_purge(const struct isis_circuit *circuit,
+ const char *lsp_id);
+
+#endif /* ISISD_ISIS_NB_H_ */
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
new file mode 100644
index 0000000000..820cfaa426
--- /dev/null
+++ b/isisd/isis_nb_config.c
@@ -0,0 +1,2236 @@
+/*
+ * Copyright (C) 2001,2002 Sampo Saaristo
+ * Tampere University of Technology
+ * Institute of Communications Engineering
+ * Copyright (C) 2018 Volta Networks
+ * Emanuele Di Pascale
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "northbound.h"
+#include "linklist.h"
+#include "log.h"
+#include "bfd.h"
+#include "spf_backoff.h"
+#include "lib_errors.h"
+#include "vrf.h"
+
+#include "isisd/isisd.h"
+#include "isisd/isis_nb.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_bfd.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_dynhn.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_te.h"
+#include "isisd/isis_memory.h"
+#include "isisd/isis_mt.h"
+#include "isisd/isis_redist.h"
+
+/*
+ * XPath: /frr-isisd:isis/instance
+ */
+int isis_instance_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ const char *area_tag;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area_tag = yang_dnode_get_string(dnode, "./area-tag");
+ area = isis_area_lookup(area_tag);
+ if (area)
+ return NB_ERR_INCONSISTENCY;
+
+ area = isis_area_create(area_tag);
+ /* save area in dnode to avoid looking it up all the time */
+ nb_running_set_entry(dnode, area);
+
+ return NB_OK;
+}
+
+int isis_instance_destroy(enum nb_event event, const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_unset_entry(dnode);
+ isis_area_destroy(area->area_tag);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/is-type
+ */
+int isis_instance_is_type_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, NULL);
+ isis_area_is_type_set(area, type);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/area-address
+ */
+int isis_instance_area_address_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ struct area_addr addr, *addrr = NULL, *addrp = NULL;
+ struct listnode *node;
+ uint8_t buff[255];
+ const char *net_title = yang_dnode_get_string(dnode, NULL);
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ addr.addr_len = dotformat2buff(buff, net_title);
+ memcpy(addr.area_addr, buff, addr.addr_len);
+ if (addr.area_addr[addr.addr_len - 1] != 0) {
+ flog_warn(
+ EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "nsel byte (last byte) in area address must be 0");
+ return NB_ERR_VALIDATION;
+ }
+ if (isis->sysid_set) {
+ /* Check that the SystemID portions match */
+ if (memcmp(isis->sysid, GETSYSID((&addr)),
+ ISIS_SYS_ID_LEN)) {
+ flog_warn(
+ EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "System ID must not change when defining additional area addresses");
+ return NB_ERR_VALIDATION;
+ }
+ }
+ break;
+ case NB_EV_PREPARE:
+ addrr = XMALLOC(MTYPE_ISIS_AREA_ADDR, sizeof(struct area_addr));
+ addrr->addr_len = dotformat2buff(buff, net_title);
+ memcpy(addrr->area_addr, buff, addrr->addr_len);
+ resource->ptr = addrr;
+ break;
+ case NB_EV_ABORT:
+ XFREE(MTYPE_ISIS_AREA_ADDR, resource->ptr);
+ break;
+ case NB_EV_APPLY:
+ area = nb_running_get_entry(dnode, NULL, true);
+ addrr = resource->ptr;
+
+ if (isis->sysid_set == 0) {
+ /*
+ * First area address - get the SystemID for this router
+ */
+ memcpy(isis->sysid, GETSYSID(addrr), ISIS_SYS_ID_LEN);
+ isis->sysid_set = 1;
+ } else {
+ /* check that we don't already have this address */
+ for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node,
+ addrp)) {
+ if ((addrp->addr_len + ISIS_SYS_ID_LEN
+ + ISIS_NSEL_LEN)
+ != (addrr->addr_len))
+ continue;
+ if (!memcmp(addrp->area_addr, addrr->area_addr,
+ addrr->addr_len)) {
+ XFREE(MTYPE_ISIS_AREA_ADDR, addrr);
+ return NB_OK; /* silent fail */
+ }
+ }
+ }
+
+ /*Forget the systemID part of the address */
+ addrr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN);
+ assert(area->area_addrs); /* to silence scan-build sillyness */
+ listnode_add(area->area_addrs, addrr);
+
+ /* only now we can safely generate our LSPs for this area */
+ if (listcount(area->area_addrs) > 0) {
+ if (area->is_type & IS_LEVEL_1)
+ lsp_generate(area, IS_LEVEL_1);
+ if (area->is_type & IS_LEVEL_2)
+ lsp_generate(area, IS_LEVEL_2);
+ }
+ break;
+ }
+
+ return NB_OK;
+}
+
+int isis_instance_area_address_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct area_addr addr, *addrp = NULL;
+ struct listnode *node;
+ uint8_t buff[255];
+ struct isis_area *area;
+ const char *net_title;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ net_title = yang_dnode_get_string(dnode, NULL);
+ addr.addr_len = dotformat2buff(buff, net_title);
+ memcpy(addr.area_addr, buff, (int)addr.addr_len);
+ area = nb_running_get_entry(dnode, NULL, true);
+ for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node, addrp)) {
+ if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len
+ && !memcmp(addrp->area_addr, addr.area_addr, addr.addr_len))
+ break;
+ }
+ if (!addrp)
+ return NB_ERR_INCONSISTENCY;
+
+ listnode_delete(area->area_addrs, addrp);
+ XFREE(MTYPE_ISIS_AREA_ADDR, addrp);
+ /*
+ * Last area address - reset the SystemID for this router
+ */
+ if (listcount(area->area_addrs) == 0) {
+ memset(isis->sysid, 0, ISIS_SYS_ID_LEN);
+ isis->sysid_set = 0;
+ if (isis->debugs & DEBUG_EVENTS)
+ zlog_debug("Router has no SystemID");
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/dynamic-hostname
+ */
+int isis_instance_dynamic_hostname_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ isis_area_dynhostname_set(area, yang_dnode_get_bool(dnode, NULL));
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/attached
+ */
+int isis_instance_attached_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ bool attached;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ attached = yang_dnode_get_bool(dnode, NULL);
+ isis_area_attached_bit_set(area, attached);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/overload
+ */
+int isis_instance_overload_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ bool overload;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ overload = yang_dnode_get_bool(dnode, NULL);
+ isis_area_overload_bit_set(area, overload);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/metric-style
+ */
+int isis_instance_metric_style_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ bool old_metric, new_metric;
+ enum isis_metric_style metric_style = yang_dnode_get_enum(dnode, NULL);
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ old_metric = (metric_style == ISIS_WIDE_METRIC) ? false : true;
+ new_metric = (metric_style == ISIS_NARROW_METRIC) ? false : true;
+ isis_area_metricstyle_set(area, old_metric, new_metric);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/purge-originator
+ */
+int isis_instance_purge_originator_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ area->purge_originator = yang_dnode_get_bool(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/lsp/mtu
+ */
+int isis_instance_lsp_mtu_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ uint16_t lsp_mtu = yang_dnode_get_uint16(dnode, NULL);
+ struct isis_area *area;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ area = nb_running_get_entry(dnode, NULL, false);
+ if (!area)
+ break;
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
+ if (circuit->state != C_STATE_INIT
+ && circuit->state != C_STATE_UP)
+ continue;
+ if (lsp_mtu > isis_circuit_pdu_size(circuit)) {
+ flog_warn(
+ EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "ISIS area contains circuit %s, which has a maximum PDU size of %zu",
+ circuit->interface->name,
+ isis_circuit_pdu_size(circuit));
+ return NB_ERR_VALIDATION;
+ }
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ area = nb_running_get_entry(dnode, NULL, true);
+ isis_area_lsp_mtu_set(area, lsp_mtu);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/lsp/refresh-interval/level-1
+ */
+int isis_instance_lsp_refresh_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ uint16_t refr_int;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ refr_int = yang_dnode_get_uint16(dnode, NULL);
+ area = nb_running_get_entry(dnode, NULL, true);
+ isis_area_lsp_refresh_set(area, IS_LEVEL_1, refr_int);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/lsp/refresh-interval/level-2
+ */
+int isis_instance_lsp_refresh_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ uint16_t refr_int;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ refr_int = yang_dnode_get_uint16(dnode, NULL);
+ area = nb_running_get_entry(dnode, NULL, true);
+ isis_area_lsp_refresh_set(area, IS_LEVEL_2, refr_int);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/lsp/maximum-lifetime/level-1
+ */
+int isis_instance_lsp_maximum_lifetime_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ uint16_t max_lt;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ max_lt = yang_dnode_get_uint16(dnode, NULL);
+ area = nb_running_get_entry(dnode, NULL, true);
+ isis_area_max_lsp_lifetime_set(area, IS_LEVEL_1, max_lt);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/lsp/maximum-lifetime/level-2
+ */
+int isis_instance_lsp_maximum_lifetime_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ uint16_t max_lt;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ max_lt = yang_dnode_get_uint16(dnode, NULL);
+ area = nb_running_get_entry(dnode, NULL, true);
+ isis_area_max_lsp_lifetime_set(area, IS_LEVEL_2, max_lt);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/lsp/generation-interval/level-1
+ */
+int isis_instance_lsp_generation_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ uint16_t gen_int;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ gen_int = yang_dnode_get_uint16(dnode, NULL);
+ area = nb_running_get_entry(dnode, NULL, true);
+ area->lsp_gen_interval[0] = gen_int;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/lsp/generation-interval/level-2
+ */
+int isis_instance_lsp_generation_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ uint16_t gen_int;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ gen_int = yang_dnode_get_uint16(dnode, NULL);
+ area = nb_running_get_entry(dnode, NULL, true);
+ area->lsp_gen_interval[1] = gen_int;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay
+ */
+void ietf_backoff_delay_apply_finish(const struct lyd_node *dnode)
+{
+ long init_delay = yang_dnode_get_uint16(dnode, "./init-delay");
+ long short_delay = yang_dnode_get_uint16(dnode, "./short-delay");
+ long long_delay = yang_dnode_get_uint16(dnode, "./long-delay");
+ long holddown = yang_dnode_get_uint16(dnode, "./hold-down");
+ long timetolearn = yang_dnode_get_uint16(dnode, "./time-to-learn");
+ struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
+ size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS Lx");
+ char *buf = XCALLOC(MTYPE_TMP, bufsiz);
+
+ snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag);
+ spf_backoff_free(area->spf_delay_ietf[0]);
+ area->spf_delay_ietf[0] =
+ spf_backoff_new(master, buf, init_delay, short_delay,
+ long_delay, holddown, timetolearn);
+
+ snprintf(buf, bufsiz, "IS-IS %s L2", area->area_tag);
+ spf_backoff_free(area->spf_delay_ietf[1]);
+ area->spf_delay_ietf[1] =
+ spf_backoff_new(master, buf, init_delay, short_delay,
+ long_delay, holddown, timetolearn);
+
+ XFREE(MTYPE_TMP, buf);
+}
+
+int isis_instance_spf_ietf_backoff_delay_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* All the work is done in the apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_spf_ietf_backoff_delay_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ spf_backoff_free(area->spf_delay_ietf[0]);
+ spf_backoff_free(area->spf_delay_ietf[1]);
+ area->spf_delay_ietf[0] = NULL;
+ area->spf_delay_ietf[1] = NULL;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/init-delay
+ */
+int isis_instance_spf_ietf_backoff_delay_init_delay_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* All the work is done in the apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/short-delay
+ */
+int isis_instance_spf_ietf_backoff_delay_short_delay_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* All the work is done in the apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/long-delay
+ */
+int isis_instance_spf_ietf_backoff_delay_long_delay_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* All the work is done in the apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/hold-down
+ */
+int isis_instance_spf_ietf_backoff_delay_hold_down_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* All the work is done in the apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/time-to-learn
+ */
+int isis_instance_spf_ietf_backoff_delay_time_to_learn_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* All the work is done in the apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/minimum-interval/level-1
+ */
+int isis_instance_spf_minimum_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ area->min_spf_interval[0] = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/spf/minimum-interval/level-2
+ */
+int isis_instance_spf_minimum_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ area->min_spf_interval[1] = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/area-password
+ */
+void area_password_apply_finish(const struct lyd_node *dnode)
+{
+ const char *password = yang_dnode_get_string(dnode, "./password");
+ struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
+ int pass_type = yang_dnode_get_enum(dnode, "./password-type");
+ uint8_t snp_auth = yang_dnode_get_enum(dnode, "./authenticate-snp");
+
+ switch (pass_type) {
+ case ISIS_PASSWD_TYPE_CLEARTXT:
+ isis_area_passwd_cleartext_set(area, IS_LEVEL_1, password,
+ snp_auth);
+ break;
+ case ISIS_PASSWD_TYPE_HMAC_MD5:
+ isis_area_passwd_hmac_md5_set(area, IS_LEVEL_1, password,
+ snp_auth);
+ break;
+ }
+}
+
+int isis_instance_area_password_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* actual setting is done in apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_area_password_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ isis_area_passwd_unset(area, IS_LEVEL_1);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/area-password/password
+ */
+int isis_instance_area_password_password_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* actual setting is done in apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/area-password/password-type
+ */
+int isis_instance_area_password_password_type_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* actual setting is done in apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/area-password/authenticate-snp
+ */
+int isis_instance_area_password_authenticate_snp_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* actual setting is done in apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/domain-password
+ */
+void domain_password_apply_finish(const struct lyd_node *dnode)
+{
+ const char *password = yang_dnode_get_string(dnode, "./password");
+ struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
+ int pass_type = yang_dnode_get_enum(dnode, "./password-type");
+ uint8_t snp_auth = yang_dnode_get_enum(dnode, "./authenticate-snp");
+
+ switch (pass_type) {
+ case ISIS_PASSWD_TYPE_CLEARTXT:
+ isis_area_passwd_cleartext_set(area, IS_LEVEL_2, password,
+ snp_auth);
+ break;
+ case ISIS_PASSWD_TYPE_HMAC_MD5:
+ isis_area_passwd_hmac_md5_set(area, IS_LEVEL_2, password,
+ snp_auth);
+ break;
+ }
+}
+
+int isis_instance_domain_password_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* actual setting is done in apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_domain_password_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ isis_area_passwd_unset(area, IS_LEVEL_2);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/domain-password/password
+ */
+int isis_instance_domain_password_password_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* actual setting is done in apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/domain-password/password-type
+ */
+int isis_instance_domain_password_password_type_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* actual setting is done in apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/domain-password/authenticate-snp
+ */
+int isis_instance_domain_password_authenticate_snp_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* actual setting is done in apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4
+ */
+void default_info_origin_apply_finish(const struct lyd_node *dnode, int family)
+{
+ int originate_type = DEFAULT_ORIGINATE;
+ unsigned long metric = 0;
+ const char *routemap = NULL;
+ struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
+ int level = yang_dnode_get_enum(dnode, "./level");
+
+ if (yang_dnode_get_bool(dnode, "./always")) {
+ originate_type = DEFAULT_ORIGINATE_ALWAYS;
+ } else if (family == AF_INET6) {
+ zlog_warn(
+ "%s: Zebra doesn't implement default-originate for IPv6 yet, so use with care or use default-originate always.",
+ __func__);
+ }
+
+ if (yang_dnode_exists(dnode, "./metric"))
+ metric = yang_dnode_get_uint32(dnode, "./metric");
+ if (yang_dnode_exists(dnode, "./route-map"))
+ routemap = yang_dnode_get_string(dnode, "./route-map");
+
+ isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap,
+ originate_type);
+}
+
+void default_info_origin_ipv4_apply_finish(const struct lyd_node *dnode)
+{
+ default_info_origin_apply_finish(dnode, AF_INET);
+}
+
+void default_info_origin_ipv6_apply_finish(const struct lyd_node *dnode)
+{
+ default_info_origin_apply_finish(dnode, AF_INET6);
+}
+
+int isis_instance_default_information_originate_ipv4_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_default_information_originate_ipv4_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+ int level;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ level = yang_dnode_get_enum(dnode, "./level");
+ isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/always
+ */
+int isis_instance_default_information_originate_ipv4_always_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/route-map
+ */
+int isis_instance_default_information_originate_ipv4_route_map_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_default_information_originate_ipv4_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/metric
+ */
+int isis_instance_default_information_originate_ipv4_metric_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6
+ */
+int isis_instance_default_information_originate_ipv6_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_default_information_originate_ipv6_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+ int level;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ level = yang_dnode_get_enum(dnode, "./level");
+ isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/always
+ */
+int isis_instance_default_information_originate_ipv6_always_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/route-map
+ */
+int isis_instance_default_information_originate_ipv6_route_map_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_default_information_originate_ipv6_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/metric
+ */
+int isis_instance_default_information_originate_ipv6_metric_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by default_info_origin_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv4
+ */
+void redistribute_apply_finish(const struct lyd_node *dnode, int family)
+{
+ assert(family == AF_INET || family == AF_INET6);
+ int type, level;
+ unsigned long metric = 0;
+ const char *routemap = NULL;
+ struct isis_area *area;
+
+ type = yang_dnode_get_enum(dnode, "./protocol");
+ level = yang_dnode_get_enum(dnode, "./level");
+ area = nb_running_get_entry(dnode, NULL, true);
+
+ if (yang_dnode_exists(dnode, "./metric"))
+ metric = yang_dnode_get_uint32(dnode, "./metric");
+ if (yang_dnode_exists(dnode, "./route-map"))
+ routemap = yang_dnode_get_string(dnode, "./route-map");
+
+ isis_redist_set(area, level, family, type, metric, routemap, 0);
+}
+
+void redistribute_ipv4_apply_finish(const struct lyd_node *dnode)
+{
+ redistribute_apply_finish(dnode, AF_INET);
+}
+
+void redistribute_ipv6_apply_finish(const struct lyd_node *dnode)
+{
+ redistribute_apply_finish(dnode, AF_INET6);
+}
+
+int isis_instance_redistribute_ipv4_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_redistribute_ipv4_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+ int level, type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ level = yang_dnode_get_enum(dnode, "./level");
+ type = yang_dnode_get_enum(dnode, "./protocol");
+ isis_redist_unset(area, level, AF_INET, type);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv4/route-map
+ */
+int isis_instance_redistribute_ipv4_route_map_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_redistribute_ipv4_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv4/metric
+ */
+int isis_instance_redistribute_ipv4_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv6
+ */
+int isis_instance_redistribute_ipv6_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_redistribute_ipv6_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+ int level, type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ level = yang_dnode_get_enum(dnode, "./level");
+ type = yang_dnode_get_enum(dnode, "./protocol");
+ isis_redist_unset(area, level, AF_INET6, type);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv6/route-map
+ */
+int isis_instance_redistribute_ipv6_route_map_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+int isis_instance_redistribute_ipv6_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv6/metric
+ */
+int isis_instance_redistribute_ipv6_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast
+ */
+static int isis_multi_topology_common(enum nb_event event,
+ const struct lyd_node *dnode,
+ const char *topology, bool create)
+{
+ struct isis_area *area;
+ struct isis_area_mt_setting *setting;
+ uint16_t mtid = isis_str2mtid(topology);
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ if (mtid == (uint16_t)-1) {
+ flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "Unknown topology %s", topology);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ area = nb_running_get_entry(dnode, NULL, true);
+ setting = area_get_mt_setting(area, mtid);
+ setting->enabled = create;
+ lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+ break;
+ }
+
+ return NB_OK;
+}
+
+static int isis_multi_topology_overload_common(enum nb_event event,
+ const struct lyd_node *dnode,
+ const char *topology)
+{
+ struct isis_area *area;
+ struct isis_area_mt_setting *setting;
+ uint16_t mtid = isis_str2mtid(topology);
+
+ /* validation is done in isis_multi_topology_common */
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ setting = area_get_mt_setting(area, mtid);
+ setting->overload = yang_dnode_get_bool(dnode, NULL);
+ if (setting->enabled)
+ lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0);
+
+ return NB_OK;
+}
+
+int isis_instance_multi_topology_ipv4_multicast_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_common(event, dnode, "ipv4-multicast", true);
+}
+
+int isis_instance_multi_topology_ipv4_multicast_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return isis_multi_topology_common(event, dnode, "ipv4-multicast",
+ false);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast/overload
+ */
+int isis_instance_multi_topology_ipv4_multicast_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_overload_common(event, dnode,
+ "ipv4-multicast");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-management
+ */
+int isis_instance_multi_topology_ipv4_management_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_common(event, dnode, "ipv4-mgmt", true);
+}
+
+int isis_instance_multi_topology_ipv4_management_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return isis_multi_topology_common(event, dnode, "ipv4-mgmt", false);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-management/overload
+ */
+int isis_instance_multi_topology_ipv4_management_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_overload_common(event, dnode, "ipv4-mgmt");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-unicast
+ */
+int isis_instance_multi_topology_ipv6_unicast_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_common(event, dnode, "ipv6-unicast", true);
+}
+
+int isis_instance_multi_topology_ipv6_unicast_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return isis_multi_topology_common(event, dnode, "ipv6-unicast", false);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-unicast/overload
+ */
+int isis_instance_multi_topology_ipv6_unicast_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_overload_common(event, dnode,
+ "ipv6-unicast");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-multicast
+ */
+int isis_instance_multi_topology_ipv6_multicast_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_common(event, dnode, "ipv6-multicast", true);
+}
+
+int isis_instance_multi_topology_ipv6_multicast_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return isis_multi_topology_common(event, dnode, "ipv6-multicast",
+ false);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-multicast/overload
+ */
+int isis_instance_multi_topology_ipv6_multicast_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_overload_common(event, dnode,
+ "ipv6-multicast");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-management
+ */
+int isis_instance_multi_topology_ipv6_management_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_common(event, dnode, "ipv6-mgmt", true);
+}
+
+int isis_instance_multi_topology_ipv6_management_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return isis_multi_topology_common(event, dnode, "ipv6-mgmt", false);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-management/overload
+ */
+int isis_instance_multi_topology_ipv6_management_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_overload_common(event, dnode, "ipv6-mgmt");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-dstsrc
+ */
+int isis_instance_multi_topology_ipv6_dstsrc_create(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_common(event, dnode, "ipv6-dstsrc", true);
+}
+
+int isis_instance_multi_topology_ipv6_dstsrc_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ return isis_multi_topology_common(event, dnode, "ipv6-dstsrc", false);
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-dstsrc/overload
+ */
+int isis_instance_multi_topology_ipv6_dstsrc_overload_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return isis_multi_topology_overload_common(event, dnode, "ipv6-dstsrc");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/log-adjacency-changes
+ */
+int isis_instance_log_adjacency_changes_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ bool log = yang_dnode_get_bool(dnode, NULL);
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ area->log_adj_changes = log ? 1 : 0;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/mpls-te
+ */
+int isis_instance_mpls_te_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct listnode *node;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ if (area->mta == NULL) {
+
+ struct mpls_te_area *new;
+
+ zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering",
+ area->area_tag);
+
+ new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area));
+
+ /* Initialize MPLS_TE structure */
+ new->status = enable;
+ new->level = 0;
+ new->inter_as = off;
+ new->interas_areaid.s_addr = 0;
+ new->router_id.s_addr = 0;
+
+ area->mta = new;
+ } else {
+ area->mta->status = enable;
+ }
+
+ /* Update Extended TLVs according to Interface link parameters */
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ isis_link_params_update(circuit, circuit->interface);
+
+ /* Reoriginate STD_TE & GMPLS circuits */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+int isis_instance_mpls_te_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct listnode *node;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ if (IS_MPLS_TE(area->mta))
+ area->mta->status = disable;
+ else
+ return NB_OK;
+
+ /* Flush LSP if circuit engage */
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
+ if (!IS_EXT_TE(circuit->ext))
+ continue;
+
+ /* disable MPLS_TE Circuit keeping SR one's */
+ if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID))
+ circuit->ext->status = EXT_ADJ_SID;
+ else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID))
+ circuit->ext->status = EXT_LAN_ADJ_SID;
+ else
+ circuit->ext->status = 0;
+ }
+
+ /* Reoriginate STD_TE & GMPLS circuits */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering",
+ area->area_tag);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/mpls-te/router-address
+ */
+int isis_instance_mpls_te_router_address_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct in_addr value;
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ /* only proceed if MPLS-TE is enabled */
+ if (!IS_MPLS_TE(area->mta))
+ return NB_OK;
+
+ /* Update Area Router ID */
+ yang_dnode_get_ipv4(&value, dnode, NULL);
+ area->mta->router_id.s_addr = value.s_addr;
+
+ /* And re-schedule LSP update */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+int isis_instance_mpls_te_router_address_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct isis_area *area;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(dnode, NULL, true);
+ /* only proceed if MPLS-TE is enabled */
+ if (!IS_MPLS_TE(area->mta))
+ return NB_OK;
+
+ /* Reset Area Router ID */
+ area->mta->router_id.s_addr = INADDR_ANY;
+
+ /* And re-schedule LSP update */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis
+ */
+int lib_interface_isis_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_area *area;
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ const char *area_tag = yang_dnode_get_string(dnode, "./area-tag");
+ uint32_t min_mtu, actual_mtu;
+
+ switch (event) {
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_VALIDATE:
+ /* check if interface mtu is sufficient. If the area has not
+ * been created yet, assume default MTU for the area
+ */
+ ifp = nb_running_get_entry(dnode, NULL, false);
+ /* zebra might not know yet about the MTU - nothing we can do */
+ if (!ifp || ifp->mtu == 0)
+ break;
+ actual_mtu =
+ if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
+ area = isis_area_lookup(area_tag);
+ if (area)
+ min_mtu = area->lsp_mtu;
+ else
+#ifndef FABRICD
+ min_mtu = yang_get_default_uint16(
+ "/frr-isisd:isis/instance/lsp/mtu");
+#else
+ min_mtu = DEFAULT_LSP_MTU;
+#endif /* ifndef FABRICD */
+ if (actual_mtu < min_mtu) {
+ flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "Interface %s has MTU %" PRIu32
+ ", minimum MTU for the area is %" PRIu32 "",
+ ifp->name, actual_mtu, min_mtu);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_APPLY:
+ area = isis_area_lookup(area_tag);
+ /* The area should have already be created. We are
+ * setting the priority of the global isis area creation
+ * slightly lower, so it should be executed first, but I
+ * cannot rely on that so here I have to check.
+ */
+ if (!area) {
+ flog_err(
+ EC_LIB_NB_CB_CONFIG_APPLY,
+ "%s: attempt to create circuit for area %s before the area has been created",
+ __func__, area_tag);
+ abort();
+ }
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ circuit = isis_circuit_create(area, ifp);
+ assert(circuit
+ && (circuit->state == C_STATE_CONF
+ || circuit->state == C_STATE_UP));
+ nb_running_set_entry(dnode, circuit);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int lib_interface_isis_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_unset_entry(dnode);
+ if (!circuit)
+ return NB_ERR_INCONSISTENCY;
+ if (circuit->state == C_STATE_UP || circuit->state == C_STATE_CONF)
+ isis_csm_state_change(ISIS_DISABLE, circuit, circuit->area);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/area-tag
+ */
+int lib_interface_isis_area_tag_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ struct vrf *vrf;
+ const char *area_tag, *ifname, *vrfname;
+
+ if (event == NB_EV_VALIDATE) {
+ /* libyang doesn't like relative paths across module boundaries
+ */
+ ifname = yang_dnode_get_string(dnode->parent->parent, "./name");
+ vrfname = yang_dnode_get_string(dnode->parent->parent, "./vrf");
+ vrf = vrf_lookup_by_name(vrfname);
+ assert(vrf);
+ ifp = if_lookup_by_name(ifname, vrf->vrf_id);
+ if (!ifp)
+ return NB_OK;
+ circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list);
+ area_tag = yang_dnode_get_string(dnode, NULL);
+ if (circuit && circuit->area && circuit->area->area_tag
+ && strcmp(circuit->area->area_tag, area_tag)) {
+ flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "ISIS circuit is already defined on %s",
+ circuit->area->area_tag);
+ return NB_ERR_VALIDATION;
+ }
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type
+ */
+int lib_interface_isis_circuit_type_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ int circ_type = yang_dnode_get_enum(dnode, NULL);
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ struct vrf *vrf;
+ const char *ifname, *vrfname;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ /* libyang doesn't like relative paths across module boundaries
+ */
+ ifname = yang_dnode_get_string(dnode->parent->parent, "./name");
+ vrfname = yang_dnode_get_string(dnode->parent->parent, "./vrf");
+ vrf = vrf_lookup_by_name(vrfname);
+ assert(vrf);
+ ifp = if_lookup_by_name(ifname, vrf->vrf_id);
+ if (!ifp)
+ break;
+ circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list);
+ if (circuit && circuit->state == C_STATE_UP
+ && circuit->area->is_type != IS_LEVEL_1_AND_2
+ && circuit->area->is_type != circ_type) {
+ flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "Invalid circuit level for area %s",
+ circuit->area->area_tag);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ isis_circuit_is_type_set(circuit, circ_type);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv4-routing
+ */
+int lib_interface_isis_ipv4_routing_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ bool ipv4, ipv6;
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ ipv4 = yang_dnode_get_bool(dnode, NULL);
+ ipv6 = yang_dnode_get_bool(dnode, "../ipv6-routing");
+ isis_circuit_af_set(circuit, ipv4, ipv6);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing
+ */
+int lib_interface_isis_ipv6_routing_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ bool ipv4, ipv6;
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ ipv4 = yang_dnode_exists(dnode, "../ipv4-routing");
+ ipv6 = yang_dnode_get_bool(dnode, NULL);
+ isis_circuit_af_set(circuit, ipv4, ipv6);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/bfd-monitoring
+ */
+int lib_interface_isis_bfd_monitoring_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ bool bfd_monitoring;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ bfd_monitoring = yang_dnode_get_bool(dnode, NULL);
+
+ if (bfd_monitoring) {
+ isis_bfd_circuit_param_set(circuit, BFD_DEF_MIN_RX,
+ BFD_DEF_MIN_TX, BFD_DEF_DETECT_MULT,
+ true);
+ } else {
+ isis_bfd_circuit_cmd(circuit, ZEBRA_BFD_DEST_DEREGISTER);
+ bfd_info_free(&circuit->bfd_info);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1
+ */
+int lib_interface_isis_csnp_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->csnp_interval[0] = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2
+ */
+int lib_interface_isis_csnp_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->csnp_interval[1] = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1
+ */
+int lib_interface_isis_psnp_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->psnp_interval[0] = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2
+ */
+int lib_interface_isis_psnp_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->psnp_interval[1] = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/padding
+ */
+int lib_interface_isis_hello_padding_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->pad_hellos = yang_dnode_get_bool(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1
+ */
+int lib_interface_isis_hello_interval_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ uint32_t interval;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ interval = yang_dnode_get_uint32(dnode, NULL);
+ circuit->hello_interval[0] = interval;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2
+ */
+int lib_interface_isis_hello_interval_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ uint32_t interval;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ interval = yang_dnode_get_uint32(dnode, NULL);
+ circuit->hello_interval[1] = interval;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1
+ */
+int lib_interface_isis_hello_multiplier_level_1_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ uint16_t multi;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ multi = yang_dnode_get_uint16(dnode, NULL);
+ circuit->hello_multiplier[0] = multi;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2
+ */
+int lib_interface_isis_hello_multiplier_level_2_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ uint16_t multi;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ multi = yang_dnode_get_uint16(dnode, NULL);
+ circuit->hello_multiplier[1] = multi;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/metric/level-1
+ */
+int lib_interface_isis_metric_level_1_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ unsigned int met;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ met = yang_dnode_get_uint32(dnode, NULL);
+ isis_circuit_metric_set(circuit, IS_LEVEL_1, met);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/metric/level-2
+ */
+int lib_interface_isis_metric_level_2_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ unsigned int met;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ met = yang_dnode_get_uint32(dnode, NULL);
+ isis_circuit_metric_set(circuit, IS_LEVEL_2, met);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/priority/level-1
+ */
+int lib_interface_isis_priority_level_1_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->priority[0] = yang_dnode_get_uint8(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/priority/level-2
+ */
+int lib_interface_isis_priority_level_2_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->priority[1] = yang_dnode_get_uint8(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/network-type
+ */
+int lib_interface_isis_network_type_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ int net_type = yang_dnode_get_enum(dnode, NULL);
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ circuit = nb_running_get_entry(dnode, NULL, false);
+ if (!circuit)
+ break;
+ if (circuit->circ_type == CIRCUIT_T_LOOPBACK) {
+ flog_warn(
+ EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "Cannot change network type on loopback interface");
+ return NB_ERR_VALIDATION;
+ }
+ if (net_type == CIRCUIT_T_BROADCAST
+ && circuit->state == C_STATE_UP
+ && !if_is_broadcast(circuit->interface)) {
+ flog_warn(
+ EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "Cannot configure non-broadcast interface for broadcast operation");
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ isis_circuit_circ_type_set(circuit, net_type);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/passive
+ */
+int lib_interface_isis_passive_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ struct isis_area *area;
+ struct interface *ifp;
+ bool passive = yang_dnode_get_bool(dnode, NULL);
+
+ /* validation only applies if we are setting passive to false */
+ if (!passive && event == NB_EV_VALIDATE) {
+ circuit = nb_running_get_entry(dnode, NULL, false);
+ if (!circuit)
+ return NB_OK;
+ ifp = circuit->interface;
+ if (!ifp)
+ return NB_OK;
+ if (if_is_loopback(ifp)) {
+ flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "Loopback is always passive");
+ return NB_ERR_VALIDATION;
+ }
+ }
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ if (circuit->state != C_STATE_UP) {
+ circuit->is_passive = passive;
+ } else {
+ area = circuit->area;
+ isis_csm_state_change(ISIS_DISABLE, circuit, area);
+ circuit->is_passive = passive;
+ isis_csm_state_change(ISIS_ENABLE, circuit, area);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/password
+ */
+int lib_interface_isis_password_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return NB_OK;
+}
+
+int lib_interface_isis_password_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ isis_circuit_passwd_unset(circuit);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/password/password
+ */
+int lib_interface_isis_password_password_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ const char *password;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ password = yang_dnode_get_string(dnode, NULL);
+ circuit = nb_running_get_entry(dnode, NULL, true);
+
+ isis_circuit_passwd_set(circuit, circuit->passwd.type, password);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/password/password-type
+ */
+int lib_interface_isis_password_password_type_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+ uint8_t pass_type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ pass_type = yang_dnode_get_enum(dnode, NULL);
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->passwd.type = pass_type;
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/disable-three-way-handshake
+ */
+int lib_interface_isis_disable_three_way_handshake_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct isis_circuit *circuit;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ circuit->disable_threeway_adj = yang_dnode_get_bool(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-unicast
+ */
+static int lib_interface_isis_multi_topology_common(
+ enum nb_event event, const struct lyd_node *dnode, uint16_t mtid)
+{
+ struct isis_circuit *circuit;
+ bool value;
+
+ switch (event) {
+ case NB_EV_VALIDATE:
+ circuit = nb_running_get_entry(dnode, NULL, false);
+ if (circuit && circuit->area && circuit->area->oldmetric) {
+ flog_warn(
+ EC_LIB_NB_CB_CONFIG_VALIDATE,
+ "Multi topology IS-IS can only be used with wide metrics");
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ circuit = nb_running_get_entry(dnode, NULL, true);
+ value = yang_dnode_get_bool(dnode, NULL);
+ isis_circuit_mt_enabled_set(circuit, mtid, value);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int lib_interface_isis_multi_topology_ipv4_unicast_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_interface_isis_multi_topology_common(event, dnode,
+ ISIS_MT_IPV4_UNICAST);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-multicast
+ */
+int lib_interface_isis_multi_topology_ipv4_multicast_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_interface_isis_multi_topology_common(event, dnode,
+ ISIS_MT_IPV4_MULTICAST);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-management
+ */
+int lib_interface_isis_multi_topology_ipv4_management_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_interface_isis_multi_topology_common(event, dnode,
+ ISIS_MT_IPV4_MGMT);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-unicast
+ */
+int lib_interface_isis_multi_topology_ipv6_unicast_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_interface_isis_multi_topology_common(event, dnode,
+ ISIS_MT_IPV6_UNICAST);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-multicast
+ */
+int lib_interface_isis_multi_topology_ipv6_multicast_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_interface_isis_multi_topology_common(event, dnode,
+ ISIS_MT_IPV6_MULTICAST);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-management
+ */
+int lib_interface_isis_multi_topology_ipv6_management_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_interface_isis_multi_topology_common(event, dnode,
+ ISIS_MT_IPV6_MGMT);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-dstsrc
+ */
+int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ return lib_interface_isis_multi_topology_common(event, dnode,
+ ISIS_MT_IPV6_DSTSRC);
+}
diff --git a/isisd/isis_nb_notifications.c b/isisd/isis_nb_notifications.c
new file mode 100644
index 0000000000..ea33ec10ec
--- /dev/null
+++ b/isisd/isis_nb_notifications.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2018 Volta Networks
+ * Emanuele Di Pascale
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "northbound.h"
+#include "log.h"
+
+#include "isisd/isisd.h"
+#include "isisd/isis_nb.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_dynhn.h"
+#include "isisd/isis_misc.h"
+
+/*
+ * Helper functions.
+ */
+static void notif_prep_instance_hdr(const char *xpath,
+ const struct isis_area *area,
+ const char *routing_instance,
+ struct list *args)
+{
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/routing-instance", xpath);
+ data = yang_data_new_string(xpath_arg, routing_instance);
+ listnode_add(args, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/routing-protocol-name",
+ xpath);
+ data = yang_data_new_string(xpath_arg, area->area_tag);
+ listnode_add(args, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/isis-level", xpath);
+ data = yang_data_new_enum(xpath_arg, area->is_type);
+ listnode_add(args, data);
+}
+
+static void notif_prepr_iface_hdr(const char *xpath,
+ const struct isis_circuit *circuit,
+ struct list *args)
+{
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-name", xpath);
+ data = yang_data_new_string(xpath_arg, circuit->interface->name);
+ listnode_add(args, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-level", xpath);
+ data = yang_data_new_enum(xpath_arg, circuit->is_type);
+ listnode_add(args, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/extended-circuit-id", xpath);
+ /* we do not seem to have the extended version of the circuit_id */
+ data = yang_data_new_uint32(xpath_arg, (uint32_t)circuit->circuit_id);
+ listnode_add(args, data);
+}
+
+/*
+ * XPath: /frr-isisd:database-overload
+ */
+void isis_notif_db_overload(const struct isis_area *area, bool overload)
+{
+ const char *xpath = "/frr-isisd:database-overload";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/overload", xpath);
+ data = yang_data_new_enum(xpath_arg, !!overload);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:lsp-too-large
+ */
+void isis_notif_lsp_too_large(const struct isis_circuit *circuit,
+ uint32_t pdu_size, const char *lsp_id)
+{
+ const char *xpath = "/frr-isisd:lsp-too-large";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/pdu-size", xpath);
+ data = yang_data_new_uint32(xpath_arg, pdu_size);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
+ data = yang_data_new_string(xpath_arg, lsp_id);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:if-state-change
+ */
+void isis_notif_if_state_change(const struct isis_circuit *circuit, bool down)
+{
+ const char *xpath = "/frr-isisd:if-state-change";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath);
+ data = yang_data_new_enum(xpath_arg, !!down);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:corrupted-lsp-detected
+ */
+void isis_notif_corrupted_lsp(const struct isis_area *area, const char *lsp_id)
+{
+ const char *xpath = "/frr-isisd:corrupted-lsp-detected";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
+ data = yang_data_new_string(xpath_arg, lsp_id);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:attempt-to-exceed-max-sequence
+ */
+void isis_notif_lsp_exceed_max(const struct isis_area *area, const char *lsp_id)
+{
+ const char *xpath = "/frr-isisd:attempt-to-exceed-max-sequence";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
+ data = yang_data_new_string(xpath_arg, lsp_id);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:max-area-addresses-mismatch
+ */
+void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
+ uint8_t max_area_addrs,
+ const char *raw_pdu)
+{
+ const char *xpath = "/frr-isisd:max-area-addresses-mismatch";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/max-area-addresses", xpath);
+ data = yang_data_new_uint8(xpath_arg, max_area_addrs);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
+ data = yang_data_new(xpath_arg, raw_pdu);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:authentication-type-failure
+ */
+void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
+ const char *raw_pdu)
+{
+ const char *xpath = "/frr-isisd:authentication-type-failure";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
+ data = yang_data_new(xpath_arg, raw_pdu);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:authentication-failure
+ */
+void isis_notif_authentication_failure(const struct isis_circuit *circuit,
+ const char *raw_pdu)
+{
+ const char *xpath = "/frr-isisd:authentication-failure";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
+ data = yang_data_new(xpath_arg, raw_pdu);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:adjacency-state-change
+ */
+void isis_notif_adj_state_change(const struct isis_adjacency *adj,
+ int new_state, const char *reason)
+{
+ const char *xpath = "/frr-isisd:adjacency-state-change";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_circuit *circuit = adj->circuit;
+ struct isis_area *area = circuit->area;
+ struct isis_dynhn *dyn = dynhn_find_by_id(adj->sysid);
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ if (dyn) {
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/neighbor", xpath);
+ data = yang_data_new_string(xpath_arg, dyn->hostname);
+ listnode_add(arguments, data);
+ }
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/neighbor-system-id", xpath);
+ data = yang_data_new_string(xpath_arg, sysid_print(adj->sysid));
+ listnode_add(arguments, data);
+
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath);
+ data = yang_data_new_string(xpath_arg, isis_adj_yang_state(new_state));
+ listnode_add(arguments, data);
+ if (new_state == ISIS_ADJ_DOWN) {
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath);
+ data = yang_data_new_string(xpath_arg, reason);
+ listnode_add(arguments, data);
+ }
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:rejected-adjacency
+ */
+void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
+ const char *reason, const char *raw_pdu)
+{
+ const char *xpath = "/frr-isisd:rejected-adjacency";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath);
+ data = yang_data_new_string(xpath_arg, reason);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
+ data = yang_data_new(xpath_arg, raw_pdu);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:area-mismatch
+ */
+void isis_notif_area_mismatch(const struct isis_circuit *circuit,
+ const char *raw_pdu)
+{
+ const char *xpath = "/frr-isisd:area-mismatch";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
+ data = yang_data_new(xpath_arg, raw_pdu);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:lsp-received
+ */
+void isis_notif_lsp_received(const struct isis_circuit *circuit,
+ const char *lsp_id, uint32_t seqno,
+ uint32_t timestamp, const char *sys_id)
+{
+ const char *xpath = "/frr-isisd:lsp-received";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
+ data = yang_data_new_string(xpath_arg, lsp_id);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/sequence", xpath);
+ data = yang_data_new_uint32(xpath_arg, seqno);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/received-timestamp", xpath);
+ data = yang_data_new_uint32(xpath_arg, timestamp);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/neighbor-system-id", xpath);
+ data = yang_data_new_string(xpath_arg, sys_id);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:lsp-generation
+ */
+void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id,
+ uint32_t seqno, uint32_t timestamp)
+{
+ const char *xpath = "/frr-isisd:lsp-generation";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
+ data = yang_data_new_string(xpath_arg, lsp_id);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/sequence", xpath);
+ data = yang_data_new_uint32(xpath_arg, seqno);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/send-timestamp", xpath);
+ data = yang_data_new_uint32(xpath_arg, timestamp);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:id-len-mismatch
+ */
+void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
+ uint8_t rcv_id_len, const char *raw_pdu)
+{
+ const char *xpath = "/frr-isisd:id-len-mismatch";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/pdu-field-len", xpath);
+ data = yang_data_new_uint8(xpath_arg, rcv_id_len);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
+ data = yang_data_new(xpath_arg, raw_pdu);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:version-skew
+ */
+void isis_notif_version_skew(const struct isis_circuit *circuit,
+ uint8_t version, const char *raw_pdu)
+{
+ const char *xpath = "/frr-isisd:version-skew";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/protocol-version", xpath);
+ data = yang_data_new_uint8(xpath_arg, version);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
+ data = yang_data_new(xpath_arg, raw_pdu);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:lsp-error-detected
+ */
+void isis_notif_lsp_error(const struct isis_circuit *circuit,
+ const char *lsp_id, const char *raw_pdu,
+ __attribute__((unused)) uint32_t offset,
+ __attribute__((unused)) uint8_t tlv_type)
+{
+ const char *xpath = "/frr-isisd:lsp-error-detected";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
+ data = yang_data_new_string(xpath_arg, lsp_id);
+ listnode_add(arguments, data);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
+ data = yang_data_new(xpath_arg, raw_pdu);
+ listnode_add(arguments, data);
+ /* ignore offset and tlv_type which cannot be set properly */
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:sequence-number-skipped
+ */
+void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
+ const char *lsp_id)
+{
+ const char *xpath = "/frr-isisd:sequence-number-skipped";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
+ data = yang_data_new_string(xpath_arg, lsp_id);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-isisd:own-lsp-purge
+ */
+void isis_notif_own_lsp_purge(const struct isis_circuit *circuit,
+ const char *lsp_id)
+{
+ const char *xpath = "/frr-isisd:own-lsp-purge";
+ struct list *arguments = yang_data_list_new();
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+ struct isis_area *area = circuit->area;
+
+ notif_prep_instance_hdr(xpath, area, "default", arguments);
+ notif_prepr_iface_hdr(xpath, circuit, arguments);
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
+ data = yang_data_new_string(xpath_arg, lsp_id);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
diff --git a/isisd/isis_nb_state.c b/isisd/isis_nb_state.c
new file mode 100644
index 0000000000..e52d0201d5
--- /dev/null
+++ b/isisd/isis_nb_state.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2018 Volta Networks
+ * Emanuele Di Pascale
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "northbound.h"
+#include "linklist.h"
+
+#include "isisd/isisd.h"
+#include "isisd/isis_nb.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_misc.h"
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency
+ */
+const void *
+lib_interface_isis_adjacencies_adjacency_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct isis_adjacency *adj, *adj_next = NULL;
+ struct list *list;
+ struct listnode *node, *node_next;
+
+ /* Get first adjacency. */
+ if (list_entry == NULL) {
+ ifp = (struct interface *)parent_list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
+ level++) {
+ adj = listnode_head(
+ circuit->u.bc.adjdb[level - 1]);
+ if (adj)
+ break;
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ adj = circuit->u.p2p.neighbor;
+ break;
+ default:
+ adj = NULL;
+ break;
+ }
+
+ return adj;
+ }
+
+ /* Get next adjacency. */
+ adj = (struct isis_adjacency *)list_entry;
+ circuit = adj->circuit;
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ list = circuit->u.bc.adjdb[adj->level - 1];
+ node = listnode_lookup(list, adj);
+ node_next = listnextnode(node);
+ if (node_next)
+ adj_next = listgetdata(node_next);
+ else if (adj->level == ISIS_LEVEL1) {
+ /*
+ * Once we finish the L1 adjacencies, move to the L2
+ * adjacencies list.
+ */
+ list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1];
+ adj_next = listnode_head(list);
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ /* P2P circuits have at most one adjacency. */
+ default:
+ break;
+ }
+
+ return adj_next;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type
+ */
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_enum(xpath, adj->level);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid
+ */
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_string(xpath, sysid_print(adj->sysid));
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id
+ */
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_uint32(xpath, adj->circuit->circuit_id);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa
+ */
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_string(xpath, snpa_print(adj->snpa));
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer
+ */
+struct yang_data *lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_uint16(xpath, adj->hold_time);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority
+ */
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_uint8(xpath, adj->prio[adj->level - 1]);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state
+ */
+struct yang_data *
+lib_interface_isis_adjacencies_adjacency_state_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct isis_adjacency *adj = list_entry;
+
+ return yang_data_new_string(xpath, isis_adj_yang_state(adj->adj_state));
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes
+ */
+struct yang_data *lib_interface_isis_event_counters_adjacency_changes_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->adj_state_changes);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number
+ */
+struct yang_data *lib_interface_isis_event_counters_adjacency_number_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct isis_adjacency *adj;
+ struct listnode *node;
+ uint32_t total = 0;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ /*
+ * TODO: keep track of the number of adjacencies instead of calculating
+ * it on demand.
+ */
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ for (ALL_LIST_ELEMENTS_RO(
+ circuit->u.bc.adjdb[level - 1], node, adj))
+ total++;
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ adj = circuit->u.p2p.neighbor;
+ if (adj)
+ total = 1;
+ break;
+ default:
+ break;
+ }
+
+ return yang_data_new_uint32(xpath, total);
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails
+ */
+struct yang_data *
+lib_interface_isis_event_counters_init_fails_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->init_failures);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects
+ */
+struct yang_data *lib_interface_isis_event_counters_adjacency_rejects_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->rej_adjacencies);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch
+ */
+struct yang_data *lib_interface_isis_event_counters_id_len_mismatch_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->id_len_mismatches);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch
+ */
+struct yang_data *
+lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->max_area_addr_mismatches);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails
+ */
+struct yang_data *
+lib_interface_isis_event_counters_authentication_type_fails_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->auth_type_failures);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails
+ */
+struct yang_data *
+lib_interface_isis_event_counters_authentication_fails_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return NULL;
+
+ return yang_data_new_uint32(xpath, circuit->auth_failures);
+}
diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c
deleted file mode 100644
index 97b7ae4f7e..0000000000
--- a/isisd/isis_northbound.c
+++ /dev/null
@@ -1,3932 +0,0 @@
-/*
- * Copyright (C) 2001,2002 Sampo Saaristo
- * Tampere University of Technology
- * Institute of Communications Engineering
- * Copyright (C) 2018 Volta Networks
- * Emanuele Di Pascale
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-#include "northbound.h"
-#include "libfrr.h"
-#include "linklist.h"
-#include "log.h"
-#include "lib/bfd.h"
-#include "isisd/isis_bfd.h"
-#include "isisd/isis_constants.h"
-#include "isisd/isis_common.h"
-#include "isisd/isis_flags.h"
-#include "isisd/isis_circuit.h"
-#include "isisd/isisd.h"
-#include "isisd/isis_lsp.h"
-#include "isisd/isis_pdu.h"
-#include "isisd/isis_dynhn.h"
-#include "isisd/isis_misc.h"
-#include "isisd/isis_csm.h"
-#include "isisd/isis_adjacency.h"
-#include "isisd/isis_spf.h"
-#include "isisd/isis_te.h"
-#include "isisd/isis_memory.h"
-#include "isisd/isis_mt.h"
-#include "isisd/isis_cli.h"
-#include "isisd/isis_redist.h"
-#include "lib/spf_backoff.h"
-#include "lib/lib_errors.h"
-#include "lib/vrf.h"
-
-/*
- * Helper functions.
- */
-static const char *isis_yang_adj_state(enum isis_adj_state state)
-{
- switch (state) {
- case ISIS_ADJ_DOWN:
- return "down";
- case ISIS_ADJ_UP:
- return "up";
- case ISIS_ADJ_INITIALIZING:
- return "init";
- default:
- return "failed";
- }
-}
-
-/*
- * XPath: /frr-isisd:isis/instance
- */
-static int isis_instance_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- const char *area_tag;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area_tag = yang_dnode_get_string(dnode, "./area-tag");
- area = isis_area_lookup(area_tag);
- if (area)
- return NB_ERR_INCONSISTENCY;
-
- area = isis_area_create(area_tag);
- /* save area in dnode to avoid looking it up all the time */
- nb_running_set_entry(dnode, area);
-
- return NB_OK;
-}
-
-static int isis_instance_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_unset_entry(dnode);
- isis_area_destroy(area->area_tag);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/is-type
- */
-static int isis_instance_is_type_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, NULL);
- isis_area_is_type_set(area, type);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/area-address
- */
-static int isis_instance_area_address_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- struct area_addr addr, *addrr = NULL, *addrp = NULL;
- struct listnode *node;
- uint8_t buff[255];
- const char *net_title = yang_dnode_get_string(dnode, NULL);
-
- switch (event) {
- case NB_EV_VALIDATE:
- addr.addr_len = dotformat2buff(buff, net_title);
- memcpy(addr.area_addr, buff, addr.addr_len);
- if (addr.area_addr[addr.addr_len - 1] != 0) {
- flog_warn(
- EC_LIB_NB_CB_CONFIG_VALIDATE,
- "nsel byte (last byte) in area address must be 0");
- return NB_ERR_VALIDATION;
- }
- if (isis->sysid_set) {
- /* Check that the SystemID portions match */
- if (memcmp(isis->sysid, GETSYSID((&addr)),
- ISIS_SYS_ID_LEN)) {
- flog_warn(
- EC_LIB_NB_CB_CONFIG_VALIDATE,
- "System ID must not change when defining additional area addresses");
- return NB_ERR_VALIDATION;
- }
- }
- break;
- case NB_EV_PREPARE:
- addrr = XMALLOC(MTYPE_ISIS_AREA_ADDR, sizeof(struct area_addr));
- addrr->addr_len = dotformat2buff(buff, net_title);
- memcpy(addrr->area_addr, buff, addrr->addr_len);
- resource->ptr = addrr;
- break;
- case NB_EV_ABORT:
- XFREE(MTYPE_ISIS_AREA_ADDR, resource->ptr);
- break;
- case NB_EV_APPLY:
- area = nb_running_get_entry(dnode, NULL, true);
- addrr = resource->ptr;
-
- if (isis->sysid_set == 0) {
- /*
- * First area address - get the SystemID for this router
- */
- memcpy(isis->sysid, GETSYSID(addrr), ISIS_SYS_ID_LEN);
- isis->sysid_set = 1;
- } else {
- /* check that we don't already have this address */
- for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node,
- addrp)) {
- if ((addrp->addr_len + ISIS_SYS_ID_LEN
- + ISIS_NSEL_LEN)
- != (addrr->addr_len))
- continue;
- if (!memcmp(addrp->area_addr, addrr->area_addr,
- addrr->addr_len)) {
- XFREE(MTYPE_ISIS_AREA_ADDR, addrr);
- return NB_OK; /* silent fail */
- }
- }
- }
-
- /*Forget the systemID part of the address */
- addrr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN);
- assert(area->area_addrs); /* to silence scan-build sillyness */
- listnode_add(area->area_addrs, addrr);
-
- /* only now we can safely generate our LSPs for this area */
- if (listcount(area->area_addrs) > 0) {
- if (area->is_type & IS_LEVEL_1)
- lsp_generate(area, IS_LEVEL_1);
- if (area->is_type & IS_LEVEL_2)
- lsp_generate(area, IS_LEVEL_2);
- }
- break;
- }
-
- return NB_OK;
-}
-
-static int isis_instance_area_address_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct area_addr addr, *addrp = NULL;
- struct listnode *node;
- uint8_t buff[255];
- struct isis_area *area;
- const char *net_title;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- net_title = yang_dnode_get_string(dnode, NULL);
- addr.addr_len = dotformat2buff(buff, net_title);
- memcpy(addr.area_addr, buff, (int)addr.addr_len);
- area = nb_running_get_entry(dnode, NULL, true);
- for (ALL_LIST_ELEMENTS_RO(area->area_addrs, node, addrp)) {
- if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len
- && !memcmp(addrp->area_addr, addr.area_addr, addr.addr_len))
- break;
- }
- if (!addrp)
- return NB_ERR_INCONSISTENCY;
-
- listnode_delete(area->area_addrs, addrp);
- XFREE(MTYPE_ISIS_AREA_ADDR, addrp);
- /*
- * Last area address - reset the SystemID for this router
- */
- if (listcount(area->area_addrs) == 0) {
- memset(isis->sysid, 0, ISIS_SYS_ID_LEN);
- isis->sysid_set = 0;
- if (isis->debugs & DEBUG_EVENTS)
- zlog_debug("Router has no SystemID");
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/dynamic-hostname
- */
-static int isis_instance_dynamic_hostname_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- isis_area_dynhostname_set(area, yang_dnode_get_bool(dnode, NULL));
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/attached
- */
-static int isis_instance_attached_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- bool attached;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- attached = yang_dnode_get_bool(dnode, NULL);
- isis_area_attached_bit_set(area, attached);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/overload
- */
-static int isis_instance_overload_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- bool overload;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- overload = yang_dnode_get_bool(dnode, NULL);
- isis_area_overload_bit_set(area, overload);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/metric-style
- */
-static int isis_instance_metric_style_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- bool old_metric, new_metric;
- enum isis_metric_style metric_style = yang_dnode_get_enum(dnode, NULL);
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- old_metric = (metric_style == ISIS_WIDE_METRIC) ? false : true;
- new_metric = (metric_style == ISIS_NARROW_METRIC) ? false : true;
- isis_area_metricstyle_set(area, old_metric, new_metric);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/purge-originator
- */
-static int isis_instance_purge_originator_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- area->purge_originator = yang_dnode_get_bool(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/lsp/mtu
- */
-static int isis_instance_lsp_mtu_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct listnode *node;
- struct isis_circuit *circuit;
- uint16_t lsp_mtu = yang_dnode_get_uint16(dnode, NULL);
- struct isis_area *area;
-
- switch (event) {
- case NB_EV_VALIDATE:
- area = nb_running_get_entry(dnode, NULL, false);
- if (!area)
- break;
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
- if (circuit->state != C_STATE_INIT
- && circuit->state != C_STATE_UP)
- continue;
- if (lsp_mtu > isis_circuit_pdu_size(circuit)) {
- flog_warn(
- EC_LIB_NB_CB_CONFIG_VALIDATE,
- "ISIS area contains circuit %s, which has a maximum PDU size of %zu",
- circuit->interface->name,
- isis_circuit_pdu_size(circuit));
- return NB_ERR_VALIDATION;
- }
- }
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- area = nb_running_get_entry(dnode, NULL, true);
- isis_area_lsp_mtu_set(area, lsp_mtu);
- break;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/lsp/refresh-interval/level-1
- */
-static int
-isis_instance_lsp_refresh_interval_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- uint16_t refr_int;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- refr_int = yang_dnode_get_uint16(dnode, NULL);
- area = nb_running_get_entry(dnode, NULL, true);
- isis_area_lsp_refresh_set(area, IS_LEVEL_1, refr_int);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/lsp/refresh-interval/level-2
- */
-static int
-isis_instance_lsp_refresh_interval_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- uint16_t refr_int;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- refr_int = yang_dnode_get_uint16(dnode, NULL);
- area = nb_running_get_entry(dnode, NULL, true);
- isis_area_lsp_refresh_set(area, IS_LEVEL_2, refr_int);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/lsp/maximum-lifetime/level-1
- */
-static int
-isis_instance_lsp_maximum_lifetime_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- uint16_t max_lt;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- max_lt = yang_dnode_get_uint16(dnode, NULL);
- area = nb_running_get_entry(dnode, NULL, true);
- isis_area_max_lsp_lifetime_set(area, IS_LEVEL_1, max_lt);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/lsp/maximum-lifetime/level-2
- */
-static int
-isis_instance_lsp_maximum_lifetime_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- uint16_t max_lt;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- max_lt = yang_dnode_get_uint16(dnode, NULL);
- area = nb_running_get_entry(dnode, NULL, true);
- isis_area_max_lsp_lifetime_set(area, IS_LEVEL_2, max_lt);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/lsp/generation-interval/level-1
- */
-static int isis_instance_lsp_generation_interval_level_1_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- uint16_t gen_int;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- gen_int = yang_dnode_get_uint16(dnode, NULL);
- area = nb_running_get_entry(dnode, NULL, true);
- area->lsp_gen_interval[0] = gen_int;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/lsp/generation-interval/level-2
- */
-static int isis_instance_lsp_generation_interval_level_2_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- uint16_t gen_int;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- gen_int = yang_dnode_get_uint16(dnode, NULL);
- area = nb_running_get_entry(dnode, NULL, true);
- area->lsp_gen_interval[1] = gen_int;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay
- */
-static void ietf_backoff_delay_apply_finish(const struct lyd_node *dnode)
-{
- long init_delay = yang_dnode_get_uint16(dnode, "./init-delay");
- long short_delay = yang_dnode_get_uint16(dnode, "./short-delay");
- long long_delay = yang_dnode_get_uint16(dnode, "./long-delay");
- long holddown = yang_dnode_get_uint16(dnode, "./hold-down");
- long timetolearn = yang_dnode_get_uint16(dnode, "./time-to-learn");
- struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
- size_t bufsiz = strlen(area->area_tag) + sizeof("IS-IS Lx");
- char *buf = XCALLOC(MTYPE_TMP, bufsiz);
-
- snprintf(buf, bufsiz, "IS-IS %s L1", area->area_tag);
- spf_backoff_free(area->spf_delay_ietf[0]);
- area->spf_delay_ietf[0] =
- spf_backoff_new(master, buf, init_delay, short_delay,
- long_delay, holddown, timetolearn);
-
- snprintf(buf, bufsiz, "IS-IS %s L2", area->area_tag);
- spf_backoff_free(area->spf_delay_ietf[1]);
- area->spf_delay_ietf[1] =
- spf_backoff_new(master, buf, init_delay, short_delay,
- long_delay, holddown, timetolearn);
-
- XFREE(MTYPE_TMP, buf);
-}
-
-static int
-isis_instance_spf_ietf_backoff_delay_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* All the work is done in the apply_finish */
- return NB_OK;
-}
-
-static int
-isis_instance_spf_ietf_backoff_delay_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- spf_backoff_free(area->spf_delay_ietf[0]);
- spf_backoff_free(area->spf_delay_ietf[1]);
- area->spf_delay_ietf[0] = NULL;
- area->spf_delay_ietf[1] = NULL;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/init-delay
- */
-static int isis_instance_spf_ietf_backoff_delay_init_delay_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* All the work is done in the apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/short-delay
- */
-static int isis_instance_spf_ietf_backoff_delay_short_delay_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* All the work is done in the apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/long-delay
- */
-static int isis_instance_spf_ietf_backoff_delay_long_delay_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* All the work is done in the apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/hold-down
- */
-static int isis_instance_spf_ietf_backoff_delay_hold_down_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* All the work is done in the apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/spf/ietf-backoff-delay/time-to-learn
- */
-static int isis_instance_spf_ietf_backoff_delay_time_to_learn_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* All the work is done in the apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/spf/minimum-interval/level-1
- */
-static int
-isis_instance_spf_minimum_interval_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- area->min_spf_interval[0] = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/spf/minimum-interval/level-2
- */
-static int
-isis_instance_spf_minimum_interval_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- area->min_spf_interval[1] = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/area-password
- */
-static void area_password_apply_finish(const struct lyd_node *dnode)
-{
- const char *password = yang_dnode_get_string(dnode, "./password");
- struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
- int pass_type = yang_dnode_get_enum(dnode, "./password-type");
- uint8_t snp_auth = yang_dnode_get_enum(dnode, "./authenticate-snp");
-
- switch (pass_type) {
- case ISIS_PASSWD_TYPE_CLEARTXT:
- isis_area_passwd_cleartext_set(area, IS_LEVEL_1, password,
- snp_auth);
- break;
- case ISIS_PASSWD_TYPE_HMAC_MD5:
- isis_area_passwd_hmac_md5_set(area, IS_LEVEL_1, password,
- snp_auth);
- break;
- }
-}
-
-static int isis_instance_area_password_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* actual setting is done in apply_finish */
- return NB_OK;
-}
-
-static int isis_instance_area_password_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- isis_area_passwd_unset(area, IS_LEVEL_1);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/area-password/password
- */
-static int
-isis_instance_area_password_password_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* actual setting is done in apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/area-password/password-type
- */
-static int
-isis_instance_area_password_password_type_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* actual setting is done in apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/area-password/authenticate-snp
- */
-static int isis_instance_area_password_authenticate_snp_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* actual setting is done in apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/domain-password
- */
-static void domain_password_apply_finish(const struct lyd_node *dnode)
-{
- const char *password = yang_dnode_get_string(dnode, "./password");
- struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
- int pass_type = yang_dnode_get_enum(dnode, "./password-type");
- uint8_t snp_auth = yang_dnode_get_enum(dnode, "./authenticate-snp");
-
- switch (pass_type) {
- case ISIS_PASSWD_TYPE_CLEARTXT:
- isis_area_passwd_cleartext_set(area, IS_LEVEL_2, password,
- snp_auth);
- break;
- case ISIS_PASSWD_TYPE_HMAC_MD5:
- isis_area_passwd_hmac_md5_set(area, IS_LEVEL_2, password,
- snp_auth);
- break;
- }
-}
-
-static int isis_instance_domain_password_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* actual setting is done in apply_finish */
- return NB_OK;
-}
-
-static int isis_instance_domain_password_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- isis_area_passwd_unset(area, IS_LEVEL_2);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/domain-password/password
- */
-static int
-isis_instance_domain_password_password_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* actual setting is done in apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/domain-password/password-type
- */
-static int
-isis_instance_domain_password_password_type_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* actual setting is done in apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/domain-password/authenticate-snp
- */
-static int isis_instance_domain_password_authenticate_snp_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* actual setting is done in apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4
- */
-static void default_info_origin_apply_finish(const struct lyd_node *dnode,
- int family)
-{
- int originate_type = DEFAULT_ORIGINATE;
- unsigned long metric = 0;
- const char *routemap = NULL;
- struct isis_area *area = nb_running_get_entry(dnode, NULL, true);
- int level = yang_dnode_get_enum(dnode, "./level");
-
- if (yang_dnode_get_bool(dnode, "./always")) {
- originate_type = DEFAULT_ORIGINATE_ALWAYS;
- } else if (family == AF_INET6) {
- zlog_warn(
- "%s: Zebra doesn't implement default-originate for IPv6 yet, so use with care or use default-originate always.",
- __func__);
- }
-
- if (yang_dnode_exists(dnode, "./metric"))
- metric = yang_dnode_get_uint32(dnode, "./metric");
- if (yang_dnode_exists(dnode, "./route-map"))
- routemap = yang_dnode_get_string(dnode, "./route-map");
-
- isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap,
- originate_type);
-}
-
-static void default_info_origin_ipv4_apply_finish(const struct lyd_node *dnode)
-{
- default_info_origin_apply_finish(dnode, AF_INET);
-}
-
-static void default_info_origin_ipv6_apply_finish(const struct lyd_node *dnode)
-{
- default_info_origin_apply_finish(dnode, AF_INET6);
-}
-
-static int isis_instance_default_information_originate_ipv4_create(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-static int isis_instance_default_information_originate_ipv4_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- struct isis_area *area;
- int level;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- level = yang_dnode_get_enum(dnode, "./level");
- isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/always
- */
-static int isis_instance_default_information_originate_ipv4_always_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/route-map
- */
-static int isis_instance_default_information_originate_ipv4_route_map_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-static int isis_instance_default_information_originate_ipv4_route_map_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/default-information-originate/ipv4/metric
- */
-static int isis_instance_default_information_originate_ipv4_metric_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6
- */
-static int isis_instance_default_information_originate_ipv6_create(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-static int isis_instance_default_information_originate_ipv6_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- struct isis_area *area;
- int level;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- level = yang_dnode_get_enum(dnode, "./level");
- isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/always
- */
-static int isis_instance_default_information_originate_ipv6_always_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/route-map
- */
-static int isis_instance_default_information_originate_ipv6_route_map_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-static int isis_instance_default_information_originate_ipv6_route_map_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/default-information-originate/ipv6/metric
- */
-static int isis_instance_default_information_originate_ipv6_metric_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by default_info_origin_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/redistribute/ipv4
- */
-static void redistribute_apply_finish(const struct lyd_node *dnode, int family)
-{
- assert(family == AF_INET || family == AF_INET6);
- int type, level;
- unsigned long metric = 0;
- const char *routemap = NULL;
- struct isis_area *area;
-
- type = yang_dnode_get_enum(dnode, "./protocol");
- level = yang_dnode_get_enum(dnode, "./level");
- area = nb_running_get_entry(dnode, NULL, true);
-
- if (yang_dnode_exists(dnode, "./metric"))
- metric = yang_dnode_get_uint32(dnode, "./metric");
- if (yang_dnode_exists(dnode, "./route-map"))
- routemap = yang_dnode_get_string(dnode, "./route-map");
-
- isis_redist_set(area, level, family, type, metric, routemap, 0);
-}
-
-static void redistribute_ipv4_apply_finish(const struct lyd_node *dnode)
-{
- redistribute_apply_finish(dnode, AF_INET);
-}
-
-static void redistribute_ipv6_apply_finish(const struct lyd_node *dnode)
-{
- redistribute_apply_finish(dnode, AF_INET6);
-}
-
-static int isis_instance_redistribute_ipv4_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
-static int isis_instance_redistribute_ipv4_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_area *area;
- int level, type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- level = yang_dnode_get_enum(dnode, "./level");
- type = yang_dnode_get_enum(dnode, "./protocol");
- isis_redist_unset(area, level, AF_INET, type);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/redistribute/ipv4/route-map
- */
-static int
-isis_instance_redistribute_ipv4_route_map_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
-static int
-isis_instance_redistribute_ipv4_route_map_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/redistribute/ipv4/metric
- */
-static int
-isis_instance_redistribute_ipv4_metric_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/redistribute/ipv6
- */
-static int isis_instance_redistribute_ipv6_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
-static int isis_instance_redistribute_ipv6_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_area *area;
- int level, type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- level = yang_dnode_get_enum(dnode, "./level");
- type = yang_dnode_get_enum(dnode, "./protocol");
- isis_redist_unset(area, level, AF_INET6, type);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/redistribute/ipv6/route-map
- */
-static int
-isis_instance_redistribute_ipv6_route_map_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
-static int
-isis_instance_redistribute_ipv6_route_map_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/redistribute/ipv6/metric
- */
-static int
-isis_instance_redistribute_ipv6_metric_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- /* It's all done by redistribute_apply_finish */
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast
- */
-static int isis_multi_topology_common(enum nb_event event,
- const struct lyd_node *dnode,
- const char *topology, bool create)
-{
- struct isis_area *area;
- struct isis_area_mt_setting *setting;
- uint16_t mtid = isis_str2mtid(topology);
-
- switch (event) {
- case NB_EV_VALIDATE:
- if (mtid == (uint16_t)-1) {
- flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
- "Unknown topology %s", topology);
- return NB_ERR_VALIDATION;
- }
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- area = nb_running_get_entry(dnode, NULL, true);
- setting = area_get_mt_setting(area, mtid);
- setting->enabled = create;
- lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0);
- break;
- }
-
- return NB_OK;
-}
-
-static int isis_multi_topology_overload_common(enum nb_event event,
- const struct lyd_node *dnode,
- const char *topology)
-{
- struct isis_area *area;
- struct isis_area_mt_setting *setting;
- uint16_t mtid = isis_str2mtid(topology);
-
- /* validation is done in isis_multi_topology_common */
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- setting = area_get_mt_setting(area, mtid);
- setting->overload = yang_dnode_get_bool(dnode, NULL);
- if (setting->enabled)
- lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 0);
-
- return NB_OK;
-}
-
-static int
-isis_instance_multi_topology_ipv4_multicast_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_common(event, dnode, "ipv4-multicast", true);
-}
-
-static int
-isis_instance_multi_topology_ipv4_multicast_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- return isis_multi_topology_common(event, dnode, "ipv4-multicast",
- false);
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast/overload
- */
-static int isis_instance_multi_topology_ipv4_multicast_overload_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_overload_common(event, dnode,
- "ipv4-multicast");
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-management
- */
-static int isis_instance_multi_topology_ipv4_management_create(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_common(event, dnode, "ipv4-mgmt", true);
-}
-
-static int isis_instance_multi_topology_ipv4_management_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- return isis_multi_topology_common(event, dnode, "ipv4-mgmt", false);
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv4-management/overload
- */
-static int isis_instance_multi_topology_ipv4_management_overload_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_overload_common(event, dnode, "ipv4-mgmt");
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-unicast
- */
-static int
-isis_instance_multi_topology_ipv6_unicast_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_common(event, dnode, "ipv6-unicast", true);
-}
-
-static int
-isis_instance_multi_topology_ipv6_unicast_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- return isis_multi_topology_common(event, dnode, "ipv6-unicast", false);
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-unicast/overload
- */
-static int isis_instance_multi_topology_ipv6_unicast_overload_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_overload_common(event, dnode,
- "ipv6-unicast");
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-multicast
- */
-static int
-isis_instance_multi_topology_ipv6_multicast_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_common(event, dnode, "ipv6-multicast", true);
-}
-
-static int
-isis_instance_multi_topology_ipv6_multicast_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- return isis_multi_topology_common(event, dnode, "ipv6-multicast",
- false);
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-multicast/overload
- */
-static int isis_instance_multi_topology_ipv6_multicast_overload_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_overload_common(event, dnode,
- "ipv6-multicast");
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-management
- */
-static int isis_instance_multi_topology_ipv6_management_create(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_common(event, dnode, "ipv6-mgmt", true);
-}
-
-static int isis_instance_multi_topology_ipv6_management_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- return isis_multi_topology_common(event, dnode, "ipv6-mgmt", false);
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-management/overload
- */
-static int isis_instance_multi_topology_ipv6_management_overload_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_overload_common(event, dnode, "ipv6-mgmt");
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-dstsrc
- */
-static int
-isis_instance_multi_topology_ipv6_dstsrc_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_common(event, dnode, "ipv6-dstsrc", true);
-}
-
-static int
-isis_instance_multi_topology_ipv6_dstsrc_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- return isis_multi_topology_common(event, dnode, "ipv6-dstsrc", false);
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/multi-topology/ipv6-dstsrc/overload
- */
-static int isis_instance_multi_topology_ipv6_dstsrc_overload_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return isis_multi_topology_overload_common(event, dnode, "ipv6-dstsrc");
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/log-adjacency-changes
- */
-static int
-isis_instance_log_adjacency_changes_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- bool log = yang_dnode_get_bool(dnode, NULL);
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- area->log_adj_changes = log ? 1 : 0;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/mpls-te
- */
-static int isis_instance_mpls_te_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct listnode *node;
- struct isis_area *area;
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- if (area->mta == NULL) {
-
- struct mpls_te_area *new;
-
- zlog_debug("ISIS-TE(%s): Initialize MPLS Traffic Engineering",
- area->area_tag);
-
- new = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_area));
-
- /* Initialize MPLS_TE structure */
- new->status = enable;
- new->level = 0;
- new->inter_as = off;
- new->interas_areaid.s_addr = 0;
- new->router_id.s_addr = 0;
-
- area->mta = new;
- } else {
- area->mta->status = enable;
- }
-
- /* Update Extended TLVs according to Interface link parameters */
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
- isis_link_params_update(circuit, circuit->interface);
-
- /* Reoriginate STD_TE & GMPLS circuits */
- lsp_regenerate_schedule(area, area->is_type, 0);
-
- return NB_OK;
-}
-
-static int isis_instance_mpls_te_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct listnode *node;
- struct isis_area *area;
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- if (IS_MPLS_TE(area->mta))
- area->mta->status = disable;
- else
- return NB_OK;
-
- /* Flush LSP if circuit engage */
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
- if (!IS_EXT_TE(circuit->ext))
- continue;
-
- /* disable MPLS_TE Circuit keeping SR one's */
- if (IS_SUBTLV(circuit->ext, EXT_ADJ_SID))
- circuit->ext->status = EXT_ADJ_SID;
- else if (IS_SUBTLV(circuit->ext, EXT_LAN_ADJ_SID))
- circuit->ext->status = EXT_LAN_ADJ_SID;
- else
- circuit->ext->status = 0;
- }
-
- /* Reoriginate STD_TE & GMPLS circuits */
- lsp_regenerate_schedule(area, area->is_type, 0);
-
- zlog_debug("ISIS-TE(%s): Disabled MPLS Traffic Engineering",
- area->area_tag);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-isisd:isis/instance/mpls-te/router-address
- */
-static int isis_instance_mpls_te_router_address_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct in_addr value;
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- /* only proceed if MPLS-TE is enabled */
- if (!IS_MPLS_TE(area->mta))
- return NB_OK;
-
- /* Update Area Router ID */
- yang_dnode_get_ipv4(&value, dnode, NULL);
- area->mta->router_id.s_addr = value.s_addr;
-
- /* And re-schedule LSP update */
- lsp_regenerate_schedule(area, area->is_type, 0);
-
- return NB_OK;
-}
-
-static int isis_instance_mpls_te_router_address_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_area *area;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- area = nb_running_get_entry(dnode, NULL, true);
- /* only proceed if MPLS-TE is enabled */
- if (!IS_MPLS_TE(area->mta))
- return NB_OK;
-
- /* Reset Area Router ID */
- area->mta->router_id.s_addr = INADDR_ANY;
-
- /* And re-schedule LSP update */
- lsp_regenerate_schedule(area, area->is_type, 0);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis
- */
-static int lib_interface_isis_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_area *area;
- struct interface *ifp;
- struct isis_circuit *circuit;
- const char *area_tag = yang_dnode_get_string(dnode, "./area-tag");
- uint32_t min_mtu, actual_mtu;
-
- switch (event) {
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_VALIDATE:
- /* check if interface mtu is sufficient. If the area has not
- * been created yet, assume default MTU for the area
- */
- ifp = nb_running_get_entry(dnode, NULL, false);
- /* zebra might not know yet about the MTU - nothing we can do */
- if (!ifp || ifp->mtu == 0)
- break;
- actual_mtu =
- if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
- area = isis_area_lookup(area_tag);
- if (area)
- min_mtu = area->lsp_mtu;
- else
-#ifndef FABRICD
- min_mtu = yang_get_default_uint16(
- "/frr-isisd:isis/instance/lsp/mtu");
-#else
- min_mtu = DEFAULT_LSP_MTU;
-#endif /* ifndef FABRICD */
- if (actual_mtu < min_mtu) {
- flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
- "Interface %s has MTU %" PRIu32
- ", minimum MTU for the area is %" PRIu32 "",
- ifp->name, actual_mtu, min_mtu);
- return NB_ERR_VALIDATION;
- }
- break;
- case NB_EV_APPLY:
- area = isis_area_lookup(area_tag);
- /* The area should have already be created. We are
- * setting the priority of the global isis area creation
- * slightly lower, so it should be executed first, but I
- * cannot rely on that so here I have to check.
- */
- if (!area) {
- flog_err(
- EC_LIB_NB_CB_CONFIG_APPLY,
- "%s: attempt to create circuit for area %s before the area has been created",
- __func__, area_tag);
- abort();
- }
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- circuit = isis_circuit_create(area, ifp);
- assert(circuit
- && (circuit->state == C_STATE_CONF
- || circuit->state == C_STATE_UP));
- nb_running_set_entry(dnode, circuit);
- break;
- }
-
- return NB_OK;
-}
-
-static int lib_interface_isis_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_unset_entry(dnode);
- if (!circuit)
- return NB_ERR_INCONSISTENCY;
- if (circuit->state == C_STATE_UP || circuit->state == C_STATE_CONF)
- isis_csm_state_change(ISIS_DISABLE, circuit, circuit->area);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/area-tag
- */
-static int lib_interface_isis_area_tag_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- struct interface *ifp;
- struct vrf *vrf;
- const char *area_tag, *ifname, *vrfname;
-
- if (event == NB_EV_VALIDATE) {
- /* libyang doesn't like relative paths across module boundaries
- */
- ifname = yang_dnode_get_string(dnode->parent->parent, "./name");
- vrfname = yang_dnode_get_string(dnode->parent->parent, "./vrf");
- vrf = vrf_lookup_by_name(vrfname);
- assert(vrf);
- ifp = if_lookup_by_name(ifname, vrf->vrf_id);
- if (!ifp)
- return NB_OK;
- circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list);
- area_tag = yang_dnode_get_string(dnode, NULL);
- if (circuit && circuit->area && circuit->area->area_tag
- && strcmp(circuit->area->area_tag, area_tag)) {
- flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
- "ISIS circuit is already defined on %s",
- circuit->area->area_tag);
- return NB_ERR_VALIDATION;
- }
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/circuit-type
- */
-static int lib_interface_isis_circuit_type_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- int circ_type = yang_dnode_get_enum(dnode, NULL);
- struct isis_circuit *circuit;
- struct interface *ifp;
- struct vrf *vrf;
- const char *ifname, *vrfname;
-
- switch (event) {
- case NB_EV_VALIDATE:
- /* libyang doesn't like relative paths across module boundaries
- */
- ifname = yang_dnode_get_string(dnode->parent->parent, "./name");
- vrfname = yang_dnode_get_string(dnode->parent->parent, "./vrf");
- vrf = vrf_lookup_by_name(vrfname);
- assert(vrf);
- ifp = if_lookup_by_name(ifname, vrf->vrf_id);
- if (!ifp)
- break;
- circuit = circuit_lookup_by_ifp(ifp, isis->init_circ_list);
- if (circuit && circuit->state == C_STATE_UP
- && circuit->area->is_type != IS_LEVEL_1_AND_2
- && circuit->area->is_type != circ_type) {
- flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
- "Invalid circuit level for area %s",
- circuit->area->area_tag);
- return NB_ERR_VALIDATION;
- }
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- circuit = nb_running_get_entry(dnode, NULL, true);
- isis_circuit_is_type_set(circuit, circ_type);
- break;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv4-routing
- */
-static int lib_interface_isis_ipv4_routing_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- bool ipv4, ipv6;
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- ipv4 = yang_dnode_get_bool(dnode, NULL);
- ipv6 = yang_dnode_get_bool(dnode, "../ipv6-routing");
- isis_circuit_af_set(circuit, ipv4, ipv6);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/ipv6-routing
- */
-static int lib_interface_isis_ipv6_routing_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- bool ipv4, ipv6;
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- ipv4 = yang_dnode_exists(dnode, "../ipv4-routing");
- ipv6 = yang_dnode_get_bool(dnode, NULL);
- isis_circuit_af_set(circuit, ipv4, ipv6);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/bfd-monitoring
- */
-static int lib_interface_isis_bfd_monitoring_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- bool bfd_monitoring;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- bfd_monitoring = yang_dnode_get_bool(dnode, NULL);
-
- if (bfd_monitoring) {
- isis_bfd_circuit_param_set(circuit, BFD_DEF_MIN_RX,
- BFD_DEF_MIN_TX, BFD_DEF_DETECT_MULT,
- true);
- } else {
- isis_bfd_circuit_cmd(circuit, ZEBRA_BFD_DEST_DEREGISTER);
- bfd_info_free(&circuit->bfd_info);
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1
- */
-static int
-lib_interface_isis_csnp_interval_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->csnp_interval[0] = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2
- */
-static int
-lib_interface_isis_csnp_interval_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->csnp_interval[1] = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1
- */
-static int
-lib_interface_isis_psnp_interval_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->psnp_interval[0] = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2
- */
-static int
-lib_interface_isis_psnp_interval_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->psnp_interval[1] = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/padding
- */
-static int lib_interface_isis_hello_padding_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->pad_hellos = yang_dnode_get_bool(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1
- */
-static int
-lib_interface_isis_hello_interval_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- uint32_t interval;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- interval = yang_dnode_get_uint32(dnode, NULL);
- circuit->hello_interval[0] = interval;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2
- */
-static int
-lib_interface_isis_hello_interval_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- uint32_t interval;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- interval = yang_dnode_get_uint32(dnode, NULL);
- circuit->hello_interval[1] = interval;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1
- */
-static int
-lib_interface_isis_hello_multiplier_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- uint16_t multi;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- multi = yang_dnode_get_uint16(dnode, NULL);
- circuit->hello_multiplier[0] = multi;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2
- */
-static int
-lib_interface_isis_hello_multiplier_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- uint16_t multi;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- multi = yang_dnode_get_uint16(dnode, NULL);
- circuit->hello_multiplier[1] = multi;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/metric/level-1
- */
-static int
-lib_interface_isis_metric_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- unsigned int met;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- met = yang_dnode_get_uint32(dnode, NULL);
- isis_circuit_metric_set(circuit, IS_LEVEL_1, met);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/metric/level-2
- */
-static int
-lib_interface_isis_metric_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- unsigned int met;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- met = yang_dnode_get_uint32(dnode, NULL);
- isis_circuit_metric_set(circuit, IS_LEVEL_2, met);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/priority/level-1
- */
-static int
-lib_interface_isis_priority_level_1_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->priority[0] = yang_dnode_get_uint8(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/priority/level-2
- */
-static int
-lib_interface_isis_priority_level_2_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->priority[1] = yang_dnode_get_uint8(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/network-type
- */
-static int lib_interface_isis_network_type_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- int net_type = yang_dnode_get_enum(dnode, NULL);
-
- switch (event) {
- case NB_EV_VALIDATE:
- circuit = nb_running_get_entry(dnode, NULL, false);
- if (!circuit)
- break;
- if (circuit->circ_type == CIRCUIT_T_LOOPBACK) {
- flog_warn(
- EC_LIB_NB_CB_CONFIG_VALIDATE,
- "Cannot change network type on loopback interface");
- return NB_ERR_VALIDATION;
- }
- if (net_type == CIRCUIT_T_BROADCAST
- && circuit->state == C_STATE_UP
- && !if_is_broadcast(circuit->interface)) {
- flog_warn(
- EC_LIB_NB_CB_CONFIG_VALIDATE,
- "Cannot configure non-broadcast interface for broadcast operation");
- return NB_ERR_VALIDATION;
- }
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- circuit = nb_running_get_entry(dnode, NULL, true);
- isis_circuit_circ_type_set(circuit, net_type);
- break;
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/passive
- */
-static int lib_interface_isis_passive_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- struct isis_area *area;
- struct interface *ifp;
- bool passive = yang_dnode_get_bool(dnode, NULL);
-
- /* validation only applies if we are setting passive to false */
- if (!passive && event == NB_EV_VALIDATE) {
- circuit = nb_running_get_entry(dnode, NULL, false);
- if (!circuit)
- return NB_OK;
- ifp = circuit->interface;
- if (!ifp)
- return NB_OK;
- if (if_is_loopback(ifp)) {
- flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
- "Loopback is always passive");
- return NB_ERR_VALIDATION;
- }
- }
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- if (circuit->state != C_STATE_UP) {
- circuit->is_passive = passive;
- } else {
- area = circuit->area;
- isis_csm_state_change(ISIS_DISABLE, circuit, area);
- circuit->is_passive = passive;
- isis_csm_state_change(ISIS_ENABLE, circuit, area);
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/password
- */
-static int lib_interface_isis_password_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return NB_OK;
-}
-
-static int lib_interface_isis_password_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- isis_circuit_passwd_unset(circuit);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/password/password
- */
-static int
-lib_interface_isis_password_password_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- const char *password;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- password = yang_dnode_get_string(dnode, NULL);
- circuit = nb_running_get_entry(dnode, NULL, true);
-
- isis_circuit_passwd_set(circuit, circuit->passwd.type, password);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/password/password-type
- */
-static int
-lib_interface_isis_password_password_type_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
- uint8_t pass_type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- pass_type = yang_dnode_get_enum(dnode, NULL);
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->passwd.type = pass_type;
-
- return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/disable-three-way-handshake
- */
-static int lib_interface_isis_disable_three_way_handshake_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct isis_circuit *circuit;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- circuit = nb_running_get_entry(dnode, NULL, true);
- circuit->disable_threeway_adj = yang_dnode_get_bool(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-unicast
- */
-static int lib_interface_isis_multi_topology_common(
- enum nb_event event, const struct lyd_node *dnode, uint16_t mtid)
-{
- struct isis_circuit *circuit;
- bool value;
-
- switch (event) {
- case NB_EV_VALIDATE:
- circuit = nb_running_get_entry(dnode, NULL, false);
- if (circuit && circuit->area && circuit->area->oldmetric) {
- flog_warn(
- EC_LIB_NB_CB_CONFIG_VALIDATE,
- "Multi topology IS-IS can only be used with wide metrics");
- return NB_ERR_VALIDATION;
- }
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- circuit = nb_running_get_entry(dnode, NULL, true);
- value = yang_dnode_get_bool(dnode, NULL);
- isis_circuit_mt_enabled_set(circuit, mtid, value);
- break;
- }
-
- return NB_OK;
-}
-
-static int lib_interface_isis_multi_topology_ipv4_unicast_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return lib_interface_isis_multi_topology_common(event, dnode,
- ISIS_MT_IPV4_UNICAST);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-multicast
- */
-static int lib_interface_isis_multi_topology_ipv4_multicast_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return lib_interface_isis_multi_topology_common(event, dnode,
- ISIS_MT_IPV4_MULTICAST);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-management
- */
-static int lib_interface_isis_multi_topology_ipv4_management_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return lib_interface_isis_multi_topology_common(event, dnode,
- ISIS_MT_IPV4_MGMT);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-unicast
- */
-static int lib_interface_isis_multi_topology_ipv6_unicast_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return lib_interface_isis_multi_topology_common(event, dnode,
- ISIS_MT_IPV6_UNICAST);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-multicast
- */
-static int lib_interface_isis_multi_topology_ipv6_multicast_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return lib_interface_isis_multi_topology_common(event, dnode,
- ISIS_MT_IPV6_MULTICAST);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-management
- */
-static int lib_interface_isis_multi_topology_ipv6_management_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return lib_interface_isis_multi_topology_common(event, dnode,
- ISIS_MT_IPV6_MGMT);
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-dstsrc
- */
-static int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- return lib_interface_isis_multi_topology_common(event, dnode,
- ISIS_MT_IPV6_DSTSRC);
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency
- */
-static const void *
-lib_interface_isis_adjacencies_adjacency_get_next(const void *parent_list_entry,
- const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
- struct isis_adjacency *adj, *adj_next = NULL;
- struct list *list;
- struct listnode *node, *node_next;
-
- /* Get first adjacency. */
- if (list_entry == NULL) {
- ifp = (struct interface *)parent_list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- switch (circuit->circ_type) {
- case CIRCUIT_T_BROADCAST:
- for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
- level++) {
- adj = listnode_head(
- circuit->u.bc.adjdb[level - 1]);
- if (adj)
- break;
- }
- break;
- case CIRCUIT_T_P2P:
- adj = circuit->u.p2p.neighbor;
- break;
- default:
- adj = NULL;
- break;
- }
-
- return adj;
- }
-
- /* Get next adjacency. */
- adj = (struct isis_adjacency *)list_entry;
- circuit = adj->circuit;
- switch (circuit->circ_type) {
- case CIRCUIT_T_BROADCAST:
- list = circuit->u.bc.adjdb[adj->level - 1];
- node = listnode_lookup(list, adj);
- node_next = listnextnode(node);
- if (node_next)
- adj_next = listgetdata(node_next);
- else if (adj->level == ISIS_LEVEL1) {
- /*
- * Once we finish the L1 adjacencies, move to the L2
- * adjacencies list.
- */
- list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1];
- adj_next = listnode_head(list);
- }
- break;
- case CIRCUIT_T_P2P:
- /* P2P circuits have at most one adjacency. */
- default:
- break;
- }
-
- return adj_next;
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type
- */
-static struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct isis_adjacency *adj = list_entry;
-
- return yang_data_new_enum(xpath, adj->level);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid
- */
-static struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct isis_adjacency *adj = list_entry;
-
- return yang_data_new_string(xpath, sysid_print(adj->sysid));
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id
- */
-static struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct isis_adjacency *adj = list_entry;
-
- return yang_data_new_uint32(xpath, adj->circuit->circuit_id);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa
- */
-static struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct isis_adjacency *adj = list_entry;
-
- return yang_data_new_string(xpath, snpa_print(adj->snpa));
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer
- */
-static struct yang_data *
-lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct isis_adjacency *adj = list_entry;
-
- return yang_data_new_uint16(xpath, adj->hold_time);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority
- */
-static struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct isis_adjacency *adj = list_entry;
-
- return yang_data_new_uint8(xpath, adj->prio[adj->level - 1]);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state
- */
-static struct yang_data *
-lib_interface_isis_adjacencies_adjacency_state_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct isis_adjacency *adj = list_entry;
-
- return yang_data_new_string(xpath, isis_yang_adj_state(adj->adj_state));
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes
- */
-static struct yang_data *
-lib_interface_isis_event_counters_adjacency_changes_get_elem(
- const char *xpath, const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
-
- ifp = (struct interface *)list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- return yang_data_new_uint32(xpath, circuit->adj_state_changes);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number
- */
-static struct yang_data *
-lib_interface_isis_event_counters_adjacency_number_get_elem(
- const char *xpath, const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
- struct isis_adjacency *adj;
- struct listnode *node;
- uint32_t total = 0;
-
- ifp = (struct interface *)list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- /*
- * TODO: keep track of the number of adjacencies instead of calculating
- * it on demand.
- */
- switch (circuit->circ_type) {
- case CIRCUIT_T_BROADCAST:
- for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
- for (ALL_LIST_ELEMENTS_RO(
- circuit->u.bc.adjdb[level - 1], node, adj))
- total++;
- }
- break;
- case CIRCUIT_T_P2P:
- adj = circuit->u.p2p.neighbor;
- if (adj)
- total = 1;
- break;
- default:
- break;
- }
-
- return yang_data_new_uint32(xpath, total);
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails
- */
-static struct yang_data *
-lib_interface_isis_event_counters_init_fails_get_elem(const char *xpath,
- const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
-
- ifp = (struct interface *)list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- return yang_data_new_uint32(xpath, circuit->init_failures);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects
- */
-static struct yang_data *
-lib_interface_isis_event_counters_adjacency_rejects_get_elem(
- const char *xpath, const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
-
- ifp = (struct interface *)list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- return yang_data_new_uint32(xpath, circuit->rej_adjacencies);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch
- */
-static struct yang_data *
-lib_interface_isis_event_counters_id_len_mismatch_get_elem(
- const char *xpath, const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
-
- ifp = (struct interface *)list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- return yang_data_new_uint32(xpath, circuit->id_len_mismatches);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch
- */
-static struct yang_data *
-lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem(
- const char *xpath, const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
-
- ifp = (struct interface *)list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- return yang_data_new_uint32(xpath, circuit->max_area_addr_mismatches);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails
- */
-static struct yang_data *
-lib_interface_isis_event_counters_authentication_type_fails_get_elem(
- const char *xpath, const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
-
- ifp = (struct interface *)list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- return yang_data_new_uint32(xpath, circuit->auth_type_failures);
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails
- */
-static struct yang_data *
-lib_interface_isis_event_counters_authentication_fails_get_elem(
- const char *xpath, const void *list_entry)
-{
- struct interface *ifp;
- struct isis_circuit *circuit;
-
- ifp = (struct interface *)list_entry;
- if (!ifp)
- return NULL;
-
- circuit = circuit_scan_by_ifp(ifp);
- if (!circuit)
- return NULL;
-
- return yang_data_new_uint32(xpath, circuit->auth_failures);
-}
-
-/*
- * NOTIFICATIONS
- */
-static void notif_prep_instance_hdr(const char *xpath,
- const struct isis_area *area,
- const char *routing_instance,
- struct list *args)
-{
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
-
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/routing-instance", xpath);
- data = yang_data_new_string(xpath_arg, routing_instance);
- listnode_add(args, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/routing-protocol-name",
- xpath);
- data = yang_data_new_string(xpath_arg, area->area_tag);
- listnode_add(args, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/isis-level", xpath);
- data = yang_data_new_enum(xpath_arg, area->is_type);
- listnode_add(args, data);
-}
-
-static void notif_prepr_iface_hdr(const char *xpath,
- const struct isis_circuit *circuit,
- struct list *args)
-{
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
-
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-name", xpath);
- data = yang_data_new_string(xpath_arg, circuit->interface->name);
- listnode_add(args, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-level", xpath);
- data = yang_data_new_enum(xpath_arg, circuit->is_type);
- listnode_add(args, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/extended-circuit-id", xpath);
- /* we do not seem to have the extended version of the circuit_id */
- data = yang_data_new_uint32(xpath_arg, (uint32_t)circuit->circuit_id);
- listnode_add(args, data);
-}
-
-/*
- * XPath:
- * /frr-isisd:database-overload
- */
-void isis_notif_db_overload(const struct isis_area *area, bool overload)
-{
- const char *xpath = "/frr-isisd:database-overload";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/overload", xpath);
- data = yang_data_new_enum(xpath_arg, !!overload);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:lsp-too-large
- */
-void isis_notif_lsp_too_large(const struct isis_circuit *circuit,
- uint32_t pdu_size, const char *lsp_id)
-{
- const char *xpath = "/frr-isisd:lsp-too-large";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/pdu-size", xpath);
- data = yang_data_new_uint32(xpath_arg, pdu_size);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:if-state-change
- */
-void isis_notif_if_state_change(const struct isis_circuit *circuit, bool down)
-{
- const char *xpath = "/frr-isisd:if-state-change";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath);
- data = yang_data_new_enum(xpath_arg, !!down);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:corrupted-lsp-detected
- */
-void isis_notif_corrupted_lsp(const struct isis_area *area, const char *lsp_id)
-{
- const char *xpath = "/frr-isisd:corrupted-lsp-detected";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:attempt-to-exceed-max-sequence
- */
-void isis_notif_lsp_exceed_max(const struct isis_area *area, const char *lsp_id)
-{
- const char *xpath = "/frr-isisd:attempt-to-exceed-max-sequence";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:max-area-addresses-mismatch
- */
-void isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
- uint8_t max_area_addrs,
- const char *raw_pdu)
-{
- const char *xpath = "/frr-isisd:max-area-addresses-mismatch";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/max-area-addresses", xpath);
- data = yang_data_new_uint8(xpath_arg, max_area_addrs);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:authentication-type-failure
- */
-void isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
- const char *raw_pdu)
-{
- const char *xpath = "/frr-isisd:authentication-type-failure";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:authentication-failure
- */
-void isis_notif_authentication_failure(const struct isis_circuit *circuit,
- const char *raw_pdu)
-{
- const char *xpath = "/frr-isisd:authentication-failure";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:adjacency-state-change
- */
-void isis_notif_adj_state_change(const struct isis_adjacency *adj,
- int new_state, const char *reason)
-{
- const char *xpath = "/frr-isisd:adjacency-state-change";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_circuit *circuit = adj->circuit;
- struct isis_area *area = circuit->area;
- struct isis_dynhn *dyn = dynhn_find_by_id(adj->sysid);
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- if (dyn) {
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/neighbor", xpath);
- data = yang_data_new_string(xpath_arg, dyn->hostname);
- listnode_add(arguments, data);
- }
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/neighbor-system-id", xpath);
- data = yang_data_new_string(xpath_arg, sysid_print(adj->sysid));
- listnode_add(arguments, data);
-
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath);
- data = yang_data_new_string(xpath_arg, isis_yang_adj_state(new_state));
- listnode_add(arguments, data);
- if (new_state == ISIS_ADJ_DOWN) {
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath);
- data = yang_data_new_string(xpath_arg, reason);
- listnode_add(arguments, data);
- }
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:rejected-adjacency
- */
-void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
- const char *reason, const char *raw_pdu)
-{
- const char *xpath = "/frr-isisd:rejected-adjacency";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath);
- data = yang_data_new_string(xpath_arg, reason);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:area-mismatch
- */
-void isis_notif_area_mismatch(const struct isis_circuit *circuit,
- const char *raw_pdu)
-{
- const char *xpath = "/frr-isisd:area-mismatch";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:lsp-received
- */
-void isis_notif_lsp_received(const struct isis_circuit *circuit,
- const char *lsp_id, uint32_t seqno,
- uint32_t timestamp, const char *sys_id)
-{
- const char *xpath = "/frr-isisd:lsp-received";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/sequence", xpath);
- data = yang_data_new_uint32(xpath_arg, seqno);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/received-timestamp", xpath);
- data = yang_data_new_uint32(xpath_arg, timestamp);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/neighbor-system-id", xpath);
- data = yang_data_new_string(xpath_arg, sys_id);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:lsp-generation
- */
-void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id,
- uint32_t seqno, uint32_t timestamp)
-{
- const char *xpath = "/frr-isisd:lsp-generation";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/sequence", xpath);
- data = yang_data_new_uint32(xpath_arg, seqno);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/send-timestamp", xpath);
- data = yang_data_new_uint32(xpath_arg, timestamp);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:id-len-mismatch
- */
-void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
- uint8_t rcv_id_len, const char *raw_pdu)
-{
- const char *xpath = "/frr-isisd:id-len-mismatch";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/pdu-field-len", xpath);
- data = yang_data_new_uint8(xpath_arg, rcv_id_len);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:version-skew
- */
-void isis_notif_version_skew(const struct isis_circuit *circuit,
- uint8_t version, const char *raw_pdu)
-{
- const char *xpath = "/frr-isisd:version-skew";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/protocol-version", xpath);
- data = yang_data_new_uint8(xpath_arg, version);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:lsp-error-detected
- */
-void isis_notif_lsp_error(const struct isis_circuit *circuit,
- const char *lsp_id, const char *raw_pdu,
- __attribute__((unused)) uint32_t offset,
- __attribute__((unused)) uint8_t tlv_type)
-{
- const char *xpath = "/frr-isisd:lsp-error-detected";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
- listnode_add(arguments, data);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/raw-pdu", xpath);
- data = yang_data_new(xpath_arg, raw_pdu);
- listnode_add(arguments, data);
- /* ignore offset and tlv_type which cannot be set properly */
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:sequence-number-skipped
- */
-void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
- const char *lsp_id)
-{
- const char *xpath = "/frr-isisd:sequence-number-skipped";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath:
- * /frr-isisd:own-lsp-purge
- */
-void isis_notif_own_lsp_purge(const struct isis_circuit *circuit,
- const char *lsp_id)
-{
- const char *xpath = "/frr-isisd:own-lsp-purge";
- struct list *arguments = yang_data_list_new();
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
- struct isis_area *area = circuit->area;
-
- notif_prep_instance_hdr(xpath, area, "default", arguments);
- notif_prepr_iface_hdr(xpath, circuit, arguments);
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/lsp-id", xpath);
- data = yang_data_new_string(xpath_arg, lsp_id);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/* clang-format off */
-const struct frr_yang_module_info frr_isisd_info = {
- .name = "frr-isisd",
- .nodes = {
- {
- .xpath = "/frr-isisd:isis/instance",
- .cbs = {
- .cli_show = cli_show_router_isis,
- .create = isis_instance_create,
- .destroy = isis_instance_destroy,
- },
- .priority = NB_DFLT_PRIORITY - 1,
- },
- {
- .xpath = "/frr-isisd:isis/instance/is-type",
- .cbs = {
- .cli_show = cli_show_isis_is_type,
- .modify = isis_instance_is_type_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/area-address",
- .cbs = {
- .cli_show = cli_show_isis_area_address,
- .create = isis_instance_area_address_create,
- .destroy = isis_instance_area_address_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/dynamic-hostname",
- .cbs = {
- .cli_show = cli_show_isis_dynamic_hostname,
- .modify = isis_instance_dynamic_hostname_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/attached",
- .cbs = {
- .cli_show = cli_show_isis_attached,
- .modify = isis_instance_attached_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/overload",
- .cbs = {
- .cli_show = cli_show_isis_overload,
- .modify = isis_instance_overload_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/metric-style",
- .cbs = {
- .cli_show = cli_show_isis_metric_style,
- .modify = isis_instance_metric_style_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/purge-originator",
- .cbs = {
- .cli_show = cli_show_isis_purge_origin,
- .modify = isis_instance_purge_originator_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/mtu",
- .cbs = {
- .cli_show = cli_show_isis_lsp_mtu,
- .modify = isis_instance_lsp_mtu_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/refresh-interval",
- .cbs = {
- .cli_show = cli_show_isis_lsp_ref_interval,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/refresh-interval/level-1",
- .cbs = {
- .modify = isis_instance_lsp_refresh_interval_level_1_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/refresh-interval/level-2",
- .cbs = {
- .modify = isis_instance_lsp_refresh_interval_level_2_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/maximum-lifetime",
- .cbs = {
- .cli_show = cli_show_isis_lsp_max_lifetime,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/maximum-lifetime/level-1",
- .cbs = {
- .modify = isis_instance_lsp_maximum_lifetime_level_1_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/maximum-lifetime/level-2",
- .cbs = {
- .modify = isis_instance_lsp_maximum_lifetime_level_2_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/generation-interval",
- .cbs = {
- .cli_show = cli_show_isis_lsp_gen_interval,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/generation-interval/level-1",
- .cbs = {
- .modify = isis_instance_lsp_generation_interval_level_1_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/lsp/generation-interval/level-2",
- .cbs = {
- .modify = isis_instance_lsp_generation_interval_level_2_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay",
- .cbs = {
- .apply_finish = ietf_backoff_delay_apply_finish,
- .cli_show = cli_show_isis_spf_ietf_backoff,
- .create = isis_instance_spf_ietf_backoff_delay_create,
- .destroy = isis_instance_spf_ietf_backoff_delay_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/init-delay",
- .cbs = {
- .modify = isis_instance_spf_ietf_backoff_delay_init_delay_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/short-delay",
- .cbs = {
- .modify = isis_instance_spf_ietf_backoff_delay_short_delay_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/long-delay",
- .cbs = {
- .modify = isis_instance_spf_ietf_backoff_delay_long_delay_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/hold-down",
- .cbs = {
- .modify = isis_instance_spf_ietf_backoff_delay_hold_down_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay/time-to-learn",
- .cbs = {
- .modify = isis_instance_spf_ietf_backoff_delay_time_to_learn_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/minimum-interval",
- .cbs = {
- .cli_show = cli_show_isis_spf_min_interval,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/minimum-interval/level-1",
- .cbs = {
- .modify = isis_instance_spf_minimum_interval_level_1_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/spf/minimum-interval/level-2",
- .cbs = {
- .modify = isis_instance_spf_minimum_interval_level_2_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/area-password",
- .cbs = {
- .apply_finish = area_password_apply_finish,
- .cli_show = cli_show_isis_area_pwd,
- .create = isis_instance_area_password_create,
- .destroy = isis_instance_area_password_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/area-password/password",
- .cbs = {
- .modify = isis_instance_area_password_password_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/area-password/password-type",
- .cbs = {
- .modify = isis_instance_area_password_password_type_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/area-password/authenticate-snp",
- .cbs = {
- .modify = isis_instance_area_password_authenticate_snp_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/domain-password",
- .cbs = {
- .apply_finish = domain_password_apply_finish,
- .cli_show = cli_show_isis_domain_pwd,
- .create = isis_instance_domain_password_create,
- .destroy = isis_instance_domain_password_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/domain-password/password",
- .cbs = {
- .modify = isis_instance_domain_password_password_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/domain-password/password-type",
- .cbs = {
- .modify = isis_instance_domain_password_password_type_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/domain-password/authenticate-snp",
- .cbs = {
- .modify = isis_instance_domain_password_authenticate_snp_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4",
- .cbs = {
- .apply_finish = default_info_origin_ipv4_apply_finish,
- .cli_show = cli_show_isis_def_origin_ipv4,
- .create = isis_instance_default_information_originate_ipv4_create,
- .destroy = isis_instance_default_information_originate_ipv4_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/always",
- .cbs = {
- .modify = isis_instance_default_information_originate_ipv4_always_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/route-map",
- .cbs = {
- .destroy = isis_instance_default_information_originate_ipv4_route_map_destroy,
- .modify = isis_instance_default_information_originate_ipv4_route_map_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/metric",
- .cbs = {
- .modify = isis_instance_default_information_originate_ipv4_metric_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6",
- .cbs = {
- .apply_finish = default_info_origin_ipv6_apply_finish,
- .cli_show = cli_show_isis_def_origin_ipv6,
- .create = isis_instance_default_information_originate_ipv6_create,
- .destroy = isis_instance_default_information_originate_ipv6_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/always",
- .cbs = {
- .modify = isis_instance_default_information_originate_ipv6_always_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/route-map",
- .cbs = {
- .destroy = isis_instance_default_information_originate_ipv6_route_map_destroy,
- .modify = isis_instance_default_information_originate_ipv6_route_map_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/metric",
- .cbs = {
- .modify = isis_instance_default_information_originate_ipv6_metric_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/redistribute/ipv4",
- .cbs = {
- .apply_finish = redistribute_ipv4_apply_finish,
- .cli_show = cli_show_isis_redistribute_ipv4,
- .create = isis_instance_redistribute_ipv4_create,
- .destroy = isis_instance_redistribute_ipv4_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/route-map",
- .cbs = {
- .destroy = isis_instance_redistribute_ipv4_route_map_destroy,
- .modify = isis_instance_redistribute_ipv4_route_map_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric",
- .cbs = {
- .modify = isis_instance_redistribute_ipv4_metric_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/redistribute/ipv6",
- .cbs = {
- .apply_finish = redistribute_ipv6_apply_finish,
- .cli_show = cli_show_isis_redistribute_ipv6,
- .create = isis_instance_redistribute_ipv6_create,
- .destroy = isis_instance_redistribute_ipv6_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/route-map",
- .cbs = {
- .destroy = isis_instance_redistribute_ipv6_route_map_destroy,
- .modify = isis_instance_redistribute_ipv6_route_map_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric",
- .cbs = {
- .modify = isis_instance_redistribute_ipv6_metric_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast",
- .cbs = {
- .cli_show = cli_show_isis_mt_ipv4_multicast,
- .create = isis_instance_multi_topology_ipv4_multicast_create,
- .destroy = isis_instance_multi_topology_ipv4_multicast_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast/overload",
- .cbs = {
- .modify = isis_instance_multi_topology_ipv4_multicast_overload_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-management",
- .cbs = {
- .cli_show = cli_show_isis_mt_ipv4_mgmt,
- .create = isis_instance_multi_topology_ipv4_management_create,
- .destroy = isis_instance_multi_topology_ipv4_management_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-management/overload",
- .cbs = {
- .modify = isis_instance_multi_topology_ipv4_management_overload_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-unicast",
- .cbs = {
- .cli_show = cli_show_isis_mt_ipv6_unicast,
- .create = isis_instance_multi_topology_ipv6_unicast_create,
- .destroy = isis_instance_multi_topology_ipv6_unicast_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-unicast/overload",
- .cbs = {
- .modify = isis_instance_multi_topology_ipv6_unicast_overload_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-multicast",
- .cbs = {
- .cli_show = cli_show_isis_mt_ipv6_multicast,
- .create = isis_instance_multi_topology_ipv6_multicast_create,
- .destroy = isis_instance_multi_topology_ipv6_multicast_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-multicast/overload",
- .cbs = {
- .modify = isis_instance_multi_topology_ipv6_multicast_overload_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-management",
- .cbs = {
- .cli_show = cli_show_isis_mt_ipv6_mgmt,
- .create = isis_instance_multi_topology_ipv6_management_create,
- .destroy = isis_instance_multi_topology_ipv6_management_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-management/overload",
- .cbs = {
- .modify = isis_instance_multi_topology_ipv6_management_overload_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-dstsrc",
- .cbs = {
- .cli_show = cli_show_isis_mt_ipv6_dstsrc,
- .create = isis_instance_multi_topology_ipv6_dstsrc_create,
- .destroy = isis_instance_multi_topology_ipv6_dstsrc_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-dstsrc/overload",
- .cbs = {
- .modify = isis_instance_multi_topology_ipv6_dstsrc_overload_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/log-adjacency-changes",
- .cbs = {
- .cli_show = cli_show_isis_log_adjacency,
- .modify = isis_instance_log_adjacency_changes_modify,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/mpls-te",
- .cbs = {
- .cli_show = cli_show_isis_mpls_te,
- .create = isis_instance_mpls_te_create,
- .destroy = isis_instance_mpls_te_destroy,
- },
- },
- {
- .xpath = "/frr-isisd:isis/instance/mpls-te/router-address",
- .cbs = {
- .cli_show = cli_show_isis_mpls_te_router_addr,
- .destroy = isis_instance_mpls_te_router_address_destroy,
- .modify = isis_instance_mpls_te_router_address_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis",
- .cbs = {
- .create = lib_interface_isis_create,
- .destroy = lib_interface_isis_destroy,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/area-tag",
- .cbs = {
- .modify = lib_interface_isis_area_tag_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/circuit-type",
- .cbs = {
- .cli_show = cli_show_ip_isis_circ_type,
- .modify = lib_interface_isis_circuit_type_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/ipv4-routing",
- .cbs = {
- .cli_show = cli_show_ip_isis_ipv4,
- .modify = lib_interface_isis_ipv4_routing_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/ipv6-routing",
- .cbs = {
- .cli_show = cli_show_ip_isis_ipv6,
- .modify = lib_interface_isis_ipv6_routing_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/bfd-monitoring",
- .cbs = {
- .modify = lib_interface_isis_bfd_monitoring_modify,
- .cli_show = cli_show_ip_isis_bfd_monitoring,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval",
- .cbs = {
- .cli_show = cli_show_ip_isis_csnp_interval,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1",
- .cbs = {
- .modify = lib_interface_isis_csnp_interval_level_1_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2",
- .cbs = {
- .modify = lib_interface_isis_csnp_interval_level_2_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval",
- .cbs = {
- .cli_show = cli_show_ip_isis_psnp_interval,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1",
- .cbs = {
- .modify = lib_interface_isis_psnp_interval_level_1_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2",
- .cbs = {
- .modify = lib_interface_isis_psnp_interval_level_2_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/padding",
- .cbs = {
- .cli_show = cli_show_ip_isis_hello_padding,
- .modify = lib_interface_isis_hello_padding_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/interval",
- .cbs = {
- .cli_show = cli_show_ip_isis_hello_interval,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1",
- .cbs = {
- .modify = lib_interface_isis_hello_interval_level_1_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2",
- .cbs = {
- .modify = lib_interface_isis_hello_interval_level_2_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier",
- .cbs = {
- .cli_show = cli_show_ip_isis_hello_multi,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1",
- .cbs = {
- .modify = lib_interface_isis_hello_multiplier_level_1_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2",
- .cbs = {
- .modify = lib_interface_isis_hello_multiplier_level_2_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/metric",
- .cbs = {
- .cli_show = cli_show_ip_isis_metric,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1",
- .cbs = {
- .modify = lib_interface_isis_metric_level_1_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2",
- .cbs = {
- .modify = lib_interface_isis_metric_level_2_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/priority",
- .cbs = {
- .cli_show = cli_show_ip_isis_priority,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/priority/level-1",
- .cbs = {
- .modify = lib_interface_isis_priority_level_1_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/priority/level-2",
- .cbs = {
- .modify = lib_interface_isis_priority_level_2_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/network-type",
- .cbs = {
- .cli_show = cli_show_ip_isis_network_type,
- .modify = lib_interface_isis_network_type_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/passive",
- .cbs = {
- .cli_show = cli_show_ip_isis_passive,
- .modify = lib_interface_isis_passive_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password",
- .cbs = {
- .cli_show = cli_show_ip_isis_password,
- .create = lib_interface_isis_password_create,
- .destroy = lib_interface_isis_password_destroy,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password/password",
- .cbs = {
- .modify = lib_interface_isis_password_password_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/password/password-type",
- .cbs = {
- .modify = lib_interface_isis_password_password_type_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/disable-three-way-handshake",
- .cbs = {
- .cli_show = cli_show_ip_isis_threeway_shake,
- .modify = lib_interface_isis_disable_three_way_handshake_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-unicast",
- .cbs = {
- .cli_show = cli_show_ip_isis_mt_ipv4_unicast,
- .modify = lib_interface_isis_multi_topology_ipv4_unicast_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-multicast",
- .cbs = {
- .cli_show = cli_show_ip_isis_mt_ipv4_multicast,
- .modify = lib_interface_isis_multi_topology_ipv4_multicast_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv4-management",
- .cbs = {
- .cli_show = cli_show_ip_isis_mt_ipv4_mgmt,
- .modify = lib_interface_isis_multi_topology_ipv4_management_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-unicast",
- .cbs = {
- .cli_show = cli_show_ip_isis_mt_ipv6_unicast,
- .modify = lib_interface_isis_multi_topology_ipv6_unicast_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-multicast",
- .cbs = {
- .cli_show = cli_show_ip_isis_mt_ipv6_multicast,
- .modify = lib_interface_isis_multi_topology_ipv6_multicast_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-management",
- .cbs = {
- .cli_show = cli_show_ip_isis_mt_ipv6_mgmt,
- .modify = lib_interface_isis_multi_topology_ipv6_management_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/multi-topology/ipv6-dstsrc",
- .cbs = {
- .cli_show = cli_show_ip_isis_mt_ipv6_dstsrc,
- .modify = lib_interface_isis_multi_topology_ipv6_dstsrc_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency",
- .cbs = {
- .get_next = lib_interface_isis_adjacencies_adjacency_get_next,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type",
- .cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid",
- .cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id",
- .cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa",
- .cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer",
- .cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority",
- .cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state",
- .cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_state_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes",
- .cbs = {
- .get_elem = lib_interface_isis_event_counters_adjacency_changes_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number",
- .cbs = {
- .get_elem = lib_interface_isis_event_counters_adjacency_number_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails",
- .cbs = {
- .get_elem = lib_interface_isis_event_counters_init_fails_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects",
- .cbs = {
- .get_elem = lib_interface_isis_event_counters_adjacency_rejects_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch",
- .cbs = {
- .get_elem = lib_interface_isis_event_counters_id_len_mismatch_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch",
- .cbs = {
- .get_elem = lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails",
- .cbs = {
- .get_elem = lib_interface_isis_event_counters_authentication_type_fails_get_elem,
- }
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails",
- .cbs = {
- .get_elem = lib_interface_isis_event_counters_authentication_fails_get_elem,
- }
- },
- {
- .xpath = NULL,
- },
- }
-};
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index a637ff003f..71249cf658 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -58,6 +58,7 @@
#include "isisd/fabricd.h"
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_pdu_counter.h"
+#include "isisd/isis_nb.h"
static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
int level)
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 029a9e0688..f15d7a9c7e 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -57,6 +57,7 @@
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#include "isisd/fabricd.h"
+#include "isisd/isis_nb.h"
struct isis *isis = NULL;
diff --git a/isisd/isisd.h b/isisd/isisd.h
index f825b6ecb4..052cc10928 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -219,52 +219,6 @@ int isis_area_passwd_cleartext_set(struct isis_area *area, int level,
int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level,
const char *passwd, uint8_t snp_auth);
-extern const struct frr_yang_module_info frr_isisd_info;
-extern void isis_northbound_init(void);
-
-/* YANG northbound notifications */
-extern void isis_notif_db_overload(const struct isis_area *area, bool overload);
-extern void isis_notif_lsp_too_large(const struct isis_circuit *circuit,
- uint32_t pdu_size, const char *lsp_id);
-extern void isis_notif_if_state_change(const struct isis_circuit *circuit,
- bool down);
-extern void isis_notif_corrupted_lsp(const struct isis_area *area,
- const char *lsp_id); /* currently unused */
-extern void isis_notif_lsp_exceed_max(const struct isis_area *area,
- const char *lsp_id);
-extern void
-isis_notif_max_area_addr_mismatch(const struct isis_circuit *circuit,
- uint8_t max_area_addrs, const char *raw_pdu);
-extern void
-isis_notif_authentication_type_failure(const struct isis_circuit *circuit,
- const char *raw_pdu);
-extern void
-isis_notif_authentication_failure(const struct isis_circuit *circuit,
- const char *raw_pdu);
-extern void isis_notif_adj_state_change(const struct isis_adjacency *adj,
- int new_state, const char *reason);
-extern void isis_notif_reject_adjacency(const struct isis_circuit *circuit,
- const char *reason,
- const char *raw_pdu);
-extern void isis_notif_area_mismatch(const struct isis_circuit *circuit,
- const char *raw_pdu);
-extern void isis_notif_lsp_received(const struct isis_circuit *circuit,
- const char *lsp_id, uint32_t seqno,
- uint32_t timestamp, const char *sys_id);
-extern void isis_notif_lsp_gen(const struct isis_area *area, const char *lsp_id,
- uint32_t seqno, uint32_t timestamp);
-extern void isis_notif_id_len_mismatch(const struct isis_circuit *circuit,
- uint8_t rcv_id_len, const char *raw_pdu);
-extern void isis_notif_version_skew(const struct isis_circuit *circuit,
- uint8_t version, const char *raw_pdu);
-extern void isis_notif_lsp_error(const struct isis_circuit *circuit,
- const char *lsp_id, const char *raw_pdu,
- uint32_t offset, uint8_t tlv_type);
-extern void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
- const char *lsp_id);
-extern void isis_notif_own_lsp_purge(const struct isis_circuit *circuit,
- const char *lsp_id);
-
/* Master of threads. */
extern struct thread_master *master;
diff --git a/isisd/subdir.am b/isisd/subdir.am
index 24f24022a5..e77fef41dd 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -39,6 +39,7 @@ noinst_HEADERS += \
isisd/isis_memory.h \
isisd/isis_misc.h \
isisd/isis_mt.h \
+ isisd/isis_nb.h \
isisd/isis_network.h \
isisd/isis_pdu.h \
isisd/isis_pdu_counter.h \
@@ -54,7 +55,6 @@ noinst_HEADERS += \
isisd/isisd.h \
isisd/iso_checksum.h \
isisd/fabricd.h \
- isisd/isis_cli.h \
# end
LIBISIS_SOURCES = \
@@ -99,7 +99,10 @@ ISIS_LDADD_COMMON = lib/libfrr.la $(LIBCAP)
isisd_libisis_a_SOURCES = \
$(LIBISIS_SOURCES) \
- isisd/isis_northbound.c \
+ isisd/isis_nb.c \
+ isisd/isis_nb_config.c \
+ isisd/isis_nb_notifications.c \
+ isisd/isis_nb_state.c \
isisd/isis_cli.c \
#end
diff --git a/lib/bfd.c b/lib/bfd.c
index 00dbd1b3d1..ffb3cbc1f8 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -315,6 +315,8 @@ const char *bfd_get_status_str(int status)
return "Down";
case BFD_STATUS_UP:
return "Up";
+ case BFD_STATUS_ADMIN_DOWN:
+ return "Admin Down";
case BFD_STATUS_UNKNOWN:
default:
return "Unknown";
diff --git a/lib/bfd.h b/lib/bfd.h
index e4781f4eaf..7f5d111504 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -51,9 +51,17 @@ struct bfd_gbl {
#define BFD_FLAG_BFD_CBIT_ON (1 << 3) /* Peer registered with CBIT set to on */
#define BFD_FLAG_BFD_CHECK_CONTROLPLANE (1 << 4) /* BFD and controlplane daemon are linked */
-#define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */
-#define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */
-#define BFD_STATUS_UP (1 << 2) /* BFD session status is up */
+#define BFD_STATUS_UNKNOWN (1 << 0) /* BFD session status never received */
+#define BFD_STATUS_DOWN (1 << 1) /* BFD session status is down */
+#define BFD_STATUS_UP (1 << 2) /* BFD session status is up */
+#define BFD_STATUS_ADMIN_DOWN (1 << 3) /* BFD session is admin down */
+
+#define BFD_SET_CLIENT_STATUS(current_status, new_status) \
+ do { \
+ (current_status) = \
+ (((new_status) == BFD_STATUS_ADMIN_DOWN) ? \
+ BFD_STATUS_DOWN : (new_status));\
+ } while (0)
enum bfd_sess_type {
BFD_TYPE_NOT_CONFIGURED,
diff --git a/lib/if.c b/lib/if.c
index 594961d763..7c3606bbbf 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -959,6 +959,20 @@ static int connected_same_prefix(struct prefix *p1, struct prefix *p2)
return 0;
}
+/* count the number of connected addresses that are in the given family */
+unsigned int connected_count_by_family(struct interface *ifp, int family)
+{
+ struct listnode *cnode;
+ struct connected *connected;
+ unsigned int cnt = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected))
+ if (connected->address->family == family)
+ cnt++;
+
+ return cnt;
+}
+
struct connected *connected_lookup_prefix_exact(struct interface *ifp,
struct prefix *p)
{
diff --git a/lib/if.h b/lib/if.h
index 1ee6561e8d..6322290937 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -553,6 +553,7 @@ extern struct connected *connected_lookup_prefix(struct interface *,
struct prefix *);
extern struct connected *connected_lookup_prefix_exact(struct interface *,
struct prefix *);
+extern unsigned int connected_count_by_family(struct interface *, int family);
extern struct nbr_connected *nbr_connected_new(void);
extern void nbr_connected_free(struct nbr_connected *);
struct nbr_connected *nbr_connected_check(struct interface *, struct prefix *);
diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c
index f0500601b0..4e7a0050aa 100644
--- a/ospf6d/ospf6_bfd.c
+++ b/ospf6d/ospf6_bfd.c
@@ -236,7 +236,7 @@ static int ospf6_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
continue;
old_status = bfd_info->status;
- bfd_info->status = status;
+ BFD_SET_CLIENT_STATUS(bfd_info->status, status);
monotime(&tv);
bfd_info->last_update = tv.tv_sec;
diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c
index a17975270a..73802ce13e 100644
--- a/ospfd/ospf_bfd.c
+++ b/ospfd/ospf_bfd.c
@@ -240,7 +240,7 @@ static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
continue;
old_status = bfd_info->status;
- bfd_info->status = status;
+ BFD_SET_CLIENT_STATUS(bfd_info->status, status);
monotime(&tv);
bfd_info->last_update = tv.tv_sec;
diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c
index 87d0f9fa22..01a7980858 100644
--- a/pimd/pim_bfd.c
+++ b/pimd/pim_bfd.c
@@ -270,7 +270,7 @@ static int pim_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
continue;
}
old_status = bfd_info->status;
- bfd_info->status = status;
+ BFD_SET_CLIENT_STATUS(bfd_info->status, status);
monotime(&tv);
bfd_info->last_update = tv.tv_sec;
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 6624974c96..e5686a94f4 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -6341,6 +6341,7 @@ static int pim_ssm_cmd_worker(struct pim_instance *pim, struct vty *vty,
const char *plist)
{
int result = pim_ssm_range_set(pim, pim->vrf_id, plist);
+ int ret = CMD_WARNING_CONFIG_FAILED;
if (result == PIM_SSM_ERR_NONE)
return CMD_SUCCESS;
@@ -6351,12 +6352,13 @@ static int pim_ssm_cmd_worker(struct pim_instance *pim, struct vty *vty,
break;
case PIM_SSM_ERR_DUP:
vty_out(vty, "%% duplicate config\n");
+ ret = CMD_WARNING;
break;
default:
vty_out(vty, "%% ssm range config failed\n");
}
- return CMD_WARNING_CONFIG_FAILED;
+ return ret;
}
DEFUN (ip_pim_ssm_prefix_list,
diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c
index 627d3d1993..5c26c0cef7 100644
--- a/ripd/rip_cli.c
+++ b/ripd/rip_cli.c
@@ -29,7 +29,7 @@
#include "libfrr.h"
#include "ripd/ripd.h"
-#include "ripd/rip_cli.h"
+#include "ripd/rip_nb.h"
#ifndef VTYSH_EXTRACT_PL
#include "ripd/rip_cli_clippy.c"
#endif
diff --git a/ripd/rip_cli.h b/ripd/rip_cli.h
deleted file mode 100644
index ef1e1504e8..0000000000
--- a/ripd/rip_cli.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
- * Copyright (C) 2018 NetDEF, Inc.
- * Renato Westphal
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _FRR_RIP_CLI_H_
-#define _FRR_RIP_CLI_H_
-
-extern void cli_show_router_rip(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_allow_ecmp(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_default_information_originate(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_default_metric(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_distance(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_distance_source(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_neighbor(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_network_prefix(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_network_interface(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_offset_list(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_passive_default(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_passive_interface(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_non_passive_interface(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_redistribute(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_route(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_timers(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_rip_version(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ip_rip_split_horizon(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ip_rip_v2_broadcast(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ip_rip_receive_version(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ip_rip_send_version(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ip_rip_authentication_scheme(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ip_rip_authentication_string(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ip_rip_authentication_key_chain(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-
-#endif /* _FRR_RIP_CLI_H_ */
diff --git a/ripd/rip_main.c b/ripd/rip_main.c
index 773cb1d0fe..08cc515856 100644
--- a/ripd/rip_main.c
+++ b/ripd/rip_main.c
@@ -38,6 +38,7 @@
#include "libfrr.h"
#include "ripd/ripd.h"
+#include "ripd/rip_nb.h"
#include "ripd/rip_errors.h"
/* ripd options. */
diff --git a/ripd/rip_nb.c b/ripd/rip_nb.c
new file mode 100644
index 0000000000..4716041ad6
--- /dev/null
+++ b/ripd/rip_nb.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripd/rip_nb.h"
+
+/* clang-format off */
+const struct frr_yang_module_info frr_ripd_info = {
+ .name = "frr-ripd",
+ .nodes = {
+ {
+ .xpath = "/frr-ripd:ripd/instance",
+ .cbs = {
+ .cli_show = cli_show_router_rip,
+ .create = ripd_instance_create,
+ .destroy = ripd_instance_destroy,
+ .get_keys = ripd_instance_get_keys,
+ .get_next = ripd_instance_get_next,
+ .lookup_entry = ripd_instance_lookup_entry,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/allow-ecmp",
+ .cbs = {
+ .cli_show = cli_show_rip_allow_ecmp,
+ .modify = ripd_instance_allow_ecmp_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/default-information-originate",
+ .cbs = {
+ .cli_show = cli_show_rip_default_information_originate,
+ .modify = ripd_instance_default_information_originate_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/default-metric",
+ .cbs = {
+ .cli_show = cli_show_rip_default_metric,
+ .modify = ripd_instance_default_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/distance/default",
+ .cbs = {
+ .cli_show = cli_show_rip_distance,
+ .modify = ripd_instance_distance_default_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/distance/source",
+ .cbs = {
+ .cli_show = cli_show_rip_distance_source,
+ .create = ripd_instance_distance_source_create,
+ .destroy = ripd_instance_distance_source_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/distance/source/distance",
+ .cbs = {
+ .modify = ripd_instance_distance_source_distance_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/distance/source/access-list",
+ .cbs = {
+ .destroy = ripd_instance_distance_source_access_list_destroy,
+ .modify = ripd_instance_distance_source_access_list_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/explicit-neighbor",
+ .cbs = {
+ .cli_show = cli_show_rip_neighbor,
+ .create = ripd_instance_explicit_neighbor_create,
+ .destroy = ripd_instance_explicit_neighbor_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/network",
+ .cbs = {
+ .cli_show = cli_show_rip_network_prefix,
+ .create = ripd_instance_network_create,
+ .destroy = ripd_instance_network_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/interface",
+ .cbs = {
+ .cli_show = cli_show_rip_network_interface,
+ .create = ripd_instance_interface_create,
+ .destroy = ripd_instance_interface_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/offset-list",
+ .cbs = {
+ .cli_show = cli_show_rip_offset_list,
+ .create = ripd_instance_offset_list_create,
+ .destroy = ripd_instance_offset_list_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/offset-list/access-list",
+ .cbs = {
+ .modify = ripd_instance_offset_list_access_list_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/offset-list/metric",
+ .cbs = {
+ .modify = ripd_instance_offset_list_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/passive-default",
+ .cbs = {
+ .cli_show = cli_show_rip_passive_default,
+ .modify = ripd_instance_passive_default_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/passive-interface",
+ .cbs = {
+ .cli_show = cli_show_rip_passive_interface,
+ .create = ripd_instance_passive_interface_create,
+ .destroy = ripd_instance_passive_interface_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/non-passive-interface",
+ .cbs = {
+ .cli_show = cli_show_rip_non_passive_interface,
+ .create = ripd_instance_non_passive_interface_create,
+ .destroy = ripd_instance_non_passive_interface_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/redistribute",
+ .cbs = {
+ .apply_finish = ripd_instance_redistribute_apply_finish,
+ .cli_show = cli_show_rip_redistribute,
+ .create = ripd_instance_redistribute_create,
+ .destroy = ripd_instance_redistribute_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/redistribute/route-map",
+ .cbs = {
+ .destroy = ripd_instance_redistribute_route_map_destroy,
+ .modify = ripd_instance_redistribute_route_map_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/redistribute/metric",
+ .cbs = {
+ .destroy = ripd_instance_redistribute_metric_destroy,
+ .modify = ripd_instance_redistribute_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/static-route",
+ .cbs = {
+ .cli_show = cli_show_rip_route,
+ .create = ripd_instance_static_route_create,
+ .destroy = ripd_instance_static_route_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/timers",
+ .cbs = {
+ .apply_finish = ripd_instance_timers_apply_finish,
+ .cli_show = cli_show_rip_timers,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/timers/flush-interval",
+ .cbs = {
+ .modify = ripd_instance_timers_flush_interval_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/timers/holddown-interval",
+ .cbs = {
+ .modify = ripd_instance_timers_holddown_interval_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/timers/update-interval",
+ .cbs = {
+ .modify = ripd_instance_timers_update_interval_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/version",
+ .cbs = {
+ .cli_show = cli_show_rip_version,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/version/receive",
+ .cbs = {
+ .modify = ripd_instance_version_receive_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/version/send",
+ .cbs = {
+ .modify = ripd_instance_version_send_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/split-horizon",
+ .cbs = {
+ .cli_show = cli_show_ip_rip_split_horizon,
+ .modify = lib_interface_rip_split_horizon_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/v2-broadcast",
+ .cbs = {
+ .cli_show = cli_show_ip_rip_v2_broadcast,
+ .modify = lib_interface_rip_v2_broadcast_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-receive",
+ .cbs = {
+ .cli_show = cli_show_ip_rip_receive_version,
+ .modify = lib_interface_rip_version_receive_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-send",
+ .cbs = {
+ .cli_show = cli_show_ip_rip_send_version,
+ .modify = lib_interface_rip_version_send_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme",
+ .cbs = {
+ .cli_show = cli_show_ip_rip_authentication_scheme,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/mode",
+ .cbs = {
+ .modify = lib_interface_rip_authentication_scheme_mode_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length",
+ .cbs = {
+ .destroy = lib_interface_rip_authentication_scheme_md5_auth_length_destroy,
+ .modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password",
+ .cbs = {
+ .cli_show = cli_show_ip_rip_authentication_string,
+ .destroy = lib_interface_rip_authentication_password_destroy,
+ .modify = lib_interface_rip_authentication_password_modify,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain",
+ .cbs = {
+ .cli_show = cli_show_ip_rip_authentication_key_chain,
+ .destroy = lib_interface_rip_authentication_key_chain_destroy,
+ .modify = lib_interface_rip_authentication_key_chain_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor",
+ .cbs = {
+ .get_keys = ripd_instance_state_neighbors_neighbor_get_keys,
+ .get_next = ripd_instance_state_neighbors_neighbor_get_next,
+ .lookup_entry = ripd_instance_state_neighbors_neighbor_lookup_entry,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/address",
+ .cbs = {
+ .get_elem = ripd_instance_state_neighbors_neighbor_address_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/last-update",
+ .cbs = {
+ .get_elem = ripd_instance_state_neighbors_neighbor_last_update_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/bad-packets-rcvd",
+ .cbs = {
+ .get_elem = ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/bad-routes-rcvd",
+ .cbs = {
+ .get_elem = ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/routes/route",
+ .cbs = {
+ .get_keys = ripd_instance_state_routes_route_get_keys,
+ .get_next = ripd_instance_state_routes_route_get_next,
+ .lookup_entry = ripd_instance_state_routes_route_lookup_entry,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/routes/route/prefix",
+ .cbs = {
+ .get_elem = ripd_instance_state_routes_route_prefix_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/routes/route/next-hop",
+ .cbs = {
+ .get_elem = ripd_instance_state_routes_route_next_hop_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/routes/route/interface",
+ .cbs = {
+ .get_elem = ripd_instance_state_routes_route_interface_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:ripd/instance/state/routes/route/metric",
+ .cbs = {
+ .get_elem = ripd_instance_state_routes_route_metric_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripd:clear-rip-route",
+ .cbs = {
+ .rpc = clear_rip_route_rpc,
+ },
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/ripd/rip_nb.h b/ripd/rip_nb.h
new file mode 100644
index 0000000000..441b253fea
--- /dev/null
+++ b/ripd/rip_nb.h
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_RIP_NB_H_
+#define _FRR_RIP_NB_H_
+
+extern const struct frr_yang_module_info frr_ripd_info;
+
+/* Mandatory callbacks. */
+int ripd_instance_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_destroy(enum nb_event event, const struct lyd_node *dnode);
+const void *ripd_instance_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int ripd_instance_get_keys(const void *list_entry, struct yang_list_keys *keys);
+const void *ripd_instance_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+int ripd_instance_allow_ecmp_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_default_information_originate_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_default_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_distance_default_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_distance_source_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_distance_source_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_distance_source_distance_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_distance_source_access_list_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_distance_source_access_list_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int ripd_instance_explicit_neighbor_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_explicit_neighbor_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_network_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_network_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_offset_list_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_offset_list_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_offset_list_access_list_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_offset_list_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_passive_default_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_passive_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_passive_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_non_passive_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_non_passive_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_redistribute_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_redistribute_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_redistribute_route_map_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_redistribute_route_map_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_redistribute_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_redistribute_metric_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_static_route_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_static_route_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripd_instance_timers_flush_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_timers_holddown_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_timers_update_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_version_receive_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripd_instance_version_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+const void *
+ripd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int ripd_instance_state_neighbors_neighbor_get_keys(
+ const void *list_entry, struct yang_list_keys *keys);
+const void *ripd_instance_state_neighbors_neighbor_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *
+ripd_instance_state_neighbors_neighbor_address_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *ripd_instance_state_neighbors_neighbor_last_update_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
+ const char *xpath, const void *list_entry);
+const void *
+ripd_instance_state_routes_route_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int ripd_instance_state_routes_route_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *ripd_instance_state_routes_route_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *
+ripd_instance_state_routes_route_prefix_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+ripd_instance_state_routes_route_next_hop_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+ripd_instance_state_routes_route_interface_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+ripd_instance_state_routes_route_metric_get_elem(const char *xpath,
+ const void *list_entry);
+int clear_rip_route_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int lib_interface_rip_split_horizon_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_rip_v2_broadcast_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_rip_version_receive_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_rip_version_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_rip_authentication_scheme_mode_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_rip_authentication_scheme_md5_auth_length_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_rip_authentication_scheme_md5_auth_length_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int lib_interface_rip_authentication_password_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_rip_authentication_password_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int lib_interface_rip_authentication_key_chain_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int lib_interface_rip_authentication_key_chain_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+
+/* Optional 'apply_finish' callbacks. */
+void ripd_instance_redistribute_apply_finish(const struct lyd_node *dnode);
+void ripd_instance_timers_apply_finish(const struct lyd_node *dnode);
+
+/* Optional 'cli_show' callbacks. */
+void cli_show_router_rip(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_allow_ecmp(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_default_information_originate(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_default_metric(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_distance(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_distance_source(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_neighbor(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_network_prefix(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_network_interface(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_offset_list(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_passive_default(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_passive_interface(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_non_passive_interface(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_redistribute(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_route(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_timers(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_rip_version(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_rip_split_horizon(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_rip_v2_broadcast(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_rip_receive_version(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_rip_send_version(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_rip_authentication_scheme(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_rip_authentication_string(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ip_rip_authentication_key_chain(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+
+/* Notifications. */
+extern void ripd_notif_send_auth_type_failure(const char *ifname);
+extern void ripd_notif_send_auth_failure(const char *ifname);
+
+#endif /* _FRR_RIP_NB_H_ */
diff --git a/ripd/rip_nb_config.c b/ripd/rip_nb_config.c
new file mode 100644
index 0000000000..e75db342af
--- /dev/null
+++ b/ripd/rip_nb_config.c
@@ -0,0 +1,1099 @@
+/*
+ * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vrf.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "routemap.h"
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_nb.h"
+#include "ripd/rip_debug.h"
+#include "ripd/rip_interface.h"
+
+/*
+ * XPath: /frr-ripd:ripd/instance
+ */
+int ripd_instance_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ struct vrf *vrf;
+ const char *vrf_name;
+ int socket;
+
+ vrf_name = yang_dnode_get_string(dnode, "./vrf");
+ vrf = vrf_lookup_by_name(vrf_name);
+
+ /*
+ * Try to create a RIP socket only if the VRF is enabled, otherwise
+ * create a disabled RIP instance and wait for the VRF to be enabled.
+ */
+ switch (event) {
+ case NB_EV_VALIDATE:
+ break;
+ case NB_EV_PREPARE:
+ if (!vrf || !vrf_is_enabled(vrf))
+ break;
+
+ socket = rip_create_socket(vrf);
+ if (socket < 0)
+ return NB_ERR_RESOURCE;
+ resource->fd = socket;
+ break;
+ case NB_EV_ABORT:
+ if (!vrf || !vrf_is_enabled(vrf))
+ break;
+
+ socket = resource->fd;
+ close(socket);
+ break;
+ case NB_EV_APPLY:
+ if (vrf && vrf_is_enabled(vrf))
+ socket = resource->fd;
+ else
+ socket = -1;
+
+ rip = rip_create(vrf_name, vrf, socket);
+ nb_running_set_entry(dnode, rip);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int ripd_instance_destroy(enum nb_event event, const struct lyd_node *dnode)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_unset_entry(dnode);
+ rip_clean(rip);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/allow-ecmp
+ */
+int ripd_instance_allow_ecmp_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->ecmp = yang_dnode_get_bool(dnode, NULL);
+ if (!rip->ecmp)
+ rip_ecmp_disable(rip);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/default-information-originate
+ */
+int ripd_instance_default_information_originate_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ bool default_information;
+ struct prefix_ipv4 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ default_information = yang_dnode_get_bool(dnode, NULL);
+
+ memset(&p, 0, sizeof(struct prefix_ipv4));
+ p.family = AF_INET;
+ if (default_information) {
+ struct nexthop nh;
+
+ memset(&nh, 0, sizeof(nh));
+ nh.type = NEXTHOP_TYPE_IPV4;
+ rip_redistribute_add(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT,
+ &p, &nh, 0, 0, 0);
+ } else {
+ rip_redistribute_delete(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT,
+ &p, 0);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/default-metric
+ */
+int ripd_instance_default_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->default_metric = yang_dnode_get_uint8(dnode, NULL);
+ /* rip_update_default_metric (); */
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/distance/default
+ */
+int ripd_instance_distance_default_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->distance = yang_dnode_get_uint8(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/distance/source
+ */
+int ripd_instance_distance_source_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ struct prefix_ipv4 prefix;
+ struct route_node *rn;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ yang_dnode_get_ipv4p(&prefix, dnode, "./prefix");
+ apply_mask_ipv4(&prefix);
+
+ /* Get RIP distance node. */
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rn = route_node_get(rip->distance_table, (struct prefix *)&prefix);
+ rn->info = rip_distance_new();
+ nb_running_set_entry(dnode, rn);
+
+ return NB_OK;
+}
+
+int ripd_instance_distance_source_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct route_node *rn;
+ struct rip_distance *rdistance;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rn = nb_running_unset_entry(dnode);
+ rdistance = rn->info;
+ rip_distance_free(rdistance);
+ rn->info = NULL;
+ route_unlock_node(rn);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/distance/source/distance
+ */
+int ripd_instance_distance_source_distance_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct route_node *rn;
+ uint8_t distance;
+ struct rip_distance *rdistance;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Set distance value. */
+ rn = nb_running_get_entry(dnode, NULL, true);
+ distance = yang_dnode_get_uint8(dnode, NULL);
+ rdistance = rn->info;
+ rdistance->distance = distance;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/distance/source/access-list
+ */
+int ripd_instance_distance_source_access_list_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ const char *acl_name;
+ struct route_node *rn;
+ struct rip_distance *rdistance;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ acl_name = yang_dnode_get_string(dnode, NULL);
+
+ /* Set access-list */
+ rn = nb_running_get_entry(dnode, NULL, true);
+ rdistance = rn->info;
+ if (rdistance->access_list)
+ free(rdistance->access_list);
+ rdistance->access_list = strdup(acl_name);
+
+ return NB_OK;
+}
+
+int ripd_instance_distance_source_access_list_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ struct route_node *rn;
+ struct rip_distance *rdistance;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* Reset access-list configuration. */
+ rn = nb_running_get_entry(dnode, NULL, true);
+ rdistance = rn->info;
+ free(rdistance->access_list);
+ rdistance->access_list = NULL;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/explicit-neighbor
+ */
+int ripd_instance_explicit_neighbor_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ struct prefix_ipv4 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
+
+ return rip_neighbor_add(rip, &p);
+}
+
+int ripd_instance_explicit_neighbor_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ struct prefix_ipv4 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
+
+ return rip_neighbor_delete(rip, &p);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/network
+ */
+int ripd_instance_network_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ struct prefix p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv4p(&p, dnode, NULL);
+ apply_mask_ipv4((struct prefix_ipv4 *)&p);
+
+ return rip_enable_network_add(rip, &p);
+}
+
+int ripd_instance_network_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ struct prefix p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv4p(&p, dnode, NULL);
+ apply_mask_ipv4((struct prefix_ipv4 *)&p);
+
+ return rip_enable_network_delete(rip, &p);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/interface
+ */
+int ripd_instance_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return rip_enable_if_add(rip, ifname);
+}
+
+int ripd_instance_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return rip_enable_if_delete(rip, ifname);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/offset-list
+ */
+int ripd_instance_offset_list_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ const char *ifname;
+ struct rip_offset_list *offset;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, "./interface");
+
+ offset = rip_offset_list_new(rip, ifname);
+ nb_running_set_entry(dnode, offset);
+
+ return NB_OK;
+}
+
+int ripd_instance_offset_list_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ int direct;
+ struct rip_offset_list *offset;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ direct = yang_dnode_get_enum(dnode, "./direction");
+
+ offset = nb_running_unset_entry(dnode);
+ if (offset->direct[direct].alist_name) {
+ free(offset->direct[direct].alist_name);
+ offset->direct[direct].alist_name = NULL;
+ }
+ if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL
+ && offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL)
+ offset_list_del(offset);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/offset-list/access-list
+ */
+int ripd_instance_offset_list_access_list_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ int direct;
+ struct rip_offset_list *offset;
+ const char *alist_name;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ direct = yang_dnode_get_enum(dnode, "../direction");
+ alist_name = yang_dnode_get_string(dnode, NULL);
+
+ offset = nb_running_get_entry(dnode, NULL, true);
+ if (offset->direct[direct].alist_name)
+ free(offset->direct[direct].alist_name);
+ offset->direct[direct].alist_name = strdup(alist_name);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/offset-list/metric
+ */
+int ripd_instance_offset_list_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ int direct;
+ uint8_t metric;
+ struct rip_offset_list *offset;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ direct = yang_dnode_get_enum(dnode, "../direction");
+ metric = yang_dnode_get_uint8(dnode, NULL);
+
+ offset = nb_running_get_entry(dnode, NULL, true);
+ offset->direct[direct].metric = metric;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/passive-default
+ */
+int ripd_instance_passive_default_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->passive_default = yang_dnode_get_bool(dnode, NULL);
+ rip_passive_nondefault_clean(rip);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/passive-interface
+ */
+int ripd_instance_passive_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return rip_passive_nondefault_set(rip, ifname);
+}
+
+int ripd_instance_passive_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return rip_passive_nondefault_unset(rip, ifname);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/non-passive-interface
+ */
+int ripd_instance_non_passive_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return rip_passive_nondefault_unset(rip, ifname);
+}
+
+int ripd_instance_non_passive_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return rip_passive_nondefault_set(rip, ifname);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/redistribute
+ */
+int ripd_instance_redistribute_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "./protocol");
+
+ rip->redist[type].enabled = true;
+
+ return NB_OK;
+}
+
+int ripd_instance_redistribute_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "./protocol");
+
+ rip->redist[type].enabled = false;
+ if (rip->redist[type].route_map.name) {
+ free(rip->redist[type].route_map.name);
+ rip->redist[type].route_map.name = NULL;
+ rip->redist[type].route_map.map = NULL;
+ }
+ rip->redist[type].metric_config = false;
+ rip->redist[type].metric = 0;
+
+ if (rip->enabled)
+ rip_redistribute_conf_delete(rip, type);
+
+ return NB_OK;
+}
+
+void ripd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ int type;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "./protocol");
+
+ if (rip->enabled)
+ rip_redistribute_conf_update(rip, type);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/redistribute/route-map
+ */
+int ripd_instance_redistribute_route_map_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ int type;
+ const char *rmap_name;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "../protocol");
+ rmap_name = yang_dnode_get_string(dnode, NULL);
+
+ if (rip->redist[type].route_map.name)
+ free(rip->redist[type].route_map.name);
+ rip->redist[type].route_map.name = strdup(rmap_name);
+ rip->redist[type].route_map.map = route_map_lookup_by_name(rmap_name);
+
+ return NB_OK;
+}
+
+int ripd_instance_redistribute_route_map_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "../protocol");
+
+ free(rip->redist[type].route_map.name);
+ rip->redist[type].route_map.name = NULL;
+ rip->redist[type].route_map.map = NULL;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/redistribute/metric
+ */
+int ripd_instance_redistribute_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ int type;
+ uint8_t metric;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "../protocol");
+ metric = yang_dnode_get_uint8(dnode, NULL);
+
+ rip->redist[type].metric_config = true;
+ rip->redist[type].metric = metric;
+
+ return NB_OK;
+}
+
+int ripd_instance_redistribute_metric_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "../protocol");
+
+ rip->redist[type].metric_config = false;
+ rip->redist[type].metric = 0;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/static-route
+ */
+int ripd_instance_static_route_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+ struct nexthop nh;
+ struct prefix_ipv4 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv4p(&p, dnode, NULL);
+ apply_mask_ipv4(&p);
+
+ memset(&nh, 0, sizeof(nh));
+ nh.type = NEXTHOP_TYPE_IPV4;
+ rip_redistribute_add(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, &nh, 0,
+ 0, 0);
+
+ return NB_OK;
+}
+
+int ripd_instance_static_route_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct rip *rip;
+ struct prefix_ipv4 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv4p(&p, dnode, NULL);
+ apply_mask_ipv4(&p);
+
+ rip_redistribute_delete(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/timers/
+ */
+void ripd_instance_timers_apply_finish(const struct lyd_node *dnode)
+{
+ struct rip *rip;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+
+ /* Reset update timer thread. */
+ rip_event(rip, RIP_UPDATE_EVENT, 0);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/timers/flush-interval
+ */
+int ripd_instance_timers_flush_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->garbage_time = yang_dnode_get_uint32(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/timers/holddown-interval
+ */
+int ripd_instance_timers_holddown_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->timeout_time = yang_dnode_get_uint32(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/timers/update-interval
+ */
+int ripd_instance_timers_update_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->update_time = yang_dnode_get_uint32(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/version/receive
+ */
+int ripd_instance_version_receive_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->version_recv = yang_dnode_get_enum(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/version/send
+ */
+int ripd_instance_version_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct rip *rip;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = nb_running_get_entry(dnode, NULL, true);
+ rip->version_send = yang_dnode_get_enum(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/split-horizon
+ */
+int lib_interface_rip_split_horizon_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ ri->split_horizon = yang_dnode_get_enum(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/v2-broadcast
+ */
+int lib_interface_rip_v2_broadcast_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ ri->v2_broadcast = yang_dnode_get_bool(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/version-receive
+ */
+int lib_interface_rip_version_receive_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ ri->ri_receive = yang_dnode_get_enum(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/version-send
+ */
+int lib_interface_rip_version_send_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ ri->ri_send = yang_dnode_get_enum(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/mode
+ */
+int lib_interface_rip_authentication_scheme_mode_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ ri->auth_type = yang_dnode_get_enum(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length
+ */
+int lib_interface_rip_authentication_scheme_md5_auth_length_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ ri->md5_auth_len = yang_dnode_get_enum(dnode, NULL);
+
+ return NB_OK;
+}
+
+int lib_interface_rip_authentication_scheme_md5_auth_length_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ ri->md5_auth_len = yang_get_default_enum(
+ "%s/authentication-scheme/md5-auth-length", RIP_IFACE);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-password
+ */
+int lib_interface_rip_authentication_password_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
+ ri->auth_str = XSTRDUP(MTYPE_RIP_INTERFACE_STRING,
+ yang_dnode_get_string(dnode, NULL));
+
+ return NB_OK;
+}
+
+int lib_interface_rip_authentication_password_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain
+ */
+int lib_interface_rip_authentication_key_chain_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
+ ri->key_chain = XSTRDUP(MTYPE_RIP_INTERFACE_STRING,
+ yang_dnode_get_string(dnode, NULL));
+
+ return NB_OK;
+}
+
+int lib_interface_rip_authentication_key_chain_destroy(
+ enum nb_event event, const struct lyd_node *dnode)
+{
+ struct interface *ifp;
+ struct rip_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
+
+ return NB_OK;
+}
diff --git a/ripd/rip_nb_notifications.c b/ripd/rip_nb_notifications.c
new file mode 100644
index 0000000000..28d3517dfd
--- /dev/null
+++ b/ripd/rip_nb_notifications.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vrf.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "routemap.h"
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_nb.h"
+#include "ripd/rip_debug.h"
+#include "ripd/rip_interface.h"
+
+/*
+ * XPath: /frr-ripd:authentication-type-failure
+ */
+void ripd_notif_send_auth_type_failure(const char *ifname)
+{
+ const char *xpath = "/frr-ripd:authentication-type-failure";
+ struct list *arguments;
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+
+ arguments = yang_data_list_new();
+
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-name", xpath);
+ data = yang_data_new_string(xpath_arg, ifname);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
+
+/*
+ * XPath: /frr-ripd:authentication-failure
+ */
+void ripd_notif_send_auth_failure(const char *ifname)
+{
+ const char *xpath = "/frr-ripd:authentication-failure";
+ struct list *arguments;
+ char xpath_arg[XPATH_MAXLEN];
+ struct yang_data *data;
+
+ arguments = yang_data_list_new();
+
+ snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-name", xpath);
+ data = yang_data_new_string(xpath_arg, ifname);
+ listnode_add(arguments, data);
+
+ nb_notification_send(xpath, arguments);
+}
diff --git a/ripd/rip_nb_rpcs.c b/ripd/rip_nb_rpcs.c
new file mode 100644
index 0000000000..0ca85296fd
--- /dev/null
+++ b/ripd/rip_nb_rpcs.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vrf.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "routemap.h"
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_nb.h"
+#include "ripd/rip_debug.h"
+#include "ripd/rip_interface.h"
+
+/*
+ * XPath: /frr-ripd:clear-rip-route
+ */
+static void clear_rip_route(struct rip *rip)
+{
+ struct route_node *rp;
+
+ if (IS_RIP_DEBUG_EVENT)
+ zlog_debug("Clearing all RIP routes (VRF %s)", rip->vrf_name);
+
+ /* Clear received RIP routes */
+ for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
+ struct list *list;
+ struct listnode *listnode;
+ struct rip_info *rinfo;
+
+ list = rp->info;
+ if (!list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
+ if (!rip_route_rte(rinfo))
+ continue;
+
+ if (CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
+ rip_zebra_ipv4_delete(rip, rp);
+ break;
+ }
+
+ if (rinfo) {
+ RIP_TIMER_OFF(rinfo->t_timeout);
+ RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ listnode_delete(list, rinfo);
+ rip_info_free(rinfo);
+ }
+
+ if (list_isempty(list)) {
+ list_delete(&list);
+ rp->info = NULL;
+ route_unlock_node(rp);
+ }
+ }
+}
+
+int clear_rip_route_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ struct rip *rip;
+ struct yang_data *yang_vrf;
+
+ yang_vrf = yang_data_list_find(input, "%s/%s", xpath, "input/vrf");
+ if (yang_vrf) {
+ rip = rip_lookup_by_vrf_name(yang_vrf->value);
+ if (rip)
+ clear_rip_route(rip);
+ } else {
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ rip = vrf->info;
+ if (!rip)
+ continue;
+
+ clear_rip_route(rip);
+ }
+ }
+
+ return NB_OK;
+}
diff --git a/ripd/rip_nb_state.c b/ripd/rip_nb_state.c
new file mode 100644
index 0000000000..2f7eb3cb5e
--- /dev/null
+++ b/ripd/rip_nb_state.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vrf.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "routemap.h"
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripd/ripd.h"
+#include "ripd/rip_nb.h"
+#include "ripd/rip_debug.h"
+#include "ripd/rip_interface.h"
+
+/*
+ * XPath: /frr-ripd:ripd/instance
+ */
+const void *ripd_instance_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ struct rip *rip = (struct rip *)list_entry;
+
+ if (list_entry == NULL)
+ rip = RB_MIN(rip_instance_head, &rip_instances);
+ else
+ rip = RB_NEXT(rip_instance_head, rip);
+
+ return rip;
+}
+
+int ripd_instance_get_keys(const void *list_entry, struct yang_list_keys *keys)
+{
+ const struct rip *rip = list_entry;
+
+ keys->num = 1;
+ strlcpy(keys->key[0], rip->vrf_name, sizeof(keys->key[0]));
+
+ return NB_OK;
+}
+
+const void *ripd_instance_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ const char *vrf_name = keys->key[0];
+
+ return rip_lookup_by_vrf_name(vrf_name);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor
+ */
+const void *
+ripd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ const struct rip *rip = parent_list_entry;
+ struct listnode *node;
+
+ if (list_entry == NULL)
+ node = listhead(rip->peer_list);
+ else
+ node = listnextnode((struct listnode *)list_entry);
+
+ return node;
+}
+
+int ripd_instance_state_neighbors_neighbor_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct listnode *node = list_entry;
+ const struct rip_peer *peer = listgetdata(node);
+
+ keys->num = 1;
+ (void)inet_ntop(AF_INET, &peer->addr, keys->key[0],
+ sizeof(keys->key[0]));
+
+ return NB_OK;
+}
+
+const void *ripd_instance_state_neighbors_neighbor_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys)
+{
+ const struct rip *rip = parent_list_entry;
+ struct in_addr address;
+ struct rip_peer *peer;
+ struct listnode *node;
+
+ yang_str2ipv4(keys->key[0], &address);
+
+ for (ALL_LIST_ELEMENTS_RO(rip->peer_list, node, peer)) {
+ if (IPV4_ADDR_SAME(&peer->addr, &address))
+ return node;
+ }
+
+ return NULL;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/address
+ */
+struct yang_data *
+ripd_instance_state_neighbors_neighbor_address_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct listnode *node = list_entry;
+ const struct rip_peer *peer = listgetdata(node);
+
+ return yang_data_new_ipv4(xpath, &peer->addr);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/last-update
+ */
+struct yang_data *ripd_instance_state_neighbors_neighbor_last_update_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: yang:date-and-time is tricky */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-packets-rcvd
+ */
+struct yang_data *
+ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct listnode *node = list_entry;
+ const struct rip_peer *peer = listgetdata(node);
+
+ return yang_data_new_uint32(xpath, peer->recv_badpackets);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-routes-rcvd
+ */
+struct yang_data *
+ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct listnode *node = list_entry;
+ const struct rip_peer *peer = listgetdata(node);
+
+ return yang_data_new_uint32(xpath, peer->recv_badroutes);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/routes/route
+ */
+const void *
+ripd_instance_state_routes_route_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ const struct rip *rip = parent_list_entry;
+ struct route_node *rn;
+
+ if (list_entry == NULL)
+ rn = route_top(rip->table);
+ else
+ rn = route_next((struct route_node *)list_entry);
+ while (rn && rn->info == NULL)
+ rn = route_next(rn);
+
+ return rn;
+}
+
+int ripd_instance_state_routes_route_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct route_node *rn = list_entry;
+
+ keys->num = 1;
+ (void)prefix2str(&rn->p, keys->key[0], sizeof(keys->key[0]));
+
+ return NB_OK;
+}
+
+const void *
+ripd_instance_state_routes_route_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ const struct rip *rip = parent_list_entry;
+ struct prefix prefix;
+ struct route_node *rn;
+
+ yang_str2ipv4p(keys->key[0], &prefix);
+
+ rn = route_node_lookup(rip->table, &prefix);
+ if (!rn || !rn->info)
+ return NULL;
+
+ route_unlock_node(rn);
+
+ return rn;
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/routes/route/prefix
+ */
+struct yang_data *
+ripd_instance_state_routes_route_prefix_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct route_node *rn = list_entry;
+ const struct rip_info *rinfo = listnode_head(rn->info);
+
+ return yang_data_new_ipv4p(xpath, &rinfo->rp->p);
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/routes/route/next-hop
+ */
+struct yang_data *
+ripd_instance_state_routes_route_next_hop_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct route_node *rn = list_entry;
+ const struct rip_info *rinfo = listnode_head(rn->info);
+
+ switch (rinfo->nh.type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ return yang_data_new_ipv4(xpath, &rinfo->nh.gate.ipv4);
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/routes/route/interface
+ */
+struct yang_data *
+ripd_instance_state_routes_route_interface_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct route_node *rn = list_entry;
+ const struct rip_info *rinfo = listnode_head(rn->info);
+ const struct rip *rip = rip_info_get_instance(rinfo);
+
+ switch (rinfo->nh.type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ return yang_data_new_string(
+ xpath,
+ ifindex2ifname(rinfo->nh.ifindex, rip->vrf->vrf_id));
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * XPath: /frr-ripd:ripd/instance/state/routes/route/metric
+ */
+struct yang_data *
+ripd_instance_state_routes_route_metric_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct route_node *rn = list_entry;
+ const struct rip_info *rinfo = listnode_head(rn->info);
+
+ return yang_data_new_uint8(xpath, rinfo->metric);
+}
diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c
deleted file mode 100644
index 1238d0f0fc..0000000000
--- a/ripd/rip_northbound.c
+++ /dev/null
@@ -1,1823 +0,0 @@
-/*
- * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
- * Copyright (C) 2018 NetDEF, Inc.
- * Renato Westphal
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include "if.h"
-#include "vrf.h"
-#include "log.h"
-#include "prefix.h"
-#include "table.h"
-#include "command.h"
-#include "routemap.h"
-#include "northbound.h"
-#include "libfrr.h"
-
-#include "ripd/ripd.h"
-#include "ripd/rip_debug.h"
-#include "ripd/rip_cli.h"
-#include "ripd/rip_interface.h"
-
-/*
- * XPath: /frr-ripd:ripd/instance
- */
-static int ripd_instance_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- struct vrf *vrf;
- const char *vrf_name;
- int socket;
-
- vrf_name = yang_dnode_get_string(dnode, "./vrf");
- vrf = vrf_lookup_by_name(vrf_name);
-
- /*
- * Try to create a RIP socket only if the VRF is enabled, otherwise
- * create a disabled RIP instance and wait for the VRF to be enabled.
- */
- switch (event) {
- case NB_EV_VALIDATE:
- break;
- case NB_EV_PREPARE:
- if (!vrf || !vrf_is_enabled(vrf))
- break;
-
- socket = rip_create_socket(vrf);
- if (socket < 0)
- return NB_ERR_RESOURCE;
- resource->fd = socket;
- break;
- case NB_EV_ABORT:
- if (!vrf || !vrf_is_enabled(vrf))
- break;
-
- socket = resource->fd;
- close(socket);
- break;
- case NB_EV_APPLY:
- if (vrf && vrf_is_enabled(vrf))
- socket = resource->fd;
- else
- socket = -1;
-
- rip = rip_create(vrf_name, vrf, socket);
- nb_running_set_entry(dnode, rip);
- break;
- }
-
- return NB_OK;
-}
-
-static int ripd_instance_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_unset_entry(dnode);
- rip_clean(rip);
-
- return NB_OK;
-}
-
-static const void *ripd_instance_get_next(const void *parent_list_entry,
- const void *list_entry)
-{
- struct rip *rip = (struct rip *)list_entry;
-
- if (list_entry == NULL)
- rip = RB_MIN(rip_instance_head, &rip_instances);
- else
- rip = RB_NEXT(rip_instance_head, rip);
-
- return rip;
-}
-
-static int ripd_instance_get_keys(const void *list_entry,
- struct yang_list_keys *keys)
-{
- const struct rip *rip = list_entry;
-
- keys->num = 1;
- strlcpy(keys->key[0], rip->vrf_name, sizeof(keys->key[0]));
-
- return NB_OK;
-}
-
-static const void *ripd_instance_lookup_entry(const void *parent_list_entry,
- const struct yang_list_keys *keys)
-{
- const char *vrf_name = keys->key[0];
-
- return rip_lookup_by_vrf_name(vrf_name);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/allow-ecmp
- */
-static int ripd_instance_allow_ecmp_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->ecmp = yang_dnode_get_bool(dnode, NULL);
- if (!rip->ecmp)
- rip_ecmp_disable(rip);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/default-information-originate
- */
-static int
-ripd_instance_default_information_originate_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- bool default_information;
- struct prefix_ipv4 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- default_information = yang_dnode_get_bool(dnode, NULL);
-
- memset(&p, 0, sizeof(struct prefix_ipv4));
- p.family = AF_INET;
- if (default_information) {
- struct nexthop nh;
-
- memset(&nh, 0, sizeof(nh));
- nh.type = NEXTHOP_TYPE_IPV4;
- rip_redistribute_add(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT,
- &p, &nh, 0, 0, 0);
- } else {
- rip_redistribute_delete(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT,
- &p, 0);
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/default-metric
- */
-static int ripd_instance_default_metric_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->default_metric = yang_dnode_get_uint8(dnode, NULL);
- /* rip_update_default_metric (); */
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/distance/default
- */
-static int ripd_instance_distance_default_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->distance = yang_dnode_get_uint8(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/distance/source
- */
-static int ripd_instance_distance_source_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- struct prefix_ipv4 prefix;
- struct route_node *rn;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- yang_dnode_get_ipv4p(&prefix, dnode, "./prefix");
- apply_mask_ipv4(&prefix);
-
- /* Get RIP distance node. */
- rip = nb_running_get_entry(dnode, NULL, true);
- rn = route_node_get(rip->distance_table, (struct prefix *)&prefix);
- rn->info = rip_distance_new();
- nb_running_set_entry(dnode, rn);
-
- return NB_OK;
-}
-
-static int ripd_instance_distance_source_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct route_node *rn;
- struct rip_distance *rdistance;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rn = nb_running_unset_entry(dnode);
- rdistance = rn->info;
- rip_distance_free(rdistance);
- rn->info = NULL;
- route_unlock_node(rn);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/distance/source/distance
- */
-static int
-ripd_instance_distance_source_distance_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct route_node *rn;
- uint8_t distance;
- struct rip_distance *rdistance;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- /* Set distance value. */
- rn = nb_running_get_entry(dnode, NULL, true);
- distance = yang_dnode_get_uint8(dnode, NULL);
- rdistance = rn->info;
- rdistance->distance = distance;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/distance/source/access-list
- */
-static int
-ripd_instance_distance_source_access_list_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- const char *acl_name;
- struct route_node *rn;
- struct rip_distance *rdistance;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- acl_name = yang_dnode_get_string(dnode, NULL);
-
- /* Set access-list */
- rn = nb_running_get_entry(dnode, NULL, true);
- rdistance = rn->info;
- if (rdistance->access_list)
- free(rdistance->access_list);
- rdistance->access_list = strdup(acl_name);
-
- return NB_OK;
-}
-
-static int
-ripd_instance_distance_source_access_list_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct route_node *rn;
- struct rip_distance *rdistance;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- /* Reset access-list configuration. */
- rn = nb_running_get_entry(dnode, NULL, true);
- rdistance = rn->info;
- free(rdistance->access_list);
- rdistance->access_list = NULL;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/explicit-neighbor
- */
-static int ripd_instance_explicit_neighbor_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- struct prefix_ipv4 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- p.family = AF_INET;
- p.prefixlen = IPV4_MAX_BITLEN;
- yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
-
- return rip_neighbor_add(rip, &p);
-}
-
-static int ripd_instance_explicit_neighbor_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- struct prefix_ipv4 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- p.family = AF_INET;
- p.prefixlen = IPV4_MAX_BITLEN;
- yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
-
- return rip_neighbor_delete(rip, &p);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/network
- */
-static int ripd_instance_network_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- struct prefix p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv4p(&p, dnode, NULL);
- apply_mask_ipv4((struct prefix_ipv4 *)&p);
-
- return rip_enable_network_add(rip, &p);
-}
-
-static int ripd_instance_network_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- struct prefix p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv4p(&p, dnode, NULL);
- apply_mask_ipv4((struct prefix_ipv4 *)&p);
-
- return rip_enable_network_delete(rip, &p);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/interface
- */
-static int ripd_instance_interface_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return rip_enable_if_add(rip, ifname);
-}
-
-static int ripd_instance_interface_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return rip_enable_if_delete(rip, ifname);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/offset-list
- */
-static int ripd_instance_offset_list_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- const char *ifname;
- struct rip_offset_list *offset;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, "./interface");
-
- offset = rip_offset_list_new(rip, ifname);
- nb_running_set_entry(dnode, offset);
-
- return NB_OK;
-}
-
-static int ripd_instance_offset_list_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- int direct;
- struct rip_offset_list *offset;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- direct = yang_dnode_get_enum(dnode, "./direction");
-
- offset = nb_running_unset_entry(dnode);
- if (offset->direct[direct].alist_name) {
- free(offset->direct[direct].alist_name);
- offset->direct[direct].alist_name = NULL;
- }
- if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL
- && offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL)
- offset_list_del(offset);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/offset-list/access-list
- */
-static int
-ripd_instance_offset_list_access_list_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- int direct;
- struct rip_offset_list *offset;
- const char *alist_name;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- direct = yang_dnode_get_enum(dnode, "../direction");
- alist_name = yang_dnode_get_string(dnode, NULL);
-
- offset = nb_running_get_entry(dnode, NULL, true);
- if (offset->direct[direct].alist_name)
- free(offset->direct[direct].alist_name);
- offset->direct[direct].alist_name = strdup(alist_name);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/offset-list/metric
- */
-static int ripd_instance_offset_list_metric_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- int direct;
- uint8_t metric;
- struct rip_offset_list *offset;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- direct = yang_dnode_get_enum(dnode, "../direction");
- metric = yang_dnode_get_uint8(dnode, NULL);
-
- offset = nb_running_get_entry(dnode, NULL, true);
- offset->direct[direct].metric = metric;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/passive-default
- */
-static int ripd_instance_passive_default_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->passive_default = yang_dnode_get_bool(dnode, NULL);
- rip_passive_nondefault_clean(rip);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/passive-interface
- */
-static int ripd_instance_passive_interface_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return rip_passive_nondefault_set(rip, ifname);
-}
-
-static int ripd_instance_passive_interface_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return rip_passive_nondefault_unset(rip, ifname);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/non-passive-interface
- */
-static int
-ripd_instance_non_passive_interface_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return rip_passive_nondefault_unset(rip, ifname);
-}
-
-static int
-ripd_instance_non_passive_interface_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return rip_passive_nondefault_set(rip, ifname);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/redistribute
- */
-static int ripd_instance_redistribute_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "./protocol");
-
- rip->redist[type].enabled = true;
-
- return NB_OK;
-}
-
-static int ripd_instance_redistribute_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "./protocol");
-
- rip->redist[type].enabled = false;
- if (rip->redist[type].route_map.name) {
- free(rip->redist[type].route_map.name);
- rip->redist[type].route_map.name = NULL;
- rip->redist[type].route_map.map = NULL;
- }
- rip->redist[type].metric_config = false;
- rip->redist[type].metric = 0;
-
- if (rip->enabled)
- rip_redistribute_conf_delete(rip, type);
-
- return NB_OK;
-}
-
-static void
-ripd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
-{
- struct rip *rip;
- int type;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "./protocol");
-
- if (rip->enabled)
- rip_redistribute_conf_update(rip, type);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/redistribute/route-map
- */
-static int
-ripd_instance_redistribute_route_map_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- int type;
- const char *rmap_name;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "../protocol");
- rmap_name = yang_dnode_get_string(dnode, NULL);
-
- if (rip->redist[type].route_map.name)
- free(rip->redist[type].route_map.name);
- rip->redist[type].route_map.name = strdup(rmap_name);
- rip->redist[type].route_map.map = route_map_lookup_by_name(rmap_name);
-
- return NB_OK;
-}
-
-static int
-ripd_instance_redistribute_route_map_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "../protocol");
-
- free(rip->redist[type].route_map.name);
- rip->redist[type].route_map.name = NULL;
- rip->redist[type].route_map.map = NULL;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/redistribute/metric
- */
-static int
-ripd_instance_redistribute_metric_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- int type;
- uint8_t metric;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "../protocol");
- metric = yang_dnode_get_uint8(dnode, NULL);
-
- rip->redist[type].metric_config = true;
- rip->redist[type].metric = metric;
-
- return NB_OK;
-}
-
-static int
-ripd_instance_redistribute_metric_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "../protocol");
-
- rip->redist[type].metric_config = false;
- rip->redist[type].metric = 0;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/static-route
- */
-static int ripd_instance_static_route_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
- struct nexthop nh;
- struct prefix_ipv4 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv4p(&p, dnode, NULL);
- apply_mask_ipv4(&p);
-
- memset(&nh, 0, sizeof(nh));
- nh.type = NEXTHOP_TYPE_IPV4;
- rip_redistribute_add(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, &nh, 0,
- 0, 0);
-
- return NB_OK;
-}
-
-static int ripd_instance_static_route_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct rip *rip;
- struct prefix_ipv4 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv4p(&p, dnode, NULL);
- apply_mask_ipv4(&p);
-
- rip_redistribute_delete(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/timers/
- */
-static void ripd_instance_timers_apply_finish(const struct lyd_node *dnode)
-{
- struct rip *rip;
-
- rip = nb_running_get_entry(dnode, NULL, true);
-
- /* Reset update timer thread. */
- rip_event(rip, RIP_UPDATE_EVENT, 0);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/timers/flush-interval
- */
-static int
-ripd_instance_timers_flush_interval_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->garbage_time = yang_dnode_get_uint32(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/timers/holddown-interval
- */
-static int
-ripd_instance_timers_holddown_interval_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->timeout_time = yang_dnode_get_uint32(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/timers/update-interval
- */
-static int
-ripd_instance_timers_update_interval_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->update_time = yang_dnode_get_uint32(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/version/receive
- */
-static int ripd_instance_version_receive_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->version_recv = yang_dnode_get_enum(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/version/send
- */
-static int ripd_instance_version_send_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct rip *rip;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- rip = nb_running_get_entry(dnode, NULL, true);
- rip->version_send = yang_dnode_get_enum(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-ripd:rip/split-horizon
- */
-static int lib_interface_rip_split_horizon_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- ri->split_horizon = yang_dnode_get_enum(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-ripd:rip/v2-broadcast
- */
-static int lib_interface_rip_v2_broadcast_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- ri->v2_broadcast = yang_dnode_get_bool(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-ripd:rip/version-receive
- */
-static int
-lib_interface_rip_version_receive_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- ri->ri_receive = yang_dnode_get_enum(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-ripd:rip/version-send
- */
-static int lib_interface_rip_version_send_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- ri->ri_send = yang_dnode_get_enum(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/mode
- */
-static int lib_interface_rip_authentication_scheme_mode_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- ri->auth_type = yang_dnode_get_enum(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath:
- * /frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length
- */
-static int lib_interface_rip_authentication_scheme_md5_auth_length_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- ri->md5_auth_len = yang_dnode_get_enum(dnode, NULL);
-
- return NB_OK;
-}
-
-static int lib_interface_rip_authentication_scheme_md5_auth_length_destroy(
- enum nb_event event, const struct lyd_node *dnode)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- ri->md5_auth_len = yang_get_default_enum(
- "%s/authentication-scheme/md5-auth-length", RIP_IFACE);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-password
- */
-static int
-lib_interface_rip_authentication_password_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
- ri->auth_str = XSTRDUP(MTYPE_RIP_INTERFACE_STRING,
- yang_dnode_get_string(dnode, NULL));
-
- return NB_OK;
-}
-
-static int
-lib_interface_rip_authentication_password_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain
- */
-static int
-lib_interface_rip_authentication_key_chain_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
- ri->key_chain = XSTRDUP(MTYPE_RIP_INTERFACE_STRING,
- yang_dnode_get_string(dnode, NULL));
-
- return NB_OK;
-}
-
-static int
-lib_interface_rip_authentication_key_chain_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct interface *ifp;
- struct rip_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor
- */
-static const void *
-ripd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry,
- const void *list_entry)
-{
- const struct rip *rip = parent_list_entry;
- struct listnode *node;
-
- if (list_entry == NULL)
- node = listhead(rip->peer_list);
- else
- node = listnextnode((struct listnode *)list_entry);
-
- return node;
-}
-
-static int
-ripd_instance_state_neighbors_neighbor_get_keys(const void *list_entry,
- struct yang_list_keys *keys)
-{
- const struct listnode *node = list_entry;
- const struct rip_peer *peer = listgetdata(node);
-
- keys->num = 1;
- (void)inet_ntop(AF_INET, &peer->addr, keys->key[0],
- sizeof(keys->key[0]));
-
- return NB_OK;
-}
-
-static const void *ripd_instance_state_neighbors_neighbor_lookup_entry(
- const void *parent_list_entry, const struct yang_list_keys *keys)
-{
- const struct rip *rip = parent_list_entry;
- struct in_addr address;
- struct rip_peer *peer;
- struct listnode *node;
-
- yang_str2ipv4(keys->key[0], &address);
-
- for (ALL_LIST_ELEMENTS_RO(rip->peer_list, node, peer)) {
- if (IPV4_ADDR_SAME(&peer->addr, &address))
- return node;
- }
-
- return NULL;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/address
- */
-static struct yang_data *
-ripd_instance_state_neighbors_neighbor_address_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct listnode *node = list_entry;
- const struct rip_peer *peer = listgetdata(node);
-
- return yang_data_new_ipv4(xpath, &peer->addr);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/last-update
- */
-static struct yang_data *
-ripd_instance_state_neighbors_neighbor_last_update_get_elem(
- const char *xpath, const void *list_entry)
-{
- /* TODO: yang:date-and-time is tricky */
- return NULL;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-packets-rcvd
- */
-static struct yang_data *
-ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct listnode *node = list_entry;
- const struct rip_peer *peer = listgetdata(node);
-
- return yang_data_new_uint32(xpath, peer->recv_badpackets);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-routes-rcvd
- */
-static struct yang_data *
-ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct listnode *node = list_entry;
- const struct rip_peer *peer = listgetdata(node);
-
- return yang_data_new_uint32(xpath, peer->recv_badroutes);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/routes/route
- */
-static const void *
-ripd_instance_state_routes_route_get_next(const void *parent_list_entry,
- const void *list_entry)
-{
- const struct rip *rip = parent_list_entry;
- struct route_node *rn;
-
- if (list_entry == NULL)
- rn = route_top(rip->table);
- else
- rn = route_next((struct route_node *)list_entry);
- while (rn && rn->info == NULL)
- rn = route_next(rn);
-
- return rn;
-}
-
-static int
-ripd_instance_state_routes_route_get_keys(const void *list_entry,
- struct yang_list_keys *keys)
-{
- const struct route_node *rn = list_entry;
-
- keys->num = 1;
- (void)prefix2str(&rn->p, keys->key[0], sizeof(keys->key[0]));
-
- return NB_OK;
-}
-
-static const void *
-ripd_instance_state_routes_route_lookup_entry(const void *parent_list_entry,
- const struct yang_list_keys *keys)
-{
- const struct rip *rip = parent_list_entry;
- struct prefix prefix;
- struct route_node *rn;
-
- yang_str2ipv4p(keys->key[0], &prefix);
-
- rn = route_node_lookup(rip->table, &prefix);
- if (!rn || !rn->info)
- return NULL;
-
- route_unlock_node(rn);
-
- return rn;
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/routes/route/prefix
- */
-static struct yang_data *
-ripd_instance_state_routes_route_prefix_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct route_node *rn = list_entry;
- const struct rip_info *rinfo = listnode_head(rn->info);
-
- return yang_data_new_ipv4p(xpath, &rinfo->rp->p);
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/routes/route/next-hop
- */
-static struct yang_data *
-ripd_instance_state_routes_route_next_hop_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct route_node *rn = list_entry;
- const struct rip_info *rinfo = listnode_head(rn->info);
-
- switch (rinfo->nh.type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- return yang_data_new_ipv4(xpath, &rinfo->nh.gate.ipv4);
- default:
- return NULL;
- }
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/routes/route/interface
- */
-static struct yang_data *
-ripd_instance_state_routes_route_interface_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct route_node *rn = list_entry;
- const struct rip_info *rinfo = listnode_head(rn->info);
- const struct rip *rip = rip_info_get_instance(rinfo);
-
- switch (rinfo->nh.type) {
- case NEXTHOP_TYPE_IFINDEX:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- return yang_data_new_string(
- xpath,
- ifindex2ifname(rinfo->nh.ifindex, rip->vrf->vrf_id));
- default:
- return NULL;
- }
-}
-
-/*
- * XPath: /frr-ripd:ripd/instance/state/routes/route/metric
- */
-static struct yang_data *
-ripd_instance_state_routes_route_metric_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct route_node *rn = list_entry;
- const struct rip_info *rinfo = listnode_head(rn->info);
-
- return yang_data_new_uint8(xpath, rinfo->metric);
-}
-
-/*
- * XPath: /frr-ripd:clear-rip-route
- */
-static void clear_rip_route(struct rip *rip)
-{
- struct route_node *rp;
-
- if (IS_RIP_DEBUG_EVENT)
- zlog_debug("Clearing all RIP routes (VRF %s)", rip->vrf_name);
-
- /* Clear received RIP routes */
- for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
- struct list *list;
- struct listnode *listnode;
- struct rip_info *rinfo;
-
- list = rp->info;
- if (!list)
- continue;
-
- for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- if (!rip_route_rte(rinfo))
- continue;
-
- if (CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
- rip_zebra_ipv4_delete(rip, rp);
- break;
- }
-
- if (rinfo) {
- RIP_TIMER_OFF(rinfo->t_timeout);
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
- listnode_delete(list, rinfo);
- rip_info_free(rinfo);
- }
-
- if (list_isempty(list)) {
- list_delete(&list);
- rp->info = NULL;
- route_unlock_node(rp);
- }
- }
-}
-
-static int clear_rip_route_rpc(const char *xpath, const struct list *input,
- struct list *output)
-{
- struct rip *rip;
- struct yang_data *yang_vrf;
-
- yang_vrf = yang_data_list_find(input, "%s/%s", xpath, "input/vrf");
- if (yang_vrf) {
- rip = rip_lookup_by_vrf_name(yang_vrf->value);
- if (rip)
- clear_rip_route(rip);
- } else {
- struct vrf *vrf;
-
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- rip = vrf->info;
- if (!rip)
- continue;
-
- clear_rip_route(rip);
- }
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripd:authentication-type-failure
- */
-void ripd_notif_send_auth_type_failure(const char *ifname)
-{
- const char *xpath = "/frr-ripd:authentication-type-failure";
- struct list *arguments;
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
-
- arguments = yang_data_list_new();
-
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-name", xpath);
- data = yang_data_new_string(xpath_arg, ifname);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/*
- * XPath: /frr-ripd:authentication-failure
- */
-void ripd_notif_send_auth_failure(const char *ifname)
-{
- const char *xpath = "/frr-ripd:authentication-failure";
- struct list *arguments;
- char xpath_arg[XPATH_MAXLEN];
- struct yang_data *data;
-
- arguments = yang_data_list_new();
-
- snprintf(xpath_arg, sizeof(xpath_arg), "%s/interface-name", xpath);
- data = yang_data_new_string(xpath_arg, ifname);
- listnode_add(arguments, data);
-
- nb_notification_send(xpath, arguments);
-}
-
-/* clang-format off */
-const struct frr_yang_module_info frr_ripd_info = {
- .name = "frr-ripd",
- .nodes = {
- {
- .xpath = "/frr-ripd:ripd/instance",
- .cbs = {
- .cli_show = cli_show_router_rip,
- .create = ripd_instance_create,
- .destroy = ripd_instance_destroy,
- .get_keys = ripd_instance_get_keys,
- .get_next = ripd_instance_get_next,
- .lookup_entry = ripd_instance_lookup_entry,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/allow-ecmp",
- .cbs = {
- .cli_show = cli_show_rip_allow_ecmp,
- .modify = ripd_instance_allow_ecmp_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/default-information-originate",
- .cbs = {
- .cli_show = cli_show_rip_default_information_originate,
- .modify = ripd_instance_default_information_originate_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/default-metric",
- .cbs = {
- .cli_show = cli_show_rip_default_metric,
- .modify = ripd_instance_default_metric_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/distance/default",
- .cbs = {
- .cli_show = cli_show_rip_distance,
- .modify = ripd_instance_distance_default_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/distance/source",
- .cbs = {
- .cli_show = cli_show_rip_distance_source,
- .create = ripd_instance_distance_source_create,
- .destroy = ripd_instance_distance_source_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/distance/source/distance",
- .cbs = {
- .modify = ripd_instance_distance_source_distance_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/distance/source/access-list",
- .cbs = {
- .destroy = ripd_instance_distance_source_access_list_destroy,
- .modify = ripd_instance_distance_source_access_list_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/explicit-neighbor",
- .cbs = {
- .cli_show = cli_show_rip_neighbor,
- .create = ripd_instance_explicit_neighbor_create,
- .destroy = ripd_instance_explicit_neighbor_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/network",
- .cbs = {
- .cli_show = cli_show_rip_network_prefix,
- .create = ripd_instance_network_create,
- .destroy = ripd_instance_network_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/interface",
- .cbs = {
- .cli_show = cli_show_rip_network_interface,
- .create = ripd_instance_interface_create,
- .destroy = ripd_instance_interface_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/offset-list",
- .cbs = {
- .cli_show = cli_show_rip_offset_list,
- .create = ripd_instance_offset_list_create,
- .destroy = ripd_instance_offset_list_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/offset-list/access-list",
- .cbs = {
- .modify = ripd_instance_offset_list_access_list_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/offset-list/metric",
- .cbs = {
- .modify = ripd_instance_offset_list_metric_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/passive-default",
- .cbs = {
- .cli_show = cli_show_rip_passive_default,
- .modify = ripd_instance_passive_default_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/passive-interface",
- .cbs = {
- .cli_show = cli_show_rip_passive_interface,
- .create = ripd_instance_passive_interface_create,
- .destroy = ripd_instance_passive_interface_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/non-passive-interface",
- .cbs = {
- .cli_show = cli_show_rip_non_passive_interface,
- .create = ripd_instance_non_passive_interface_create,
- .destroy = ripd_instance_non_passive_interface_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/redistribute",
- .cbs = {
- .apply_finish = ripd_instance_redistribute_apply_finish,
- .cli_show = cli_show_rip_redistribute,
- .create = ripd_instance_redistribute_create,
- .destroy = ripd_instance_redistribute_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/redistribute/route-map",
- .cbs = {
- .destroy = ripd_instance_redistribute_route_map_destroy,
- .modify = ripd_instance_redistribute_route_map_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/redistribute/metric",
- .cbs = {
- .destroy = ripd_instance_redistribute_metric_destroy,
- .modify = ripd_instance_redistribute_metric_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/static-route",
- .cbs = {
- .cli_show = cli_show_rip_route,
- .create = ripd_instance_static_route_create,
- .destroy = ripd_instance_static_route_destroy,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/timers",
- .cbs = {
- .apply_finish = ripd_instance_timers_apply_finish,
- .cli_show = cli_show_rip_timers,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/timers/flush-interval",
- .cbs = {
- .modify = ripd_instance_timers_flush_interval_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/timers/holddown-interval",
- .cbs = {
- .modify = ripd_instance_timers_holddown_interval_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/timers/update-interval",
- .cbs = {
- .modify = ripd_instance_timers_update_interval_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/version",
- .cbs = {
- .cli_show = cli_show_rip_version,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/version/receive",
- .cbs = {
- .modify = ripd_instance_version_receive_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/version/send",
- .cbs = {
- .modify = ripd_instance_version_send_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/split-horizon",
- .cbs = {
- .cli_show = cli_show_ip_rip_split_horizon,
- .modify = lib_interface_rip_split_horizon_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/v2-broadcast",
- .cbs = {
- .cli_show = cli_show_ip_rip_v2_broadcast,
- .modify = lib_interface_rip_v2_broadcast_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-receive",
- .cbs = {
- .cli_show = cli_show_ip_rip_receive_version,
- .modify = lib_interface_rip_version_receive_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/version-send",
- .cbs = {
- .cli_show = cli_show_ip_rip_send_version,
- .modify = lib_interface_rip_version_send_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme",
- .cbs = {
- .cli_show = cli_show_ip_rip_authentication_scheme,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/mode",
- .cbs = {
- .modify = lib_interface_rip_authentication_scheme_mode_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length",
- .cbs = {
- .destroy = lib_interface_rip_authentication_scheme_md5_auth_length_destroy,
- .modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password",
- .cbs = {
- .cli_show = cli_show_ip_rip_authentication_string,
- .destroy = lib_interface_rip_authentication_password_destroy,
- .modify = lib_interface_rip_authentication_password_modify,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain",
- .cbs = {
- .cli_show = cli_show_ip_rip_authentication_key_chain,
- .destroy = lib_interface_rip_authentication_key_chain_destroy,
- .modify = lib_interface_rip_authentication_key_chain_modify,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor",
- .cbs = {
- .get_keys = ripd_instance_state_neighbors_neighbor_get_keys,
- .get_next = ripd_instance_state_neighbors_neighbor_get_next,
- .lookup_entry = ripd_instance_state_neighbors_neighbor_lookup_entry,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/address",
- .cbs = {
- .get_elem = ripd_instance_state_neighbors_neighbor_address_get_elem,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/last-update",
- .cbs = {
- .get_elem = ripd_instance_state_neighbors_neighbor_last_update_get_elem,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/bad-packets-rcvd",
- .cbs = {
- .get_elem = ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/bad-routes-rcvd",
- .cbs = {
- .get_elem = ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/routes/route",
- .cbs = {
- .get_keys = ripd_instance_state_routes_route_get_keys,
- .get_next = ripd_instance_state_routes_route_get_next,
- .lookup_entry = ripd_instance_state_routes_route_lookup_entry,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/routes/route/prefix",
- .cbs = {
- .get_elem = ripd_instance_state_routes_route_prefix_get_elem,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/routes/route/next-hop",
- .cbs = {
- .get_elem = ripd_instance_state_routes_route_next_hop_get_elem,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/routes/route/interface",
- .cbs = {
- .get_elem = ripd_instance_state_routes_route_interface_get_elem,
- },
- },
- {
- .xpath = "/frr-ripd:ripd/instance/state/routes/route/metric",
- .cbs = {
- .get_elem = ripd_instance_state_routes_route_metric_get_elem,
- },
- },
- {
- .xpath = "/frr-ripd:clear-rip-route",
- .cbs = {
- .rpc = clear_rip_route_rpc,
- },
- },
- {
- .xpath = NULL,
- },
- }
-};
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 1b5a582cb1..ec0770ef3d 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -46,6 +46,7 @@
#include "northbound_cli.h"
#include "ripd/ripd.h"
+#include "ripd/rip_nb.h"
#include "ripd/rip_debug.h"
#include "ripd/rip_errors.h"
#include "ripd/rip_interface.h"
diff --git a/ripd/ripd.h b/ripd/ripd.h
index 7f2c3fd068..417bd5b3b1 100644
--- a/ripd/ripd.h
+++ b/ripd/ripd.h
@@ -521,10 +521,7 @@ extern int offset_list_cmp(struct rip_offset_list *o1,
extern void rip_vrf_init(void);
extern void rip_vrf_terminate(void);
-
-/* YANG notifications */
-extern void ripd_notif_send_auth_type_failure(const char *ifname);
-extern void ripd_notif_send_auth_failure(const char *ifname);
+extern void rip_cli_init(void);
extern struct zebra_privs_t ripd_privs;
extern struct rip_instance_head rip_instances;
@@ -535,8 +532,4 @@ extern struct thread_master *master;
DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc))
DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc))
-/* Northbound. */
-extern void rip_cli_init(void);
-extern const struct frr_yang_module_info frr_ripd_info;
-
#endif /* _ZEBRA_RIP_H */
diff --git a/ripd/subdir.am b/ripd/subdir.am
index 312c1db6af..dfdfc88a56 100644
--- a/ripd/subdir.am
+++ b/ripd/subdir.am
@@ -24,7 +24,11 @@ ripd_librip_a_SOURCES = \
ripd/rip_errors.c \
ripd/rip_interface.c \
ripd/rip_offset.c \
- ripd/rip_northbound.c \
+ ripd/rip_nb.c \
+ ripd/rip_nb_config.c \
+ ripd/rip_nb_rpcs.c \
+ ripd/rip_nb_notifications.c \
+ ripd/rip_nb_state.c \
ripd/rip_peer.c \
ripd/rip_routemap.c \
ripd/rip_zebra.c \
@@ -35,10 +39,10 @@ ripd/rip_cli_clippy.c: $(CLIPPY_DEPS)
ripd/rip_cli.$(OBJEXT): ripd/rip_cli_clippy.c
noinst_HEADERS += \
- ripd/rip_cli.h \
ripd/rip_debug.h \
ripd/rip_errors.h \
ripd/rip_interface.h \
+ ripd/rip_nb.h \
ripd/ripd.h \
# end
diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c
index e95c0e95d6..2d9930e357 100644
--- a/ripngd/ripng_cli.c
+++ b/ripngd/ripng_cli.c
@@ -29,7 +29,7 @@
#include "libfrr.h"
#include "ripngd/ripngd.h"
-#include "ripngd/ripng_cli.h"
+#include "ripngd/ripng_nb.h"
#ifndef VTYSH_EXTRACT_PL
#include "ripngd/ripng_cli_clippy.c"
#endif
diff --git a/ripngd/ripng_cli.h b/ripngd/ripng_cli.h
deleted file mode 100644
index d95747e0f8..0000000000
--- a/ripngd/ripng_cli.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 1998 Kunihiro Ishiguro
- * Copyright (C) 2018 NetDEF, Inc.
- * Renato Westphal
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _FRR_RIPNG_CLI_H_
-#define _FRR_RIPNG_CLI_H_
-
-extern void cli_show_router_ripng(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_allow_ecmp(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_default_information_originate(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_default_metric(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_network_prefix(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_network_interface(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_offset_list(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_passive_interface(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_redistribute(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_route(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_aggregate_address(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ripng_timers(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void cli_show_ipv6_ripng_split_horizon(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-
-#endif /* _FRR_RIPNG_CLI_H_ */
diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c
index 4b027019c0..3f2c0e9da0 100644
--- a/ripngd/ripng_main.c
+++ b/ripngd/ripng_main.c
@@ -39,6 +39,7 @@
#include "libfrr.h"
#include "ripngd/ripngd.h"
+#include "ripngd/ripng_nb.h"
/* RIPngd options. */
struct option longopts[] = {{0}};
diff --git a/ripngd/ripng_nb.c b/ripngd/ripng_nb.c
new file mode 100644
index 0000000000..a02a72112f
--- /dev/null
+++ b/ripngd/ripng_nb.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripngd/ripng_nb.h"
+
+/* clang-format off */
+const struct frr_yang_module_info frr_ripngd_info = {
+ .name = "frr-ripngd",
+ .nodes = {
+ {
+ .xpath = "/frr-ripngd:ripngd/instance",
+ .cbs = {
+ .cli_show = cli_show_router_ripng,
+ .create = ripngd_instance_create,
+ .destroy = ripngd_instance_destroy,
+ .get_keys = ripngd_instance_get_keys,
+ .get_next = ripngd_instance_get_next,
+ .lookup_entry = ripngd_instance_lookup_entry,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/allow-ecmp",
+ .cbs = {
+ .cli_show = cli_show_ripng_allow_ecmp,
+ .modify = ripngd_instance_allow_ecmp_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/default-information-originate",
+ .cbs = {
+ .cli_show = cli_show_ripng_default_information_originate,
+ .modify = ripngd_instance_default_information_originate_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/default-metric",
+ .cbs = {
+ .cli_show = cli_show_ripng_default_metric,
+ .modify = ripngd_instance_default_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/network",
+ .cbs = {
+ .cli_show = cli_show_ripng_network_prefix,
+ .create = ripngd_instance_network_create,
+ .destroy = ripngd_instance_network_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/interface",
+ .cbs = {
+ .cli_show = cli_show_ripng_network_interface,
+ .create = ripngd_instance_interface_create,
+ .destroy = ripngd_instance_interface_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/offset-list",
+ .cbs = {
+ .cli_show = cli_show_ripng_offset_list,
+ .create = ripngd_instance_offset_list_create,
+ .destroy = ripngd_instance_offset_list_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/offset-list/access-list",
+ .cbs = {
+ .modify = ripngd_instance_offset_list_access_list_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/offset-list/metric",
+ .cbs = {
+ .modify = ripngd_instance_offset_list_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/passive-interface",
+ .cbs = {
+ .cli_show = cli_show_ripng_passive_interface,
+ .create = ripngd_instance_passive_interface_create,
+ .destroy = ripngd_instance_passive_interface_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/redistribute",
+ .cbs = {
+ .apply_finish = ripngd_instance_redistribute_apply_finish,
+ .cli_show = cli_show_ripng_redistribute,
+ .create = ripngd_instance_redistribute_create,
+ .destroy = ripngd_instance_redistribute_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map",
+ .cbs = {
+ .destroy = ripngd_instance_redistribute_route_map_destroy,
+ .modify = ripngd_instance_redistribute_route_map_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/redistribute/metric",
+ .cbs = {
+ .destroy = ripngd_instance_redistribute_metric_destroy,
+ .modify = ripngd_instance_redistribute_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/static-route",
+ .cbs = {
+ .cli_show = cli_show_ripng_route,
+ .create = ripngd_instance_static_route_create,
+ .destroy = ripngd_instance_static_route_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/aggregate-address",
+ .cbs = {
+ .cli_show = cli_show_ripng_aggregate_address,
+ .create = ripngd_instance_aggregate_address_create,
+ .destroy = ripngd_instance_aggregate_address_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/timers",
+ .cbs = {
+ .apply_finish = ripngd_instance_timers_apply_finish,
+ .cli_show = cli_show_ripng_timers,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/timers/flush-interval",
+ .cbs = {
+ .modify = ripngd_instance_timers_flush_interval_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/timers/holddown-interval",
+ .cbs = {
+ .modify = ripngd_instance_timers_holddown_interval_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/timers/update-interval",
+ .cbs = {
+ .modify = ripngd_instance_timers_update_interval_modify,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor",
+ .cbs = {
+ .get_keys = ripngd_instance_state_neighbors_neighbor_get_keys,
+ .get_next = ripngd_instance_state_neighbors_neighbor_get_next,
+ .lookup_entry = ripngd_instance_state_neighbors_neighbor_lookup_entry,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/address",
+ .cbs = {
+ .get_elem = ripngd_instance_state_neighbors_neighbor_address_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/last-update",
+ .cbs = {
+ .get_elem = ripngd_instance_state_neighbors_neighbor_last_update_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-packets-rcvd",
+ .cbs = {
+ .get_elem = ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-routes-rcvd",
+ .cbs = {
+ .get_elem = ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/routes/route",
+ .cbs = {
+ .get_keys = ripngd_instance_state_routes_route_get_keys,
+ .get_next = ripngd_instance_state_routes_route_get_next,
+ .lookup_entry = ripngd_instance_state_routes_route_lookup_entry,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/prefix",
+ .cbs = {
+ .get_elem = ripngd_instance_state_routes_route_prefix_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/next-hop",
+ .cbs = {
+ .get_elem = ripngd_instance_state_routes_route_next_hop_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/interface",
+ .cbs = {
+ .get_elem = ripngd_instance_state_routes_route_interface_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/metric",
+ .cbs = {
+ .get_elem = ripngd_instance_state_routes_route_metric_get_elem,
+ },
+ },
+ {
+ .xpath = "/frr-ripngd:clear-ripng-route",
+ .cbs = {
+ .rpc = clear_ripng_route_rpc,
+ },
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-ripngd:ripng/split-horizon",
+ .cbs = {
+ .cli_show = cli_show_ipv6_ripng_split_horizon,
+ .modify = lib_interface_ripng_split_horizon_modify,
+ },
+ },
+ {
+ .xpath = NULL,
+ },
+ }
+};
diff --git a/ripngd/ripng_nb.h b/ripngd/ripng_nb.h
new file mode 100644
index 0000000000..45e92e0a10
--- /dev/null
+++ b/ripngd/ripng_nb.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_RIPNG_NB_H_
+#define _FRR_RIPNG_NB_H_
+
+extern const struct frr_yang_module_info frr_ripngd_info;
+
+/* Mandatory callbacks. */
+int ripngd_instance_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_destroy(enum nb_event event, const struct lyd_node *dnode);
+const void *ripngd_instance_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int ripngd_instance_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *ripngd_instance_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys);
+int ripngd_instance_allow_ecmp_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_default_information_originate_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_default_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_network_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_network_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripngd_instance_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripngd_instance_offset_list_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_offset_list_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripngd_instance_offset_list_access_list_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_offset_list_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_passive_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_passive_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripngd_instance_redistribute_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_redistribute_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripngd_instance_redistribute_route_map_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_redistribute_route_map_destroy(
+ enum nb_event event, const struct lyd_node *dnode);
+int ripngd_instance_redistribute_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_redistribute_metric_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripngd_instance_static_route_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_static_route_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripngd_instance_aggregate_address_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_aggregate_address_destroy(enum nb_event event,
+ const struct lyd_node *dnode);
+int ripngd_instance_timers_flush_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_timers_holddown_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource);
+int ripngd_instance_timers_update_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+const void *
+ripngd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int ripngd_instance_state_neighbors_neighbor_get_keys(
+ const void *list_entry, struct yang_list_keys *keys);
+const void *ripngd_instance_state_neighbors_neighbor_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *ripngd_instance_state_neighbors_neighbor_address_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *ripngd_instance_state_neighbors_neighbor_last_update_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
+ const char *xpath, const void *list_entry);
+struct yang_data *
+ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
+ const char *xpath, const void *list_entry);
+const void *
+ripngd_instance_state_routes_route_get_next(const void *parent_list_entry,
+ const void *list_entry);
+int ripngd_instance_state_routes_route_get_keys(const void *list_entry,
+ struct yang_list_keys *keys);
+const void *ripngd_instance_state_routes_route_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys);
+struct yang_data *
+ripngd_instance_state_routes_route_prefix_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+ripngd_instance_state_routes_route_next_hop_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+ripngd_instance_state_routes_route_interface_get_elem(const char *xpath,
+ const void *list_entry);
+struct yang_data *
+ripngd_instance_state_routes_route_metric_get_elem(const char *xpath,
+ const void *list_entry);
+int clear_ripng_route_rpc(const char *xpath, const struct list *input,
+ struct list *output);
+int lib_interface_ripng_split_horizon_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource);
+
+/* Optional 'apply_finish' callbacks. */
+void ripngd_instance_redistribute_apply_finish(const struct lyd_node *dnode);
+void ripngd_instance_timers_apply_finish(const struct lyd_node *dnode);
+
+/* Optional 'cli_show' callbacks. */
+void cli_show_router_ripng(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_allow_ecmp(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_default_information_originate(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_default_metric(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_network_prefix(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_network_interface(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_offset_list(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_passive_interface(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_redistribute(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_route(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_aggregate_address(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ripng_timers(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_ipv6_ripng_split_horizon(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+
+#endif /* _FRR_RIPNG_NB_H_ */
diff --git a/ripngd/ripng_nb_config.c b/ripngd/ripng_nb_config.c
new file mode 100644
index 0000000000..b39c1d443a
--- /dev/null
+++ b/ripngd/ripng_nb_config.c
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) 1998 Kunihiro Ishiguro
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vrf.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "routemap.h"
+#include "agg_table.h"
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_nb.h"
+#include "ripngd/ripng_debug.h"
+#include "ripngd/ripng_route.h"
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance
+ */
+int ripngd_instance_create(enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ struct vrf *vrf;
+ const char *vrf_name;
+ int socket;
+
+ vrf_name = yang_dnode_get_string(dnode, "./vrf");
+ vrf = vrf_lookup_by_name(vrf_name);
+
+ /*
+ * Try to create a RIPng socket only if the VRF is enabled, otherwise
+ * create a disabled RIPng instance and wait for the VRF to be enabled.
+ */
+ switch (event) {
+ case NB_EV_VALIDATE:
+ break;
+ case NB_EV_PREPARE:
+ if (!vrf || !vrf_is_enabled(vrf))
+ break;
+
+ socket = ripng_make_socket(vrf);
+ if (socket < 0)
+ return NB_ERR_RESOURCE;
+ resource->fd = socket;
+ break;
+ case NB_EV_ABORT:
+ if (!vrf || !vrf_is_enabled(vrf))
+ break;
+
+ socket = resource->fd;
+ close(socket);
+ break;
+ case NB_EV_APPLY:
+ if (vrf && vrf_is_enabled(vrf))
+ socket = resource->fd;
+ else
+ socket = -1;
+
+ ripng = ripng_create(vrf_name, vrf, socket);
+ nb_running_set_entry(dnode, ripng);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int ripngd_instance_destroy(enum nb_event event, const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_unset_entry(dnode);
+ ripng_clean(ripng);
+
+ return NB_OK;
+}
+
+const void *ripngd_instance_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ struct ripng *ripng = (struct ripng *)list_entry;
+
+ if (list_entry == NULL)
+ ripng = RB_MIN(ripng_instance_head, &ripng_instances);
+ else
+ ripng = RB_NEXT(ripng_instance_head, ripng);
+
+ return ripng;
+}
+
+int ripngd_instance_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct ripng *ripng = list_entry;
+
+ keys->num = 1;
+ strlcpy(keys->key[0], ripng->vrf_name, sizeof(keys->key[0]));
+
+ return NB_OK;
+}
+
+const void *ripngd_instance_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ const char *vrf_name = keys->key[0];
+
+ return ripng_lookup_by_vrf_name(vrf_name);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/allow-ecmp
+ */
+int ripngd_instance_allow_ecmp_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ripng->ecmp = yang_dnode_get_bool(dnode, NULL);
+ if (!ripng->ecmp)
+ ripng_ecmp_disable(ripng);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/default-information-originate
+ */
+int ripngd_instance_default_information_originate_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ bool default_information;
+ struct prefix_ipv6 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ default_information = yang_dnode_get_bool(dnode, NULL);
+
+ str2prefix_ipv6("::/0", &p);
+ if (default_information) {
+ ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG,
+ RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0);
+ } else {
+ ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG,
+ RIPNG_ROUTE_DEFAULT, &p, 0);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/default-metric
+ */
+int ripngd_instance_default_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ripng->default_metric = yang_dnode_get_uint8(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/network
+ */
+int ripngd_instance_network_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ struct prefix p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv6p(&p, dnode, NULL);
+ apply_mask_ipv6((struct prefix_ipv6 *)&p);
+
+ return ripng_enable_network_add(ripng, &p);
+}
+
+int ripngd_instance_network_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ struct prefix p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv6p(&p, dnode, NULL);
+ apply_mask_ipv6((struct prefix_ipv6 *)&p);
+
+ return ripng_enable_network_delete(ripng, &p);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/interface
+ */
+int ripngd_instance_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return ripng_enable_if_add(ripng, ifname);
+}
+
+int ripngd_instance_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return ripng_enable_if_delete(ripng, ifname);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/offset-list
+ */
+int ripngd_instance_offset_list_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ const char *ifname;
+ struct ripng_offset_list *offset;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, "./interface");
+
+ offset = ripng_offset_list_new(ripng, ifname);
+ nb_running_set_entry(dnode, offset);
+
+ return NB_OK;
+}
+
+int ripngd_instance_offset_list_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ int direct;
+ struct ripng_offset_list *offset;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ direct = yang_dnode_get_enum(dnode, "./direction");
+
+ offset = nb_running_unset_entry(dnode);
+ if (offset->direct[direct].alist_name) {
+ free(offset->direct[direct].alist_name);
+ offset->direct[direct].alist_name = NULL;
+ }
+ if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name == NULL
+ && offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name == NULL)
+ ripng_offset_list_del(offset);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/offset-list/access-list
+ */
+int ripngd_instance_offset_list_access_list_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ int direct;
+ struct ripng_offset_list *offset;
+ const char *alist_name;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ direct = yang_dnode_get_enum(dnode, "../direction");
+ alist_name = yang_dnode_get_string(dnode, NULL);
+
+ offset = nb_running_get_entry(dnode, NULL, true);
+ if (offset->direct[direct].alist_name)
+ free(offset->direct[direct].alist_name);
+ offset->direct[direct].alist_name = strdup(alist_name);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/offset-list/metric
+ */
+int ripngd_instance_offset_list_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ int direct;
+ uint8_t metric;
+ struct ripng_offset_list *offset;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ direct = yang_dnode_get_enum(dnode, "../direction");
+ metric = yang_dnode_get_uint8(dnode, NULL);
+
+ offset = nb_running_get_entry(dnode, NULL, true);
+ offset->direct[direct].metric = metric;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/passive-interface
+ */
+int ripngd_instance_passive_interface_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return ripng_passive_interface_set(ripng, ifname);
+}
+
+int ripngd_instance_passive_interface_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ const char *ifname;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ifname = yang_dnode_get_string(dnode, NULL);
+
+ return ripng_passive_interface_unset(ripng, ifname);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/redistribute
+ */
+int ripngd_instance_redistribute_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "./protocol");
+
+ ripng->redist[type].enabled = true;
+
+ return NB_OK;
+}
+
+int ripngd_instance_redistribute_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "./protocol");
+
+ ripng->redist[type].enabled = false;
+ if (ripng->redist[type].route_map.name) {
+ free(ripng->redist[type].route_map.name);
+ ripng->redist[type].route_map.name = NULL;
+ ripng->redist[type].route_map.map = NULL;
+ }
+ ripng->redist[type].metric_config = false;
+ ripng->redist[type].metric = 0;
+
+ if (ripng->enabled)
+ ripng_redistribute_conf_delete(ripng, type);
+
+ return NB_OK;
+}
+
+void ripngd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ int type;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "./protocol");
+
+ if (ripng->enabled)
+ ripng_redistribute_conf_update(ripng, type);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/redistribute/route-map
+ */
+int ripngd_instance_redistribute_route_map_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ int type;
+ const char *rmap_name;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "../protocol");
+ rmap_name = yang_dnode_get_string(dnode, NULL);
+
+ if (ripng->redist[type].route_map.name)
+ free(ripng->redist[type].route_map.name);
+ ripng->redist[type].route_map.name = strdup(rmap_name);
+ ripng->redist[type].route_map.map = route_map_lookup_by_name(rmap_name);
+
+ return NB_OK;
+}
+
+int ripngd_instance_redistribute_route_map_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "../protocol");
+
+ free(ripng->redist[type].route_map.name);
+ ripng->redist[type].route_map.name = NULL;
+ ripng->redist[type].route_map.map = NULL;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/redistribute/metric
+ */
+int ripngd_instance_redistribute_metric_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ int type;
+ uint8_t metric;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "../protocol");
+ metric = yang_dnode_get_uint8(dnode, NULL);
+
+ ripng->redist[type].metric_config = true;
+ ripng->redist[type].metric = metric;
+
+ return NB_OK;
+}
+
+int ripngd_instance_redistribute_metric_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ type = yang_dnode_get_enum(dnode, "../protocol");
+
+ ripng->redist[type].metric_config = false;
+ ripng->redist[type].metric = 0;
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/static-route
+ */
+int ripngd_instance_static_route_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ struct prefix_ipv6 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv6p(&p, dnode, NULL);
+ apply_mask_ipv6(&p);
+
+ ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p,
+ 0, NULL, 0);
+
+ return NB_OK;
+}
+
+int ripngd_instance_static_route_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ struct prefix_ipv6 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv6p(&p, dnode, NULL);
+ apply_mask_ipv6(&p);
+
+ ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC,
+ &p, 0);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/aggregate-address
+ */
+int ripngd_instance_aggregate_address_create(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+ struct prefix_ipv6 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv6p(&p, dnode, NULL);
+ apply_mask_ipv6(&p);
+
+ ripng_aggregate_add(ripng, (struct prefix *)&p);
+
+ return NB_OK;
+}
+
+int ripngd_instance_aggregate_address_destroy(enum nb_event event,
+ const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+ struct prefix_ipv6 p;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ yang_dnode_get_ipv6p(&p, dnode, NULL);
+ apply_mask_ipv6(&p);
+
+ ripng_aggregate_delete(ripng, (struct prefix *)&p);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/timers
+ */
+void ripngd_instance_timers_apply_finish(const struct lyd_node *dnode)
+{
+ struct ripng *ripng;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+
+ /* Reset update timer thread. */
+ ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/timers/flush-interval
+ */
+int ripngd_instance_timers_flush_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ripng->garbage_time = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/timers/holddown-interval
+ */
+int ripngd_instance_timers_holddown_interval_modify(
+ enum nb_event event, const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ripng->timeout_time = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/timers/update-interval
+ */
+int ripngd_instance_timers_update_interval_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct ripng *ripng;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = nb_running_get_entry(dnode, NULL, true);
+ ripng->update_time = yang_dnode_get_uint16(dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-ripngd:ripng/split-horizon
+ */
+int lib_interface_ripng_split_horizon_modify(enum nb_event event,
+ const struct lyd_node *dnode,
+ union nb_resource *resource)
+{
+ struct interface *ifp;
+ struct ripng_interface *ri;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ifp = nb_running_get_entry(dnode, NULL, true);
+ ri = ifp->info;
+ ri->split_horizon = yang_dnode_get_enum(dnode, NULL);
+
+ return NB_OK;
+}
diff --git a/ripngd/ripng_nb_rpcs.c b/ripngd/ripng_nb_rpcs.c
new file mode 100644
index 0000000000..0396daf890
--- /dev/null
+++ b/ripngd/ripng_nb_rpcs.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vrf.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "routemap.h"
+#include "agg_table.h"
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_nb.h"
+#include "ripngd/ripng_debug.h"
+#include "ripngd/ripng_route.h"
+
+/*
+ * XPath: /frr-ripngd:clear-ripng-route
+ */
+static void clear_ripng_route(struct ripng *ripng)
+{
+ struct agg_node *rp;
+
+ if (IS_RIPNG_DEBUG_EVENT)
+ zlog_debug("Clearing all RIPng routes (VRF %s)",
+ ripng->vrf_name);
+
+ /* Clear received RIPng routes */
+ for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
+ struct list *list;
+ struct listnode *listnode;
+ struct ripng_info *rinfo;
+
+ list = rp->info;
+ if (list == NULL)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
+ if (!ripng_route_rte(rinfo))
+ continue;
+
+ if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
+ ripng_zebra_ipv6_delete(ripng, rp);
+ break;
+ }
+
+ if (rinfo) {
+ RIPNG_TIMER_OFF(rinfo->t_timeout);
+ RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
+ listnode_delete(list, rinfo);
+ ripng_info_free(rinfo);
+ }
+
+ if (list_isempty(list)) {
+ list_delete(&list);
+ rp->info = NULL;
+ agg_unlock_node(rp);
+ }
+ }
+}
+
+int clear_ripng_route_rpc(const char *xpath, const struct list *input,
+ struct list *output)
+{
+ struct ripng *ripng;
+ struct yang_data *yang_vrf;
+
+ yang_vrf = yang_data_list_find(input, "%s/%s", xpath, "input/vrf");
+ if (yang_vrf) {
+ ripng = ripng_lookup_by_vrf_name(yang_vrf->value);
+ if (ripng)
+ clear_ripng_route(ripng);
+ } else {
+ struct vrf *vrf;
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ ripng = vrf->info;
+ if (!ripng)
+ continue;
+
+ clear_ripng_route(ripng);
+ }
+ }
+
+ return NB_OK;
+}
diff --git a/ripngd/ripng_nb_state.c b/ripngd/ripng_nb_state.c
new file mode 100644
index 0000000000..167077ea29
--- /dev/null
+++ b/ripngd/ripng_nb_state.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2018 NetDEF, Inc.
+ * Renato Westphal
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "vrf.h"
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "command.h"
+#include "routemap.h"
+#include "agg_table.h"
+#include "northbound.h"
+#include "libfrr.h"
+
+#include "ripngd/ripngd.h"
+#include "ripngd/ripng_nb.h"
+#include "ripngd/ripng_debug.h"
+#include "ripngd/ripng_route.h"
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor
+ */
+const void *
+ripngd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ const struct ripng *ripng = parent_list_entry;
+ struct listnode *node;
+
+ if (list_entry == NULL)
+ node = listhead(ripng->peer_list);
+ else
+ node = listnextnode((struct listnode *)list_entry);
+
+ return node;
+}
+
+int ripngd_instance_state_neighbors_neighbor_get_keys(
+ const void *list_entry, struct yang_list_keys *keys)
+{
+ const struct listnode *node = list_entry;
+ const struct ripng_peer *peer = listgetdata(node);
+
+ keys->num = 1;
+ (void)inet_ntop(AF_INET6, &peer->addr, keys->key[0],
+ sizeof(keys->key[0]));
+
+ return NB_OK;
+}
+
+const void *ripngd_instance_state_neighbors_neighbor_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys)
+{
+ const struct ripng *ripng = parent_list_entry;
+ struct in6_addr address;
+ struct ripng_peer *peer;
+ struct listnode *node;
+
+ yang_str2ipv6(keys->key[0], &address);
+
+ for (ALL_LIST_ELEMENTS_RO(ripng->peer_list, node, peer)) {
+ if (IPV6_ADDR_SAME(&peer->addr, &address))
+ return node;
+ }
+
+ return NULL;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/address
+ */
+struct yang_data *ripngd_instance_state_neighbors_neighbor_address_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct listnode *node = list_entry;
+ const struct ripng_peer *peer = listgetdata(node);
+
+ return yang_data_new_ipv6(xpath, &peer->addr);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/last-update
+ */
+struct yang_data *ripngd_instance_state_neighbors_neighbor_last_update_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ /* TODO: yang:date-and-time is tricky */
+ return NULL;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-packets-rcvd
+ */
+struct yang_data *
+ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct listnode *node = list_entry;
+ const struct ripng_peer *peer = listgetdata(node);
+
+ return yang_data_new_uint32(xpath, peer->recv_badpackets);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-routes-rcvd
+ */
+struct yang_data *
+ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
+ const char *xpath, const void *list_entry)
+{
+ const struct listnode *node = list_entry;
+ const struct ripng_peer *peer = listgetdata(node);
+
+ return yang_data_new_uint32(xpath, peer->recv_badroutes);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route
+ */
+const void *
+ripngd_instance_state_routes_route_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ const struct ripng *ripng = parent_list_entry;
+ struct agg_node *rn;
+
+ if (list_entry == NULL)
+ rn = agg_route_top(ripng->table);
+ else
+ rn = agg_route_next((struct agg_node *)list_entry);
+ while (rn && rn->info == NULL)
+ rn = agg_route_next(rn);
+
+ return rn;
+}
+
+int ripngd_instance_state_routes_route_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct agg_node *rn = list_entry;
+
+ keys->num = 1;
+ (void)prefix2str(&rn->p, keys->key[0], sizeof(keys->key[0]));
+
+ return NB_OK;
+}
+
+const void *ripngd_instance_state_routes_route_lookup_entry(
+ const void *parent_list_entry, const struct yang_list_keys *keys)
+{
+ const struct ripng *ripng = parent_list_entry;
+ struct prefix prefix;
+ struct agg_node *rn;
+
+ yang_str2ipv6p(keys->key[0], &prefix);
+
+ rn = agg_node_lookup(ripng->table, &prefix);
+ if (!rn || !rn->info)
+ return NULL;
+
+ agg_unlock_node(rn);
+
+ return rn;
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route/prefix
+ */
+struct yang_data *
+ripngd_instance_state_routes_route_prefix_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct agg_node *rn = list_entry;
+ const struct ripng_info *rinfo = listnode_head(rn->info);
+
+ return yang_data_new_ipv6p(xpath, &rinfo->rp->p);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route/next-hop
+ */
+struct yang_data *
+ripngd_instance_state_routes_route_next_hop_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct agg_node *rn = list_entry;
+ const struct ripng_info *rinfo = listnode_head(rn->info);
+
+ return yang_data_new_ipv6(xpath, &rinfo->nexthop);
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route/interface
+ */
+struct yang_data *
+ripngd_instance_state_routes_route_interface_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct agg_node *rn = list_entry;
+ const struct ripng_info *rinfo = listnode_head(rn->info);
+ const struct ripng *ripng = ripng_info_get_instance(rinfo);
+
+ return yang_data_new_string(
+ xpath, ifindex2ifname(rinfo->ifindex, ripng->vrf->vrf_id));
+}
+
+/*
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route/metric
+ */
+struct yang_data *
+ripngd_instance_state_routes_route_metric_get_elem(const char *xpath,
+ const void *list_entry)
+{
+ const struct agg_node *rn = list_entry;
+ const struct ripng_info *rinfo = listnode_head(rn->info);
+
+ return yang_data_new_uint8(xpath, rinfo->metric);
+}
diff --git a/ripngd/ripng_northbound.c b/ripngd/ripng_northbound.c
deleted file mode 100644
index 588f6db037..0000000000
--- a/ripngd/ripng_northbound.c
+++ /dev/null
@@ -1,1234 +0,0 @@
-/*
- * Copyright (C) 1998 Kunihiro Ishiguro
- * Copyright (C) 2018 NetDEF, Inc.
- * Renato Westphal
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <zebra.h>
-
-#include "if.h"
-#include "vrf.h"
-#include "log.h"
-#include "prefix.h"
-#include "table.h"
-#include "command.h"
-#include "routemap.h"
-#include "agg_table.h"
-#include "northbound.h"
-#include "libfrr.h"
-
-#include "ripngd/ripngd.h"
-#include "ripngd/ripng_debug.h"
-#include "ripngd/ripng_route.h"
-#include "ripngd/ripng_cli.h"
-
-/*
- * XPath: /frr-ripngd:ripngd/instance
- */
-static int ripngd_instance_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- struct vrf *vrf;
- const char *vrf_name;
- int socket;
-
- vrf_name = yang_dnode_get_string(dnode, "./vrf");
- vrf = vrf_lookup_by_name(vrf_name);
-
- /*
- * Try to create a RIPng socket only if the VRF is enabled, otherwise
- * create a disabled RIPng instance and wait for the VRF to be enabled.
- */
- switch (event) {
- case NB_EV_VALIDATE:
- break;
- case NB_EV_PREPARE:
- if (!vrf || !vrf_is_enabled(vrf))
- break;
-
- socket = ripng_make_socket(vrf);
- if (socket < 0)
- return NB_ERR_RESOURCE;
- resource->fd = socket;
- break;
- case NB_EV_ABORT:
- if (!vrf || !vrf_is_enabled(vrf))
- break;
-
- socket = resource->fd;
- close(socket);
- break;
- case NB_EV_APPLY:
- if (vrf && vrf_is_enabled(vrf))
- socket = resource->fd;
- else
- socket = -1;
-
- ripng = ripng_create(vrf_name, vrf, socket);
- nb_running_set_entry(dnode, ripng);
- break;
- }
-
- return NB_OK;
-}
-
-static int ripngd_instance_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_unset_entry(dnode);
- ripng_clean(ripng);
-
- return NB_OK;
-}
-
-static const void *ripngd_instance_get_next(const void *parent_list_entry,
- const void *list_entry)
-{
- struct ripng *ripng = (struct ripng *)list_entry;
-
- if (list_entry == NULL)
- ripng = RB_MIN(ripng_instance_head, &ripng_instances);
- else
- ripng = RB_NEXT(ripng_instance_head, ripng);
-
- return ripng;
-}
-
-static int ripngd_instance_get_keys(const void *list_entry,
- struct yang_list_keys *keys)
-{
- const struct ripng *ripng = list_entry;
-
- keys->num = 1;
- strlcpy(keys->key[0], ripng->vrf_name, sizeof(keys->key[0]));
-
- return NB_OK;
-}
-
-static const void *
-ripngd_instance_lookup_entry(const void *parent_list_entry,
- const struct yang_list_keys *keys)
-{
- const char *vrf_name = keys->key[0];
-
- return ripng_lookup_by_vrf_name(vrf_name);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/allow-ecmp
- */
-static int ripngd_instance_allow_ecmp_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ripng->ecmp = yang_dnode_get_bool(dnode, NULL);
- if (!ripng->ecmp)
- ripng_ecmp_disable(ripng);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/default-information-originate
- */
-static int ripngd_instance_default_information_originate_modify(
- enum nb_event event, const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- bool default_information;
- struct prefix_ipv6 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- default_information = yang_dnode_get_bool(dnode, NULL);
-
- str2prefix_ipv6("::/0", &p);
- if (default_information) {
- ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG,
- RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0);
- } else {
- ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG,
- RIPNG_ROUTE_DEFAULT, &p, 0);
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/default-metric
- */
-static int ripngd_instance_default_metric_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ripng->default_metric = yang_dnode_get_uint8(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/network
- */
-static int ripngd_instance_network_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- struct prefix p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv6p(&p, dnode, NULL);
- apply_mask_ipv6((struct prefix_ipv6 *)&p);
-
- return ripng_enable_network_add(ripng, &p);
-}
-
-static int ripngd_instance_network_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- struct prefix p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv6p(&p, dnode, NULL);
- apply_mask_ipv6((struct prefix_ipv6 *)&p);
-
- return ripng_enable_network_delete(ripng, &p);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/interface
- */
-static int ripngd_instance_interface_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return ripng_enable_if_add(ripng, ifname);
-}
-
-static int ripngd_instance_interface_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return ripng_enable_if_delete(ripng, ifname);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/offset-list
- */
-static int ripngd_instance_offset_list_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- const char *ifname;
- struct ripng_offset_list *offset;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, "./interface");
-
- offset = ripng_offset_list_new(ripng, ifname);
- nb_running_set_entry(dnode, offset);
-
- return NB_OK;
-}
-
-static int ripngd_instance_offset_list_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- int direct;
- struct ripng_offset_list *offset;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- direct = yang_dnode_get_enum(dnode, "./direction");
-
- offset = nb_running_unset_entry(dnode);
- if (offset->direct[direct].alist_name) {
- free(offset->direct[direct].alist_name);
- offset->direct[direct].alist_name = NULL;
- }
- if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name == NULL
- && offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name == NULL)
- ripng_offset_list_del(offset);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/offset-list/access-list
- */
-static int
-ripngd_instance_offset_list_access_list_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- int direct;
- struct ripng_offset_list *offset;
- const char *alist_name;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- direct = yang_dnode_get_enum(dnode, "../direction");
- alist_name = yang_dnode_get_string(dnode, NULL);
-
- offset = nb_running_get_entry(dnode, NULL, true);
- if (offset->direct[direct].alist_name)
- free(offset->direct[direct].alist_name);
- offset->direct[direct].alist_name = strdup(alist_name);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/offset-list/metric
- */
-static int
-ripngd_instance_offset_list_metric_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- int direct;
- uint8_t metric;
- struct ripng_offset_list *offset;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- direct = yang_dnode_get_enum(dnode, "../direction");
- metric = yang_dnode_get_uint8(dnode, NULL);
-
- offset = nb_running_get_entry(dnode, NULL, true);
- offset->direct[direct].metric = metric;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/passive-interface
- */
-static int
-ripngd_instance_passive_interface_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return ripng_passive_interface_set(ripng, ifname);
-}
-
-static int
-ripngd_instance_passive_interface_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- const char *ifname;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ifname = yang_dnode_get_string(dnode, NULL);
-
- return ripng_passive_interface_unset(ripng, ifname);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/redistribute
- */
-static int ripngd_instance_redistribute_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "./protocol");
-
- ripng->redist[type].enabled = true;
-
- return NB_OK;
-}
-
-static int ripngd_instance_redistribute_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "./protocol");
-
- ripng->redist[type].enabled = false;
- if (ripng->redist[type].route_map.name) {
- free(ripng->redist[type].route_map.name);
- ripng->redist[type].route_map.name = NULL;
- ripng->redist[type].route_map.map = NULL;
- }
- ripng->redist[type].metric_config = false;
- ripng->redist[type].metric = 0;
-
- if (ripng->enabled)
- ripng_redistribute_conf_delete(ripng, type);
-
- return NB_OK;
-}
-
-static void
-ripngd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- int type;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "./protocol");
-
- if (ripng->enabled)
- ripng_redistribute_conf_update(ripng, type);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/redistribute/route-map
- */
-static int
-ripngd_instance_redistribute_route_map_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- int type;
- const char *rmap_name;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "../protocol");
- rmap_name = yang_dnode_get_string(dnode, NULL);
-
- if (ripng->redist[type].route_map.name)
- free(ripng->redist[type].route_map.name);
- ripng->redist[type].route_map.name = strdup(rmap_name);
- ripng->redist[type].route_map.map = route_map_lookup_by_name(rmap_name);
-
- return NB_OK;
-}
-
-static int
-ripngd_instance_redistribute_route_map_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "../protocol");
-
- free(ripng->redist[type].route_map.name);
- ripng->redist[type].route_map.name = NULL;
- ripng->redist[type].route_map.map = NULL;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/redistribute/metric
- */
-static int
-ripngd_instance_redistribute_metric_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- int type;
- uint8_t metric;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "../protocol");
- metric = yang_dnode_get_uint8(dnode, NULL);
-
- ripng->redist[type].metric_config = true;
- ripng->redist[type].metric = metric;
-
- return NB_OK;
-}
-
-static int
-ripngd_instance_redistribute_metric_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- int type;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- type = yang_dnode_get_enum(dnode, "../protocol");
-
- ripng->redist[type].metric_config = false;
- ripng->redist[type].metric = 0;
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/static-route
- */
-static int ripngd_instance_static_route_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- struct prefix_ipv6 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv6p(&p, dnode, NULL);
- apply_mask_ipv6(&p);
-
- ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p,
- 0, NULL, 0);
-
- return NB_OK;
-}
-
-static int ripngd_instance_static_route_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- struct prefix_ipv6 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv6p(&p, dnode, NULL);
- apply_mask_ipv6(&p);
-
- ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC,
- &p, 0);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/aggregate-address
- */
-static int
-ripngd_instance_aggregate_address_create(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
- struct prefix_ipv6 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv6p(&p, dnode, NULL);
- apply_mask_ipv6(&p);
-
- ripng_aggregate_add(ripng, (struct prefix *)&p);
-
- return NB_OK;
-}
-
-static int
-ripngd_instance_aggregate_address_destroy(enum nb_event event,
- const struct lyd_node *dnode)
-{
- struct ripng *ripng;
- struct prefix_ipv6 p;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- yang_dnode_get_ipv6p(&p, dnode, NULL);
- apply_mask_ipv6(&p);
-
- ripng_aggregate_delete(ripng, (struct prefix *)&p);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/timers
- */
-static void ripngd_instance_timers_apply_finish(const struct lyd_node *dnode)
-{
- struct ripng *ripng;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
-
- /* Reset update timer thread. */
- ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/timers/flush-interval
- */
-static int
-ripngd_instance_timers_flush_interval_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ripng->garbage_time = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/timers/holddown-interval
- */
-static int
-ripngd_instance_timers_holddown_interval_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ripng->timeout_time = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/timers/update-interval
- */
-static int
-ripngd_instance_timers_update_interval_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct ripng *ripng;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ripng = nb_running_get_entry(dnode, NULL, true);
- ripng->update_time = yang_dnode_get_uint16(dnode, NULL);
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor
- */
-static const void *
-ripngd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry,
- const void *list_entry)
-{
- const struct ripng *ripng = parent_list_entry;
- struct listnode *node;
-
- if (list_entry == NULL)
- node = listhead(ripng->peer_list);
- else
- node = listnextnode((struct listnode *)list_entry);
-
- return node;
-}
-
-static int
-ripngd_instance_state_neighbors_neighbor_get_keys(const void *list_entry,
- struct yang_list_keys *keys)
-{
- const struct listnode *node = list_entry;
- const struct ripng_peer *peer = listgetdata(node);
-
- keys->num = 1;
- (void)inet_ntop(AF_INET6, &peer->addr, keys->key[0],
- sizeof(keys->key[0]));
-
- return NB_OK;
-}
-
-static const void *ripngd_instance_state_neighbors_neighbor_lookup_entry(
- const void *parent_list_entry, const struct yang_list_keys *keys)
-{
- const struct ripng *ripng = parent_list_entry;
- struct in6_addr address;
- struct ripng_peer *peer;
- struct listnode *node;
-
- yang_str2ipv6(keys->key[0], &address);
-
- for (ALL_LIST_ELEMENTS_RO(ripng->peer_list, node, peer)) {
- if (IPV6_ADDR_SAME(&peer->addr, &address))
- return node;
- }
-
- return NULL;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/address
- */
-static struct yang_data *
-ripngd_instance_state_neighbors_neighbor_address_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct listnode *node = list_entry;
- const struct ripng_peer *peer = listgetdata(node);
-
- return yang_data_new_ipv6(xpath, &peer->addr);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/last-update
- */
-static struct yang_data *
-ripngd_instance_state_neighbors_neighbor_last_update_get_elem(
- const char *xpath, const void *list_entry)
-{
- /* TODO: yang:date-and-time is tricky */
- return NULL;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-packets-rcvd
- */
-static struct yang_data *
-ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct listnode *node = list_entry;
- const struct ripng_peer *peer = listgetdata(node);
-
- return yang_data_new_uint32(xpath, peer->recv_badpackets);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-routes-rcvd
- */
-static struct yang_data *
-ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
- const char *xpath, const void *list_entry)
-{
- const struct listnode *node = list_entry;
- const struct ripng_peer *peer = listgetdata(node);
-
- return yang_data_new_uint32(xpath, peer->recv_badroutes);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/routes/route
- */
-static const void *
-ripngd_instance_state_routes_route_get_next(const void *parent_list_entry,
- const void *list_entry)
-{
- const struct ripng *ripng = parent_list_entry;
- struct agg_node *rn;
-
- if (list_entry == NULL)
- rn = agg_route_top(ripng->table);
- else
- rn = agg_route_next((struct agg_node *)list_entry);
- while (rn && rn->info == NULL)
- rn = agg_route_next(rn);
-
- return rn;
-}
-
-static int
-ripngd_instance_state_routes_route_get_keys(const void *list_entry,
- struct yang_list_keys *keys)
-{
- const struct agg_node *rn = list_entry;
-
- keys->num = 1;
- (void)prefix2str(&rn->p, keys->key[0], sizeof(keys->key[0]));
-
- return NB_OK;
-}
-
-static const void *ripngd_instance_state_routes_route_lookup_entry(
- const void *parent_list_entry, const struct yang_list_keys *keys)
-{
- const struct ripng *ripng = parent_list_entry;
- struct prefix prefix;
- struct agg_node *rn;
-
- yang_str2ipv6p(keys->key[0], &prefix);
-
- rn = agg_node_lookup(ripng->table, &prefix);
- if (!rn || !rn->info)
- return NULL;
-
- agg_unlock_node(rn);
-
- return rn;
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/routes/route/prefix
- */
-static struct yang_data *
-ripngd_instance_state_routes_route_prefix_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct agg_node *rn = list_entry;
- const struct ripng_info *rinfo = listnode_head(rn->info);
-
- return yang_data_new_ipv6p(xpath, &rinfo->rp->p);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/routes/route/next-hop
- */
-static struct yang_data *
-ripngd_instance_state_routes_route_next_hop_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct agg_node *rn = list_entry;
- const struct ripng_info *rinfo = listnode_head(rn->info);
-
- return yang_data_new_ipv6(xpath, &rinfo->nexthop);
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/routes/route/interface
- */
-static struct yang_data *
-ripngd_instance_state_routes_route_interface_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct agg_node *rn = list_entry;
- const struct ripng_info *rinfo = listnode_head(rn->info);
- const struct ripng *ripng = ripng_info_get_instance(rinfo);
-
- return yang_data_new_string(
- xpath, ifindex2ifname(rinfo->ifindex, ripng->vrf->vrf_id));
-}
-
-/*
- * XPath: /frr-ripngd:ripngd/instance/state/routes/route/metric
- */
-static struct yang_data *
-ripngd_instance_state_routes_route_metric_get_elem(const char *xpath,
- const void *list_entry)
-{
- const struct agg_node *rn = list_entry;
- const struct ripng_info *rinfo = listnode_head(rn->info);
-
- return yang_data_new_uint8(xpath, rinfo->metric);
-}
-
-/*
- * XPath: /frr-ripngd:clear-ripng-route
- */
-static void clear_ripng_route(struct ripng *ripng)
-{
- struct agg_node *rp;
-
- if (IS_RIPNG_DEBUG_EVENT)
- zlog_debug("Clearing all RIPng routes (VRF %s)",
- ripng->vrf_name);
-
- /* Clear received RIPng routes */
- for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
- struct list *list;
- struct listnode *listnode;
- struct ripng_info *rinfo;
-
- list = rp->info;
- if (list == NULL)
- continue;
-
- for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- if (!ripng_route_rte(rinfo))
- continue;
-
- if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
- ripng_zebra_ipv6_delete(ripng, rp);
- break;
- }
-
- if (rinfo) {
- RIPNG_TIMER_OFF(rinfo->t_timeout);
- RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
- listnode_delete(list, rinfo);
- ripng_info_free(rinfo);
- }
-
- if (list_isempty(list)) {
- list_delete(&list);
- rp->info = NULL;
- agg_unlock_node(rp);
- }
- }
-}
-
-static int clear_ripng_route_rpc(const char *xpath, const struct list *input,
- struct list *output)
-{
- struct ripng *ripng;
- struct yang_data *yang_vrf;
-
- yang_vrf = yang_data_list_find(input, "%s/%s", xpath, "input/vrf");
- if (yang_vrf) {
- ripng = ripng_lookup_by_vrf_name(yang_vrf->value);
- if (ripng)
- clear_ripng_route(ripng);
- } else {
- struct vrf *vrf;
-
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- ripng = vrf->info;
- if (!ripng)
- continue;
-
- clear_ripng_route(ripng);
- }
- }
-
- return NB_OK;
-}
-
-/*
- * XPath: /frr-interface:lib/interface/frr-ripngd:ripng/split-horizon
- */
-static int
-lib_interface_ripng_split_horizon_modify(enum nb_event event,
- const struct lyd_node *dnode,
- union nb_resource *resource)
-{
- struct interface *ifp;
- struct ripng_interface *ri;
-
- if (event != NB_EV_APPLY)
- return NB_OK;
-
- ifp = nb_running_get_entry(dnode, NULL, true);
- ri = ifp->info;
- ri->split_horizon = yang_dnode_get_enum(dnode, NULL);
-
- return NB_OK;
-}
-
-/* clang-format off */
-const struct frr_yang_module_info frr_ripngd_info = {
- .name = "frr-ripngd",
- .nodes = {
- {
- .xpath = "/frr-ripngd:ripngd/instance",
- .cbs = {
- .cli_show = cli_show_router_ripng,
- .create = ripngd_instance_create,
- .destroy = ripngd_instance_destroy,
- .get_keys = ripngd_instance_get_keys,
- .get_next = ripngd_instance_get_next,
- .lookup_entry = ripngd_instance_lookup_entry,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/allow-ecmp",
- .cbs = {
- .cli_show = cli_show_ripng_allow_ecmp,
- .modify = ripngd_instance_allow_ecmp_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/default-information-originate",
- .cbs = {
- .cli_show = cli_show_ripng_default_information_originate,
- .modify = ripngd_instance_default_information_originate_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/default-metric",
- .cbs = {
- .cli_show = cli_show_ripng_default_metric,
- .modify = ripngd_instance_default_metric_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/network",
- .cbs = {
- .cli_show = cli_show_ripng_network_prefix,
- .create = ripngd_instance_network_create,
- .destroy = ripngd_instance_network_destroy,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/interface",
- .cbs = {
- .cli_show = cli_show_ripng_network_interface,
- .create = ripngd_instance_interface_create,
- .destroy = ripngd_instance_interface_destroy,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/offset-list",
- .cbs = {
- .cli_show = cli_show_ripng_offset_list,
- .create = ripngd_instance_offset_list_create,
- .destroy = ripngd_instance_offset_list_destroy,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/offset-list/access-list",
- .cbs = {
- .modify = ripngd_instance_offset_list_access_list_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/offset-list/metric",
- .cbs = {
- .modify = ripngd_instance_offset_list_metric_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/passive-interface",
- .cbs = {
- .cli_show = cli_show_ripng_passive_interface,
- .create = ripngd_instance_passive_interface_create,
- .destroy = ripngd_instance_passive_interface_destroy,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/redistribute",
- .cbs = {
- .apply_finish = ripngd_instance_redistribute_apply_finish,
- .cli_show = cli_show_ripng_redistribute,
- .create = ripngd_instance_redistribute_create,
- .destroy = ripngd_instance_redistribute_destroy,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map",
- .cbs = {
- .destroy = ripngd_instance_redistribute_route_map_destroy,
- .modify = ripngd_instance_redistribute_route_map_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/redistribute/metric",
- .cbs = {
- .destroy = ripngd_instance_redistribute_metric_destroy,
- .modify = ripngd_instance_redistribute_metric_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/static-route",
- .cbs = {
- .cli_show = cli_show_ripng_route,
- .create = ripngd_instance_static_route_create,
- .destroy = ripngd_instance_static_route_destroy,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/aggregate-address",
- .cbs = {
- .cli_show = cli_show_ripng_aggregate_address,
- .create = ripngd_instance_aggregate_address_create,
- .destroy = ripngd_instance_aggregate_address_destroy,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/timers",
- .cbs = {
- .apply_finish = ripngd_instance_timers_apply_finish,
- .cli_show = cli_show_ripng_timers,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/timers/flush-interval",
- .cbs = {
- .modify = ripngd_instance_timers_flush_interval_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/timers/holddown-interval",
- .cbs = {
- .modify = ripngd_instance_timers_holddown_interval_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/timers/update-interval",
- .cbs = {
- .modify = ripngd_instance_timers_update_interval_modify,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor",
- .cbs = {
- .get_keys = ripngd_instance_state_neighbors_neighbor_get_keys,
- .get_next = ripngd_instance_state_neighbors_neighbor_get_next,
- .lookup_entry = ripngd_instance_state_neighbors_neighbor_lookup_entry,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/address",
- .cbs = {
- .get_elem = ripngd_instance_state_neighbors_neighbor_address_get_elem,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/last-update",
- .cbs = {
- .get_elem = ripngd_instance_state_neighbors_neighbor_last_update_get_elem,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-packets-rcvd",
- .cbs = {
- .get_elem = ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-routes-rcvd",
- .cbs = {
- .get_elem = ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/routes/route",
- .cbs = {
- .get_keys = ripngd_instance_state_routes_route_get_keys,
- .get_next = ripngd_instance_state_routes_route_get_next,
- .lookup_entry = ripngd_instance_state_routes_route_lookup_entry,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/prefix",
- .cbs = {
- .get_elem = ripngd_instance_state_routes_route_prefix_get_elem,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/next-hop",
- .cbs = {
- .get_elem = ripngd_instance_state_routes_route_next_hop_get_elem,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/interface",
- .cbs = {
- .get_elem = ripngd_instance_state_routes_route_interface_get_elem,
- },
- },
- {
- .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/metric",
- .cbs = {
- .get_elem = ripngd_instance_state_routes_route_metric_get_elem,
- },
- },
- {
- .xpath = "/frr-ripngd:clear-ripng-route",
- .cbs = {
- .rpc = clear_ripng_route_rpc,
- },
- },
- {
- .xpath = "/frr-interface:lib/interface/frr-ripngd:ripng/split-horizon",
- .cbs = {
- .cli_show = cli_show_ipv6_ripng_split_horizon,
- .modify = lib_interface_ripng_split_horizon_modify,
- },
- },
- {
- .xpath = NULL,
- },
- }
-};
diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h
index 5a0d350a84..70508d5cb0 100644
--- a/ripngd/ripngd.h
+++ b/ripngd/ripngd.h
@@ -494,9 +494,6 @@ extern struct ripng_info *ripng_ecmp_delete(struct ripng *ripng,
extern void ripng_vrf_init(void);
extern void ripng_vrf_terminate(void);
-
-/* Northbound. */
extern void ripng_cli_init(void);
-extern const struct frr_yang_module_info frr_ripngd_info;
#endif /* _ZEBRA_RIPNG_RIPNGD_H */
diff --git a/ripngd/subdir.am b/ripngd/subdir.am
index eac0d67313..07d0cb892c 100644
--- a/ripngd/subdir.am
+++ b/ripngd/subdir.am
@@ -19,7 +19,10 @@ ripngd_libripng_a_SOURCES = \
ripngd/ripng_interface.c \
ripngd/ripng_nexthop.c \
ripngd/ripng_offset.c \
- ripngd/ripng_northbound.c \
+ ripngd/ripng_nb.c \
+ ripngd/ripng_nb_config.c \
+ ripngd/ripng_nb_rpcs.c \
+ ripngd/ripng_nb_state.c \
ripngd/ripng_peer.c \
ripngd/ripng_route.c \
ripngd/ripng_routemap.c \
@@ -31,8 +34,8 @@ ripngd/ripng_cli_clippy.c: $(CLIPPY_DEPS)
ripngd/ripng_cli.$(OBJEXT): ripngd/ripng_cli_clippy.c
noinst_HEADERS += \
- ripngd/ripng_cli.h \
ripngd/ripng_debug.h \
+ ripngd/ripng_nb.h \
ripngd/ripng_nexthop.h \
ripngd/ripng_route.h \
ripngd/ripngd.h \
diff --git a/tests/topotests/Dockerfile b/tests/topotests/Dockerfile
index fc6d6df530..cdd0ae2f6e 100644
--- a/tests/topotests/Dockerfile
+++ b/tests/topotests/Dockerfile
@@ -6,9 +6,11 @@ RUN export DEBIAN_FRONTEND=noninteractive \
autoconf \
binutils \
bison \
+ ca-certificates \
flex \
gdb \
git \
+ gpg \
install-info \
iputils-ping \
iproute2 \
@@ -38,17 +40,15 @@ RUN export DEBIAN_FRONTEND=noninteractive \
&& pip install \
exabgp==3.4.17 \
ipaddr \
- pytest
+ pytest \
+ && rm -rf /var/lib/apt/lists/*
-RUN cd /tmp \
- && wget -q https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/Debian-AMD64-Packages/libyang-dev_0.16.105-1_amd64.deb \
- -O libyang-dev.deb \
- && wget -q https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-10/Debian-AMD64-Packages/libyang0.16_0.16.105-1_amd64.deb \
- -O libyang.deb \
- && echo "34bef017e527a590020185f05dc39203bdf1c86223e0d990839623ec629d8598 libyang.deb" | sha256sum -c - \
- && echo "fe9cc6e3b173ca56ef49428c281e96bf76c0f910aa75cf85098076411484e8f4 libyang-dev.deb" | sha256sum -c - \
- && dpkg -i libyang*.deb \
- && rm libyang*.deb
+RUN export DEBIAN_FRONTEND=noninteractive \
+ && apt-key adv --keyserver keyserver.ubuntu.com --recv-key 5418F291D0D4A1AA \
+ && echo "deb https://deb.frrouting.org/frr bionic frr-stable" > /etc/apt/sources.list.d/frr.list \
+ && apt-get update \
+ && apt-get install -y libyang-dev \
+ && rm -rf /var/lib/apt/lists/*
RUN groupadd -r -g 92 frr \
&& groupadd -r -g 85 frrvty \
diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c
index 14f648e8da..cbdf01e7b8 100644
--- a/tools/gen_northbound_callbacks.c
+++ b/tools/gen_northbound_callbacks.c
@@ -26,10 +26,12 @@
#include "yang.h"
#include "northbound.h"
+static bool static_cbs;
+
static void __attribute__((noreturn)) usage(int status)
{
extern const char *__progname;
- fprintf(stderr, "usage: %s [-h] [-p path] MODULE\n", __progname);
+ fprintf(stderr, "usage: %s [-h] [-s] [-p path] MODULE\n", __progname);
exit(status);
}
@@ -153,10 +155,46 @@ static void generate_callback_name(struct lys_node *snode,
replace_hyphens_by_underscores(buffer);
}
+static void generate_prototype(const struct nb_callback_info *ncinfo,
+ const char *cb_name)
+{
+ printf("%s%s(%s);\n", ncinfo->return_type, cb_name, ncinfo->arguments);
+}
+
+static int generate_prototypes(const struct lys_node *snode, void *arg)
+{
+ switch (snode->nodetype) {
+ case LYS_CONTAINER:
+ case LYS_LEAF:
+ case LYS_LEAFLIST:
+ case LYS_LIST:
+ case LYS_NOTIF:
+ case LYS_RPC:
+ break;
+ default:
+ return YANG_ITER_CONTINUE;
+ }
+
+ for (struct nb_callback_info *cb = &nb_callbacks[0];
+ cb->operation != -1; cb++) {
+ char cb_name[BUFSIZ];
+
+ if (cb->optional
+ || !nb_operation_is_valid(cb->operation, snode))
+ continue;
+
+ generate_callback_name((struct lys_node *)snode, cb->operation,
+ cb_name, sizeof(cb_name));
+ generate_prototype(cb, cb_name);
+ }
+
+ return YANG_ITER_CONTINUE;
+}
+
static void generate_callback(const struct nb_callback_info *ncinfo,
const char *cb_name)
{
- printf("static %s%s(%s)\n{\n",
+ printf("%s%s%s(%s)\n{\n", static_cbs ? "static " : "",
ncinfo->return_type, cb_name, ncinfo->arguments);
switch (ncinfo->operation) {
@@ -287,7 +325,7 @@ int main(int argc, char *argv[])
struct stat st;
int opt;
- while ((opt = getopt(argc, argv, "hp:")) != -1) {
+ while ((opt = getopt(argc, argv, "hp:s")) != -1) {
switch (opt) {
case 'h':
usage(EXIT_SUCCESS);
@@ -307,6 +345,9 @@ int main(int argc, char *argv[])
search_path = optarg;
break;
+ case 's':
+ static_cbs = true;
+ break;
default:
usage(EXIT_FAILURE);
/* NOTREACHED */
@@ -332,6 +373,14 @@ int main(int argc, char *argv[])
/* Create a nb_node for all YANG schema nodes. */
nb_nodes_create();
+ /* Generate callback prototypes. */
+ if (!static_cbs) {
+ printf("/* prototypes */\n");
+ yang_snodes_iterate_module(module->info, generate_prototypes, 0,
+ NULL);
+ printf("\n");
+ }
+
/* Generate callback functions. */
yang_snodes_iterate_module(module->info, generate_callbacks, 0, NULL);
diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c
index 54089b3612..eed0e8a31a 100644
--- a/vrrpd/vrrp.c
+++ b/vrrpd/vrrp.c
@@ -281,7 +281,7 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
{
struct vrrp_router *r;
bool start;
- const char *whynot;
+ const char *whynot = NULL;
if (vr->shutdown || vr->ifp == NULL)
return;
@@ -289,16 +289,17 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
r = vr->v4;
/* Must not already be started */
start = r->fsm.state == VRRP_STATE_INITIALIZE;
- whynot = NULL;
+ whynot = (!start && !whynot) ? "Already running" : whynot;
/* Must have a parent interface */
start = start && (vr->ifp != NULL);
whynot = (!start && !whynot) ? "No base interface" : whynot;
#if 0
/* Parent interface must be up */
start = start && if_is_operative(vr->ifp);
+ start = (!start && !whynot) ? "Base interface inoperative" : whynot;
#endif
/* Parent interface must have at least one v4 */
- start = start && vr->ifp->connected->count > 1;
+ start = start && connected_count_by_family(vr->ifp, AF_INET) > 0;
whynot = (!start && !whynot) ? "No primary IPv4 address" : whynot;
/* Must have a macvlan interface */
start = start && (r->mvl_ifp != NULL);
@@ -306,6 +307,7 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
#if 0
/* Macvlan interface must be admin up */
start = start && CHECK_FLAG(r->mvl_ifp->flags, IFF_UP);
+ start = (!start && !whynot) ? "Macvlan device admin down" : whynot;
#endif
/* Must have at least one VIP configured */
start = start && r->addrs->count > 0;
@@ -318,10 +320,12 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
"Refusing to start Virtual Router: %s",
vr->vrid, family2str(r->family), whynot);
+ whynot = NULL;
+
r = vr->v6;
/* Must not already be started */
start = r->fsm.state == VRRP_STATE_INITIALIZE;
- whynot = NULL;
+ whynot = (!start && !whynot) ? "Already running" : whynot;
/* Must not be v2 */
start = start && vr->version != 2;
whynot = (!start && !whynot) ? "VRRPv2 does not support v6" : whynot;
@@ -331,6 +335,7 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
#if 0
/* Parent interface must be up */
start = start && if_is_operative(vr->ifp);
+ start = (!start && !whynot) ? "Base interface inoperative" : whynot;
#endif
/* Must have a macvlan interface */
start = start && (r->mvl_ifp != NULL);
@@ -338,20 +343,21 @@ void vrrp_check_start(struct vrrp_vrouter *vr)
#if 0
/* Macvlan interface must be admin up */
start = start && CHECK_FLAG(r->mvl_ifp->flags, IFF_UP);
+ start = (!start && !whynot) ? "Macvlan device admin down" : whynot;
/* Macvlan interface must have a link local */
start = start && connected_get_linklocal(r->mvl_ifp);
whynot =
- (!start && !whynot) ? "No link local address configured" : NULL;
+ (!start && !whynot) ? "No link local address configured" : whynot;
/* Macvlan interface must have a v6 IP besides the link local */
- start = start && (r->mvl_ifp->connected->count >= 2);
+ start = start && (connected_count_by_family(r->mvl_ifp, AF_INET6) > 1);
whynot = (!start && !whynot)
- ? "No Virtual IP configured on macvlan device"
- : NULL;
+ ? "No Virtual IPv6 address configured on macvlan device"
+ : whynot;
#endif
/* Must have at least one VIP configured */
start = start && r->addrs->count > 0;
whynot =
- (!start && !whynot) ? "No Virtual IP address configured" : NULL;
+ (!start && !whynot) ? "No Virtual IP address configured" : whynot;
if (start)
vrrp_event(r, VRRP_EVENT_STARTUP);
else if (whynot)
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 640802fe31..915ad1a10c 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -2246,6 +2246,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
enum nexthop_types_t type = 0;
int if_index = 0;
size_t sz = 0;
+ struct interface *ifp_lookup;
if_index = *(int *)RTA_DATA(tb[NHA_OIF]);
@@ -2280,9 +2281,13 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
if (if_index)
nh.ifindex = if_index;
- *ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex);
+ ifp_lookup =
+ if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex);
+
if (ifp)
- nh.vrf_id = (*ifp)->vrf_id;
+ *ifp = ifp_lookup;
+ if (ifp_lookup)
+ nh.vrf_id = ifp_lookup->vrf_id;
else {
flog_warn(
EC_ZEBRA_UNKNOWN_INTERFACE,
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 2bb117b272..05da25b2b8 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -886,8 +886,7 @@ static void nhg_ctx_process_finish(struct nhg_ctx *ctx)
nexthop_del_labels(nh);
done:
- if (ctx)
- nhg_ctx_free(ctx);
+ nhg_ctx_free(ctx);
}
static int queue_add(struct nhg_ctx *ctx)
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 2417b505ad..1d2748c8ef 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -5775,12 +5775,14 @@ static void process_remote_macip_del(vni_t vni,
vlan_if = zvni_map_to_svi(vxl->access_vlan,
zif->brslave_info.br_if);
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug("%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
- __PRETTY_FUNCTION__,
- ipaddr2str(ipaddr, buf1,
- sizeof(buf1)), n->flags,
- vlan_if->name);
- neigh_read_specific_ip(ipaddr, vlan_if);
+ zlog_debug(
+ "%s: IP %s (flags 0x%x intf %s) is remote and duplicate, read kernel for local entry",
+ __PRETTY_FUNCTION__,
+ ipaddr2str(ipaddr, buf1, sizeof(buf1)),
+ n->flags,
+ vlan_if ? vlan_if->name : "Unknown");
+ if (vlan_if)
+ neigh_read_specific_ip(ipaddr, vlan_if);
}
/* When the MAC changes for an IP, it is possible the