diff options
193 files changed, 12944 insertions, 9774 deletions
diff --git a/.dir-locals.el b/.dir-locals.el index 21392ecf28..e47f245db7 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -2,7 +2,7 @@ ;;; For more information see (info "(emacs) Directory Variables") ;;; Match project coding conventions -((c-mode - (indent-tabs-mode . t) - (show-trailing-whitespace . t) - (c-basic-offset . 8))) +((c-mode . ((indent-tabs-mode . t) + (show-trailing-whitespace . t) + (c-basic-offset . 8) + ))) @@ -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 d2b60100e1..cc171f2ebf 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; @@ -312,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++; @@ -347,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)) @@ -582,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) @@ -596,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); @@ -868,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); @@ -1658,17 +1696,17 @@ static int bfd_vrf_enable(struct vrf *vrf) if (vrf->vrf_id == VRF_DEFAULT || vrf_get_backend() == VRF_BACKEND_NETNS) { if (!bvrf->bg_shop) - bvrf->bg_shop = bp_udp_shop(vrf->vrf_id); + bvrf->bg_shop = bp_udp_shop(vrf); if (!bvrf->bg_mhop) - bvrf->bg_mhop = bp_udp_mhop(vrf->vrf_id); + bvrf->bg_mhop = bp_udp_mhop(vrf); if (!bvrf->bg_shop6) - bvrf->bg_shop6 = bp_udp6_shop(vrf->vrf_id); + bvrf->bg_shop6 = bp_udp6_shop(vrf); if (!bvrf->bg_mhop6) - bvrf->bg_mhop6 = bp_udp6_mhop(vrf->vrf_id); + bvrf->bg_mhop6 = bp_udp6_mhop(vrf); if (!bvrf->bg_echo) - bvrf->bg_echo = bp_echo_socket(vrf->vrf_id); + bvrf->bg_echo = bp_echo_socket(vrf); if (!bvrf->bg_echov6) - bvrf->bg_echov6 = bp_echov6_socket(vrf->vrf_id); + bvrf->bg_echov6 = bp_echov6_socket(vrf); /* Add descriptors to the event loop. */ if (!bvrf->bg_ev[0]) diff --git a/bfdd/bfd.h b/bfdd/bfd.h index a9c8bd183a..eddfde62fb 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); @@ -461,14 +461,14 @@ int bp_set_tosv6(int sd, uint8_t value); int bp_set_tos(int sd, uint8_t value); int bp_bind_dev(int sd, const char *dev); -int bp_udp_shop(vrf_id_t vrf_id); -int bp_udp_mhop(vrf_id_t vrf_id); -int bp_udp6_shop(vrf_id_t vrf_id); -int bp_udp6_mhop(vrf_id_t vrf_id); +int bp_udp_shop(const struct vrf *vrf); +int bp_udp_mhop(const struct vrf *vrf); +int bp_udp6_shop(const struct vrf *vrf); +int bp_udp6_mhop(const struct vrf *vrf); int bp_peer_socket(const struct bfd_session *bs); int bp_peer_socketv6(const struct bfd_session *bs); -int bp_echo_socket(vrf_id_t vrf_id); -int bp_echov6_socket(vrf_id_t vrf_id); +int bp_echo_socket(const struct vrf *vrf); +int bp_echov6_socket(const struct vrf *vrf); void ptm_bfd_snd(struct bfd_session *bfd, int fbit); void ptm_bfd_echo_snd(struct bfd_session *bfd); @@ -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 ed36bb742e..6da5e2cdf9 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -523,13 +523,14 @@ int bfd_recv_cb(struct thread *t) bool is_mhop; ssize_t mlen = 0; uint8_t ttl = 0; - vrf_id_t vrfid = VRF_DEFAULT; + vrf_id_t vrfid; ifindex_t ifindex = IFINDEX_INTERNAL; struct sockaddr_any local, peer; uint8_t msgbuf[1516]; struct bfd_vrf_global *bvrf = THREAD_ARG(t); vrfid = bvrf->vrf->vrf_id; + /* Schedule next read. */ bfd_sd_reschedule(bvrf, sd); @@ -889,12 +890,13 @@ static void bp_bind_ip(int sd, uint16_t port) log_fatal("bind-ip: bind: %s", strerror(errno)); } -int bp_udp_shop(vrf_id_t vrf_id) +int bp_udp_shop(const struct vrf *vrf) { int sd; frr_with_privs(&bglobal.bfdd_privs) { - sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id, + vrf->name); } if (sd == -1) log_fatal("udp-shop: socket: %s", strerror(errno)); @@ -904,12 +906,13 @@ int bp_udp_shop(vrf_id_t vrf_id) return sd; } -int bp_udp_mhop(vrf_id_t vrf_id) +int bp_udp_mhop(const struct vrf *vrf) { int sd; frr_with_privs(&bglobal.bfdd_privs) { - sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + sd = vrf_socket(AF_INET, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id, + vrf->name); } if (sd == -1) log_fatal("udp-mhop: socket: %s", strerror(errno)); @@ -1116,12 +1119,13 @@ static void bp_bind_ipv6(int sd, uint16_t port) log_fatal("bind-ipv6: bind: %s", strerror(errno)); } -int bp_udp6_shop(vrf_id_t vrf_id) +int bp_udp6_shop(const struct vrf *vrf) { int sd; frr_with_privs(&bglobal.bfdd_privs) { - sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id, + vrf->name); } if (sd == -1) log_fatal("udp6-shop: socket: %s", strerror(errno)); @@ -1132,12 +1136,13 @@ int bp_udp6_shop(vrf_id_t vrf_id) return sd; } -int bp_udp6_mhop(vrf_id_t vrf_id) +int bp_udp6_mhop(const struct vrf *vrf) { int sd; frr_with_privs(&bglobal.bfdd_privs) { - sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf_id, NULL); + sd = vrf_socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC, vrf->vrf_id, + vrf->name); } if (sd == -1) log_fatal("udp6-mhop: socket: %s", strerror(errno)); @@ -1148,12 +1153,12 @@ int bp_udp6_mhop(vrf_id_t vrf_id) return sd; } -int bp_echo_socket(vrf_id_t vrf_id) +int bp_echo_socket(const struct vrf *vrf) { int s; frr_with_privs(&bglobal.bfdd_privs) { - s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL); + s = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf->vrf_id, vrf->name); } if (s == -1) log_fatal("echo-socket: socket: %s", strerror(errno)); @@ -1164,12 +1169,12 @@ int bp_echo_socket(vrf_id_t vrf_id) return s; } -int bp_echov6_socket(vrf_id_t vrf_id) +int bp_echov6_socket(const struct vrf *vrf) { int s; frr_with_privs(&bglobal.bfdd_privs) { - s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf_id, NULL); + s = vrf_socket(AF_INET6, SOCK_DGRAM, 0, vrf->vrf_id, vrf->name); } if (s == -1) log_fatal("echov6-socket: socket: %s", strerror(errno)); 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_addpath.c b/bgpd/bgp_addpath.c index 0ca4b613ee..cf51960b70 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -321,6 +321,7 @@ void bgp_addpath_type_changed(struct bgp *bgp) for (type=0; type<BGP_ADDPATH_MAX; type++) { peer_count[afi][safi][type] = 0; } + bgp->tx_addpath.total_peercount[afi][safi] = 0; } for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { @@ -328,6 +329,7 @@ void bgp_addpath_type_changed(struct bgp *bgp) type = peer->addpath_type[afi][safi]; if (type != BGP_ADDPATH_NONE) { peer_count[afi][safi][type] += 1; + bgp->tx_addpath.total_peercount[afi][safi] += 1; } } } diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 10e78cbc96..bfa578085d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2234,6 +2234,21 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type, } } + /* + * Placeholder code for Unsupported TLV + * - SRv6 L3 Service TLV (type5) + * - SRv6 L2 Service TLV (type6) + */ + else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE + || type == BGP_PREFIX_SID_SRV6_L2_SERVICE) { + if (bgp_debug_update(peer, NULL, NULL, 1)) + zlog_debug( + "%s attr Prefix-SID sub-type=%u is not supported, skipped", + peer->host, type); + for (int i = 0; i < length; i++) + stream_getc(peer->curr); + } + return BGP_ATTR_PARSE_PROCEED; } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index eacd37b652..375a2272e1 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -62,11 +62,17 @@ #define BGP_PREFIX_SID_LABEL_INDEX 1 #define BGP_PREFIX_SID_IPV6 2 #define BGP_PREFIX_SID_ORIGINATOR_SRGB 3 +#define BGP_PREFIX_SID_SRV6_L3_SERVICE 5 +#define BGP_PREFIX_SID_SRV6_L2_SERVICE 6 #define BGP_PREFIX_SID_LABEL_INDEX_LENGTH 7 #define BGP_PREFIX_SID_IPV6_LENGTH 19 #define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6 +#define BGP_ATTR_NH_AFI(afi, attr) \ + ((afi != AFI_L2VPN) ? afi : \ + ((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) ? AFI_IP : AFI_IP6)) + /* PMSI tunnel types (RFC 6514) */ struct bgp_attr_encap_subtlv { 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_damp.c b/bgpd/bgp_damp.c index cf085e46fb..b0fee079d1 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -37,8 +37,7 @@ #include "bgpd/bgp_advertise.h" /* Global variable to access damping configuration */ -struct bgp_damp_config bgp_damp_cfg; -static struct bgp_damp_config *damp = &bgp_damp_cfg; +static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; /* Utility macro to add and delete BGP dampening information to no used list. */ @@ -46,49 +45,51 @@ static struct bgp_damp_config *damp = &bgp_damp_cfg; #define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list) /* Calculate reuse list index by penalty value. */ -static int bgp_reuse_index(int penalty) +static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc) { unsigned int i; int index; - i = (int)(((double)penalty / damp->reuse_limit - 1.0) - * damp->scale_factor); + i = (int)(((double)penalty / bdc->reuse_limit - 1.0) + * bdc->scale_factor); - if (i >= damp->reuse_index_size) - i = damp->reuse_index_size - 1; + if (i >= bdc->reuse_index_size) + i = bdc->reuse_index_size - 1; - index = damp->reuse_index[i] - damp->reuse_index[0]; + index = bdc->reuse_index[i] - bdc->reuse_index[0]; - return (damp->reuse_offset + index) % damp->reuse_list_size; + return (bdc->reuse_offset + index) % bdc->reuse_list_size; } /* Add BGP dampening information to reuse list. */ -static void bgp_reuse_list_add(struct bgp_damp_info *bdi) +static void bgp_reuse_list_add(struct bgp_damp_info *bdi, + struct bgp_damp_config *bdc) { int index; - index = bdi->index = bgp_reuse_index(bdi->penalty); + index = bdi->index = bgp_reuse_index(bdi->penalty, bdc); bdi->prev = NULL; - bdi->next = damp->reuse_list[index]; - if (damp->reuse_list[index]) - damp->reuse_list[index]->prev = bdi; - damp->reuse_list[index] = bdi; + bdi->next = bdc->reuse_list[index]; + if (bdc->reuse_list[index]) + bdc->reuse_list[index]->prev = bdi; + bdc->reuse_list[index] = bdi; } /* Delete BGP dampening information from reuse list. */ -static void bgp_reuse_list_delete(struct bgp_damp_info *bdi) +static void bgp_reuse_list_delete(struct bgp_damp_info *bdi, + struct bgp_damp_config *bdc) { if (bdi->next) bdi->next->prev = bdi->prev; if (bdi->prev) bdi->prev->next = bdi->next; else - damp->reuse_list[bdi->index] = bdi->next; + bdc->reuse_list[bdi->index] = bdi->next; } /* Return decayed penalty value. */ -int bgp_damp_decay(time_t tdiff, int penalty) +int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc) { unsigned int i; @@ -97,10 +98,10 @@ int bgp_damp_decay(time_t tdiff, int penalty) if (i == 0) return penalty; - if (i >= damp->decay_array_size) + if (i >= bdc->decay_array_size) return 0; - return (int)(penalty * damp->decay_array[i]); + return (int)(penalty * bdc->decay_array[i]); } /* Handler of reuse timer event. Each route in the current reuse-list @@ -111,20 +112,22 @@ static int bgp_reuse_timer(struct thread *t) struct bgp_damp_info *next; time_t t_now, t_diff; - damp->t_reuse = NULL; - thread_add_timer(bm->master, bgp_reuse_timer, NULL, DELTA_REUSE, - &damp->t_reuse); + struct bgp_damp_config *bdc = THREAD_ARG(t); + + bdc->t_reuse = NULL; + thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE, + &bdc->t_reuse); t_now = bgp_clock(); /* 1. save a pointer to the current zeroth queue head and zero the list head entry. */ - bdi = damp->reuse_list[damp->reuse_offset]; - damp->reuse_list[damp->reuse_offset] = NULL; + bdi = bdc->reuse_list[bdc->reuse_offset]; + bdc->reuse_list[bdc->reuse_offset] = NULL; /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby rotating the circular queue of list-heads. */ - damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size; + bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size; /* 3. if ( the saved list head pointer is non-empty ) */ for (; bdi; bdi = next) { @@ -137,13 +140,13 @@ static int bgp_reuse_timer(struct thread *t) /* Set figure-of-merit = figure-of-merit * decay-array-ok * [t-diff] */ - bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty); + bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc); /* Set t-updated = t-now. */ bdi->t_updated = t_now; /* if (figure-of-merit < reuse). */ - if (bdi->penalty < damp->reuse_limit) { + if (bdi->penalty < bdc->reuse_limit) { /* Reuse the route. */ bgp_path_info_unset_flag(bdi->rn, bdi->path, BGP_PATH_DAMPED); @@ -158,14 +161,14 @@ static int bgp_reuse_timer(struct thread *t) bgp_process(bgp, bdi->rn, bdi->afi, bdi->safi); } - if (bdi->penalty <= damp->reuse_limit / 2.0) - bgp_damp_info_free(bdi, 1); + if (bdi->penalty <= bdc->reuse_limit / 2.0) + bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi); else - BGP_DAMP_LIST_ADD(damp, bdi); + BGP_DAMP_LIST_ADD(bdc, bdi); } else /* Re-insert into another list (See RFC2439 Section * 4.8.6). */ - bgp_reuse_list_add(bdi); + bgp_reuse_list_add(bdi, bdc); } return 0; @@ -178,6 +181,7 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn, time_t t_now; struct bgp_damp_info *bdi = NULL; unsigned int last_penalty = 0; + struct bgp_damp_config *bdc = &damp[afi][safi]; t_now = bgp_clock(); @@ -206,18 +210,18 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn, bdi->afi = afi; bdi->safi = safi; (bgp_path_info_extra_get(path))->damp_info = bdi; - BGP_DAMP_LIST_ADD(damp, bdi); + BGP_DAMP_LIST_ADD(bdc, bdi); } else { last_penalty = bdi->penalty; /* 1. Set t-diff = t-now - t-updated. */ - bdi->penalty = - (bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty) - + (attr_change ? DEFAULT_PENALTY / 2 - : DEFAULT_PENALTY)); + bdi->penalty = (bgp_damp_decay(t_now - bdi->t_updated, + bdi->penalty, bdc) + + (attr_change ? DEFAULT_PENALTY / 2 + : DEFAULT_PENALTY)); - if (bdi->penalty > damp->ceiling) - bdi->penalty = damp->ceiling; + if (bdi->penalty > bdc->ceiling) + bdi->penalty = bdc->ceiling; bdi->flap++; } @@ -234,19 +238,19 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn, if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) { /* If decay rate isn't equal to 0, reinsert brn. */ if (bdi->penalty != last_penalty && bdi->index >= 0) { - bgp_reuse_list_delete(bdi); - bgp_reuse_list_add(bdi); + bgp_reuse_list_delete(bdi, bdc); + bgp_reuse_list_add(bdi, bdc); } return BGP_DAMP_SUPPRESSED; } /* If not suppressed before, do annonunce this withdraw and insert into reuse_list. */ - if (bdi->penalty >= damp->suppress_value) { + if (bdi->penalty >= bdc->suppress_value) { bgp_path_info_set_flag(rn, path, BGP_PATH_DAMPED); bdi->suppress_time = t_now; - BGP_DAMP_LIST_DEL(damp, bdi); - bgp_reuse_list_add(bdi); + BGP_DAMP_LIST_DEL(bdc, bdi); + bgp_reuse_list_add(bdi, bdc); } return BGP_DAMP_USED; @@ -258,6 +262,7 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_node *rn, afi_t afi, time_t t_now; struct bgp_damp_info *bdi; int status; + struct bgp_damp_config *bdc = &damp[afi][safi]; if (!path->extra || !((bdi = path->extra->damp_info))) return BGP_DAMP_USED; @@ -266,76 +271,35 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_node *rn, afi_t afi, bgp_path_info_unset_flag(rn, path, BGP_PATH_HISTORY); bdi->lastrecord = BGP_RECORD_UPDATE; - bdi->penalty = bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty); + bdi->penalty = + bgp_damp_decay(t_now - bdi->t_updated, bdi->penalty, bdc); if (!CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED) - && (bdi->penalty < damp->suppress_value)) + && (bdi->penalty < bdc->suppress_value)) status = BGP_DAMP_USED; else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED) - && (bdi->penalty < damp->reuse_limit)) { + && (bdi->penalty < bdc->reuse_limit)) { bgp_path_info_unset_flag(rn, path, BGP_PATH_DAMPED); - bgp_reuse_list_delete(bdi); - BGP_DAMP_LIST_ADD(damp, bdi); + bgp_reuse_list_delete(bdi, bdc); + BGP_DAMP_LIST_ADD(bdc, bdi); bdi->suppress_time = 0; status = BGP_DAMP_USED; } else status = BGP_DAMP_SUPPRESSED; - if (bdi->penalty > damp->reuse_limit / 2.0) + if (bdi->penalty > bdc->reuse_limit / 2.0) bdi->t_updated = t_now; else - bgp_damp_info_free(bdi, 0); + bgp_damp_info_free(bdi, 0, afi, safi); return status; } -/* Remove dampening information and history route. */ -int bgp_damp_scan(struct bgp_path_info *path, afi_t afi, safi_t safi) -{ - time_t t_now, t_diff; - struct bgp_damp_info *bdi; - - assert(path->extra && path->extra->damp_info); - - t_now = bgp_clock(); - bdi = path->extra->damp_info; - - if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) { - t_diff = t_now - bdi->suppress_time; - - if (t_diff >= damp->max_suppress_time) { - bgp_path_info_unset_flag(bdi->rn, path, - BGP_PATH_DAMPED); - bgp_reuse_list_delete(bdi); - BGP_DAMP_LIST_ADD(damp, bdi); - bdi->penalty = damp->reuse_limit; - bdi->suppress_time = 0; - bdi->t_updated = t_now; - - /* Need to announce UPDATE once this path is usable - * again. */ - if (bdi->lastrecord == BGP_RECORD_UPDATE) - return 1; - else - return 0; - } - } else { - t_diff = t_now - bdi->t_updated; - bdi->penalty = bgp_damp_decay(t_diff, bdi->penalty); - - if (bdi->penalty <= damp->reuse_limit / 2.0) { - /* release the bdi, bdi->path. */ - bgp_damp_info_free(bdi, 1); - return 0; - } else - bdi->t_updated = t_now; - } - return 0; -} - -void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw) +void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi, + safi_t safi) { struct bgp_path_info *path; + struct bgp_damp_config *bdc = &damp[afi][safi]; if (!bdi) return; @@ -344,9 +308,9 @@ void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw) path->extra->damp_info = NULL; if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) - bgp_reuse_list_delete(bdi); + bgp_reuse_list_delete(bdi, bdc); else - BGP_DAMP_LIST_DEL(damp, bdi); + BGP_DAMP_LIST_DEL(bdc, bdi); bgp_path_info_unset_flag(bdi->rn, path, BGP_PATH_HISTORY | BGP_PATH_DAMPED); @@ -357,68 +321,67 @@ void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw) XFREE(MTYPE_BGP_DAMP_INFO, bdi); } -static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup) +static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup, + struct bgp_damp_config *bdc) { double reuse_max_ratio; unsigned int i; double j; - damp->suppress_value = sup; - damp->half_life = hlife; - damp->reuse_limit = reuse; - damp->max_suppress_time = maxsup; + bdc->suppress_value = sup; + bdc->half_life = hlife; + bdc->reuse_limit = reuse; + bdc->max_suppress_time = maxsup; /* Initialize params per bgp_damp_config. */ - damp->reuse_index_size = REUSE_ARRAY_SIZE; + bdc->reuse_index_size = REUSE_ARRAY_SIZE; - damp->ceiling = - (int)(damp->reuse_limit * (pow(2, - (double)damp->max_suppress_time - / damp->half_life))); + bdc->ceiling = (int)(bdc->reuse_limit + * (pow(2, (double)bdc->max_suppress_time + / bdc->half_life))); /* Decay-array computations */ - damp->decay_array_size = - ceil((double)damp->max_suppress_time / DELTA_T); - damp->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY, - sizeof(double) * (damp->decay_array_size)); - damp->decay_array[0] = 1.0; - damp->decay_array[1] = - exp((1.0 / ((double)damp->half_life / DELTA_T)) * log(0.5)); + bdc->decay_array_size = ceil((double)bdc->max_suppress_time / DELTA_T); + bdc->decay_array = XMALLOC(MTYPE_BGP_DAMP_ARRAY, + sizeof(double) * (bdc->decay_array_size)); + bdc->decay_array[0] = 1.0; + bdc->decay_array[1] = + exp((1.0 / ((double)bdc->half_life / DELTA_T)) * log(0.5)); /* Calculate decay values for all possible times */ - for (i = 2; i < damp->decay_array_size; i++) - damp->decay_array[i] = - damp->decay_array[i - 1] * damp->decay_array[1]; + for (i = 2; i < bdc->decay_array_size; i++) + bdc->decay_array[i] = + bdc->decay_array[i - 1] * bdc->decay_array[1]; /* Reuse-list computations */ - i = ceil((double)damp->max_suppress_time / DELTA_REUSE) + 1; + i = ceil((double)bdc->max_suppress_time / DELTA_REUSE) + 1; if (i > REUSE_LIST_SIZE || i == 0) i = REUSE_LIST_SIZE; - damp->reuse_list_size = i; + bdc->reuse_list_size = i; - damp->reuse_list = XCALLOC(MTYPE_BGP_DAMP_ARRAY, - damp->reuse_list_size - * sizeof(struct bgp_reuse_node *)); + bdc->reuse_list = + XCALLOC(MTYPE_BGP_DAMP_ARRAY, + bdc->reuse_list_size * sizeof(struct bgp_reuse_node *)); /* Reuse-array computations */ - damp->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY, - sizeof(int) * damp->reuse_index_size); + bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY, + sizeof(int) * bdc->reuse_index_size); - reuse_max_ratio = (double)damp->ceiling / damp->reuse_limit; - j = (exp((double)damp->max_suppress_time / damp->half_life) - * log10(2.0)); + reuse_max_ratio = (double)bdc->ceiling / bdc->reuse_limit; + j = (exp((double)bdc->max_suppress_time / bdc->half_life) * log10(2.0)); if (reuse_max_ratio > j && j != 0) reuse_max_ratio = j; - damp->scale_factor = - (double)damp->reuse_index_size / (reuse_max_ratio - 1); + bdc->scale_factor = + (double)bdc->reuse_index_size / (reuse_max_ratio - 1); - for (i = 0; i < damp->reuse_index_size; i++) { - damp->reuse_index[i] = - (int)(((double)damp->half_life / DELTA_REUSE) - * log10(1.0 / (damp->reuse_limit - * (1.0 + ((double)i - / damp->scale_factor)))) + for (i = 0; i < bdc->reuse_index_size; i++) { + bdc->reuse_index[i] = + (int)(((double)bdc->half_life / DELTA_REUSE) + * log10(1.0 + / (bdc->reuse_limit + * (1.0 + + ((double)i / bdc->scale_factor)))) / log10(0.5)); } } @@ -426,122 +389,129 @@ static void bgp_damp_parameter_set(int hlife, int reuse, int sup, int maxsup) int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, unsigned int reuse, unsigned int suppress, time_t max) { + struct bgp_damp_config *bdc = &damp[afi][safi]; + if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { - if (damp->half_life == half && damp->reuse_limit == reuse - && damp->suppress_value == suppress - && damp->max_suppress_time == max) + if (bdc->half_life == half && bdc->reuse_limit == reuse + && bdc->suppress_value == suppress + && bdc->max_suppress_time == max) return 0; bgp_damp_disable(bgp, afi, safi); } SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); - bgp_damp_parameter_set(half, reuse, suppress, max); + bgp_damp_parameter_set(half, reuse, suppress, max, bdc); /* Register reuse timer. */ - thread_add_timer(bm->master, bgp_reuse_timer, NULL, DELTA_REUSE, - &damp->t_reuse); + thread_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE, + &bdc->t_reuse); return 0; } -static void bgp_damp_config_clean(struct bgp_damp_config *damp) +static void bgp_damp_config_clean(struct bgp_damp_config *bdc) { /* Free decay array */ - XFREE(MTYPE_BGP_DAMP_ARRAY, damp->decay_array); - damp->decay_array_size = 0; + XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array); + bdc->decay_array_size = 0; /* Free reuse index array */ - XFREE(MTYPE_BGP_DAMP_ARRAY, damp->reuse_index); - damp->reuse_index_size = 0; + XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index); + bdc->reuse_index_size = 0; /* Free reuse list array. */ - XFREE(MTYPE_BGP_DAMP_ARRAY, damp->reuse_list); - damp->reuse_list_size = 0; + XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list); + bdc->reuse_list_size = 0; } /* Clean all the bgp_damp_info stored in reuse_list. */ -void bgp_damp_info_clean(void) +void bgp_damp_info_clean(afi_t afi, safi_t safi) { unsigned int i; struct bgp_damp_info *bdi, *next; + struct bgp_damp_config *bdc = &damp[afi][safi]; - damp->reuse_offset = 0; + bdc->reuse_offset = 0; - for (i = 0; i < damp->reuse_list_size; i++) { - if (!damp->reuse_list[i]) + for (i = 0; i < bdc->reuse_list_size; i++) { + if (!bdc->reuse_list[i]) continue; - for (bdi = damp->reuse_list[i]; bdi; bdi = next) { + for (bdi = bdc->reuse_list[i]; bdi; bdi = next) { next = bdi->next; - bgp_damp_info_free(bdi, 1); + bgp_damp_info_free(bdi, 1, afi, safi); } - damp->reuse_list[i] = NULL; + bdc->reuse_list[i] = NULL; } - for (bdi = damp->no_reuse_list; bdi; bdi = next) { + for (bdi = bdc->no_reuse_list; bdi; bdi = next) { next = bdi->next; - bgp_damp_info_free(bdi, 1); + bgp_damp_info_free(bdi, 1, afi, safi); } - damp->no_reuse_list = NULL; + bdc->no_reuse_list = NULL; } int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi) { + struct bgp_damp_config *bdc = &damp[afi][safi]; /* If it wasn't enabled, there's nothing to do. */ if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) return 0; /* Cancel reuse thread. */ - if (damp->t_reuse) - thread_cancel(damp->t_reuse); - damp->t_reuse = NULL; + if (bdc->t_reuse) + thread_cancel(bdc->t_reuse); + bdc->t_reuse = NULL; /* Clean BGP dampening information. */ - bgp_damp_info_clean(); + bgp_damp_info_clean(afi, safi); /* Clear configuration */ - bgp_damp_config_clean(&bgp_damp_cfg); + bgp_damp_config_clean(bdc); UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); return 0; } -void bgp_config_write_damp(struct vty *vty) +void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi) { - if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE * 60 - && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE - && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS - && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life * 4) - vty_out(vty, " bgp dampening\n"); - else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE * 60 - && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE - && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS - && bgp_damp_cfg.max_suppress_time - == bgp_damp_cfg.half_life * 4) - vty_out(vty, " bgp dampening %lld\n", - bgp_damp_cfg.half_life / 60LL); + if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60 + && damp[afi][safi].reuse_limit == DEFAULT_REUSE + && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS + && damp[afi][safi].max_suppress_time + == damp[afi][safi].half_life * 4) + vty_out(vty, " bgp dampening\n"); + else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60 + && damp[afi][safi].reuse_limit == DEFAULT_REUSE + && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS + && damp[afi][safi].max_suppress_time + == damp[afi][safi].half_life * 4) + vty_out(vty, " bgp dampening %lld\n", + damp[afi][safi].half_life / 60LL); else - vty_out(vty, " bgp dampening %lld %d %d %lld\n", - bgp_damp_cfg.half_life / 60LL, bgp_damp_cfg.reuse_limit, - bgp_damp_cfg.suppress_value, - bgp_damp_cfg.max_suppress_time / 60LL); + vty_out(vty, " bgp dampening %lld %d %d %lld\n", + damp[afi][safi].half_life / 60LL, + damp[afi][safi].reuse_limit, + damp[afi][safi].suppress_value, + damp[afi][safi].max_suppress_time / 60LL); } static const char *bgp_get_reuse_time(unsigned int penalty, char *buf, - size_t len, bool use_json, - json_object *json) + size_t len, afi_t afi, safi_t safi, + bool use_json, json_object *json) { time_t reuse_time = 0; struct tm *tm = NULL; int time_store = 0; - if (penalty > damp->reuse_limit) { + if (penalty > damp[afi][safi].reuse_limit) { reuse_time = (int)(DELTA_T - * ((log((double)damp->reuse_limit / penalty)) - / (log(damp->decay_array[1])))); + * ((log((double)damp[afi][safi].reuse_limit + / penalty)) + / (log(damp[afi][safi].decay_array[1])))); - if (reuse_time > damp->max_suppress_time) - reuse_time = damp->max_suppress_time; + if (reuse_time > damp[afi][safi].max_suppress_time) + reuse_time = damp[afi][safi].max_suppress_time; tm = gmtime(&reuse_time); } else @@ -593,13 +563,14 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf, return buf; } -void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, - json_object *json_path) +void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, + safi_t safi, json_object *json_path) { struct bgp_damp_info *bdi; time_t t_now, t_diff; char timebuf[BGP_UPTIME_LEN]; int penalty; + struct bgp_damp_config *bdc = &damp[afi][safi]; if (!path->extra) return; @@ -609,13 +580,13 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, /* If dampening is not enabled or there is no dampening information, return immediately. */ - if (!damp || !bdi) + if (!bdc || !bdi) return; /* Calculate new penalty. */ t_now = bgp_clock(); t_diff = t_now - bdi->t_updated; - penalty = bgp_damp_decay(t_diff, bdi->penalty); + penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc); if (json_path) { json_object_int_add(json_path, "dampeningPenalty", penalty); @@ -625,8 +596,8 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED) && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) - bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN, 1, - json_path); + bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN, + afi, safi, 1, json_path); } else { vty_out(vty, " Dampinfo: penalty %d, flapped %d times in %s", @@ -638,7 +609,7 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) vty_out(vty, ", reuse in %s", bgp_get_reuse_time(penalty, timebuf, - BGP_UPTIME_LEN, 0, + BGP_UPTIME_LEN, afi, safi, 0, json_path)); vty_out(vty, "\n"); @@ -646,12 +617,14 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, } const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, - char *timebuf, size_t len, bool use_json, + char *timebuf, size_t len, afi_t afi, + safi_t safi, bool use_json, json_object *json) { struct bgp_damp_info *bdi; time_t t_now, t_diff; int penalty; + struct bgp_damp_config *bdc = &damp[afi][safi]; if (!path->extra) return NULL; @@ -661,15 +634,16 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, /* If dampening is not enabled or there is no dampening information, return immediately. */ - if (!damp || !bdi) + if (!bdc || !bdi) return NULL; /* Calculate new penalty. */ t_now = bgp_clock(); t_diff = t_now - bdi->t_updated; - penalty = bgp_damp_decay(t_diff, bdi->penalty); + penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc); - return bgp_get_reuse_time(penalty, timebuf, len, use_json, json); + return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json, + json); } int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi) @@ -684,12 +658,15 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi) if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { vty_out(vty, "Half-life time: %lld min\n", - (long long)damp->half_life / 60); - vty_out(vty, "Reuse penalty: %d\n", damp->reuse_limit); - vty_out(vty, "Suppress penalty: %d\n", damp->suppress_value); + (long long)damp[afi][safi].half_life / 60); + vty_out(vty, "Reuse penalty: %d\n", + damp[afi][safi].reuse_limit); + vty_out(vty, "Suppress penalty: %d\n", + damp[afi][safi].suppress_value); vty_out(vty, "Max suppress time: %lld min\n", - (long long)damp->max_suppress_time / 60); - vty_out(vty, "Max suppress penalty: %u\n", damp->ceiling); + (long long)damp[afi][safi].max_suppress_time / 60); + vty_out(vty, "Max suppress penalty: %u\n", + damp[afi][safi].ceiling); vty_out(vty, "\n"); } else vty_out(vty, "dampening not enabled for %s\n", diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h index 18bf561c47..3dd860a29d 100644 --- a/bgpd/bgp_damp.h +++ b/bgpd/bgp_damp.h @@ -106,6 +106,9 @@ struct bgp_damp_config { /* Reuse timer thread per-set base. */ struct thread *t_reuse; + + afi_t afi; + safi_t safi; }; #define BGP_DAMP_NONE 0 @@ -134,17 +137,18 @@ extern int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_node *rn, afi_t afi, safi_t safi, int attr_change); extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_node *rn, afi_t afi, safi_t saff); -extern int bgp_damp_scan(struct bgp_path_info *path, afi_t afi, safi_t safi); -extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw); -extern void bgp_damp_info_clean(void); -extern int bgp_damp_decay(time_t, int); -extern void bgp_config_write_damp(struct vty *); +extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw, + afi_t afi, safi_t safi); +extern void bgp_damp_info_clean(afi_t afi, safi_t safi); +extern int bgp_damp_decay(time_t, int, struct bgp_damp_config *damp); +extern void bgp_config_write_damp(struct vty *, afi_t afi, safi_t safi); extern void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, - json_object *json_path); + afi_t afi, safi_t safi, json_object *json_path); extern const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, - char *timebuf, size_t len, - bool use_json, json_object *json); + char *timebuf, size_t len, afi_t afi, + safi_t safi, bool use_json, + json_object *json); extern int bgp_show_dampening_parameters(struct vty *vty, afi_t, safi_t); #endif /* _QUAGGA_BGP_DAMP_H */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index f476b16188..0e4c3a3e12 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -209,7 +209,7 @@ static void bgp_debug_list_free(struct list *list) listnode_delete(list, filter); if (filter->p) - prefix_free(filter->p); + prefix_free(&filter->p); if (filter->host) XFREE(MTYPE_BGP_DEBUG_STR, filter->host); @@ -323,7 +323,7 @@ static int bgp_debug_list_remove_entry(struct list *list, const char *host, } else if (p && filter->p->prefixlen == p->prefixlen && prefix_match(filter->p, p)) { listnode_delete(list, filter); - prefix_free(filter->p); + prefix_free(&filter->p); XFREE(MTYPE_BGP_DEBUG_FILTER, filter); return 1; } @@ -1412,7 +1412,7 @@ DEFPY (debug_bgp_update_prefix_afi_safi, ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); if (ret != CMD_SUCCESS) { - prefix_free(argv_p); + prefix_free(&argv_p); return ret; } @@ -1425,7 +1425,7 @@ DEFPY (debug_bgp_update_prefix_afi_safi, vty_out(vty, "BGP updates debugging is already enabled for %s\n", buf); - prefix_free(argv_p); + prefix_free(&argv_p); return CMD_SUCCESS; } @@ -1438,7 +1438,7 @@ DEFPY (debug_bgp_update_prefix_afi_safi, vty_out(vty, "BGP updates debugging is on for %s\n", buf); } - prefix_free(argv_p); + prefix_free(&argv_p); return CMD_SUCCESS; } @@ -1477,7 +1477,7 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi, ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); if (ret != CMD_SUCCESS) { - prefix_free(argv_p); + prefix_free(&argv_p); return ret; } @@ -1505,7 +1505,7 @@ DEFPY (no_debug_bgp_update_prefix_afi_safi, vty_out(vty, "BGP updates debugging was not enabled for %s\n", buf); - prefix_free(argv_p); + prefix_free(&argv_p); return ret; } diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 640224e759..f850cb49cf 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -234,9 +234,9 @@ static void bgp_dump_routes_index_table(struct bgp *bgp) stream_put_in_addr(obuf, &bgp->router_id); /* View name */ - if (bgp->name) { - stream_putw(obuf, strlen(bgp->name)); - stream_put(obuf, bgp->name, strlen(bgp->name)); + if (bgp->name_pretty) { + stream_putw(obuf, strlen(bgp->name_pretty)); + stream_put(obuf, bgp->name_pretty, strlen(bgp->name_pretty)); } else { stream_putw(obuf, 0); } diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 07d3f7b31e..35d54983dc 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2583,6 +2583,8 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Process for route leaking. */ vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi); + bgp_unlock_node(rn); + return ret; } @@ -2638,6 +2640,8 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* Perform route selection and update zebra, if required. */ ret = evpn_route_select_install(bgp, vpn, rn); + bgp_unlock_node(rn); + return ret; } @@ -6026,3 +6030,26 @@ int bgp_evpn_get_type5_prefixlen(struct prefix *pfx) return evp->prefix.prefix_addr.ip_prefix_length; } + +/* + * Should we register nexthop for this EVPN prefix for nexthop tracking? + */ +bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx) +{ + struct prefix_evpn *evp = (struct prefix_evpn *)pfx; + + /* + * EVPN RT-5 should not be marked as valid and imported to vrfs if the + * BGP nexthop is not reachable. To check for the nexthop reachability, + * Add nexthop for EVPN RT-5 for nexthop tracking. + * + * Ideally, a BGP route should be marked as valid only if the + * nexthop is reachable. Thus, other EVPN route types also should be + * added here after testing is performed for them. + */ + if (pfx && pfx->family == AF_EVPN && + evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE) + return true; + + return false; +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 6d1e8cd31b..798c3e59bc 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -191,5 +191,6 @@ extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp); extern void bgp_evpn_cleanup(struct bgp *bgp); extern void bgp_evpn_init(struct bgp *bgp); extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx); +extern bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 55f85eeb83..3bc8345140 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -298,7 +298,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty, if (json) json_object_string_add(json, "rd", rd_str); else - vty_out(vty, "as2 %s\n", rd_str); + vty_out(vty, "%s\n", rd_str); break; case RD_TYPE_AS4: @@ -307,7 +307,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty, if (json) json_object_string_add(json, "rd", rd_str); else - vty_out(vty, "as4 %s\n", rd_str); + vty_out(vty, "%s\n", rd_str); break; case RD_TYPE_IP: @@ -317,7 +317,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty, if (json) json_object_string_add(json, "rd", rd_str); else - vty_out(vty, "ip %s\n", rd_str); + vty_out(vty, "%s\n", rd_str); break; default: @@ -326,7 +326,7 @@ static void bgp_evpn_show_route_rd_header(struct vty *vty, json_object_string_add(json, "rd", rd_str); } else { snprintf(rd_str, len, "Unknown RD type"); - vty_out(vty, "ip %s\n", rd_str); + vty_out(vty, "%s\n", rd_str); } break; } @@ -2619,10 +2619,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, prefix_rd2str((struct prefix_rd *)&rd_rn->p, rd_str, sizeof(rd_str)); - if (json) { + if (json) json_rd = json_object_new_object(); - json_object_string_add(json_rd, "rd", rd_str); - } rd_header = 1; @@ -2659,7 +2657,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, /* RD header - per RD. */ if (rd_header) { bgp_evpn_show_route_rd_header( - vty, rd_rn, NULL, rd_str, + vty, rd_rn, json_rd, rd_str, RD_ADDRSTRLEN); rd_header = 0; } diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 0be8becbab..2e5b2e115c 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -1359,8 +1359,9 @@ static int bgp_connect_success(struct peer *peer) flog_err_sys(EC_LIB_SOCKET, "%s: bgp_getsockname(): failed for peer %s, fd %d", __FUNCTION__, peer->host, peer->fd); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, - 0); /* internal error */ + bgp_notify_send( + peer, BGP_NOTIFY_FSM_ERR, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); /* internal error */ bgp_writes_on(peer); return -1; } diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 74c45ed447..0969c8e77e 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -43,6 +43,7 @@ #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_flowspec_util.h" +#include "bgpd/bgp_evpn.h" extern struct zclient *zclient; @@ -65,34 +66,14 @@ static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc) || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID))); } -int bgp_find_nexthop(struct bgp_path_info *path, int connected) -{ - struct bgp_nexthop_cache *bnc = path->nexthop; - - if (!bnc) - return 0; - - /* - * We are cheating here. Views have no associated underlying - * ability to detect nexthops. So when we have a view - * just tell everyone the nexthop is valid - */ - if (path->peer && path->peer->bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) - return 1; - - if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))) - return 0; - - return (bgp_isvalid_nexthop(bnc)); -} - static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) { if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) { if (BGP_DEBUG(nht, NHT)) { char buf[PREFIX2STR_BUFFER]; - zlog_debug("bgp_unlink_nexthop: freeing bnc %s", - bnc_str(bnc, buf, PREFIX2STR_BUFFER)); + zlog_debug("bgp_unlink_nexthop: freeing bnc %s(%s)", + bnc_str(bnc, buf, PREFIX2STR_BUFFER), + bnc->bgp->name_pretty); } unregister_zebra_rnh(bnc, CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)); @@ -194,8 +175,9 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, if (BGP_DEBUG(nht, NHT)) { char buf[PREFIX2STR_BUFFER]; - zlog_debug("Allocated bnc %s peer %p", - bnc_str(bnc, buf, PREFIX2STR_BUFFER), peer); + zlog_debug("Allocated bnc %s(%s) peer %p", + bnc_str(bnc, buf, PREFIX2STR_BUFFER), + bnc->bgp->name_pretty, peer); } } @@ -291,16 +273,18 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer) peer->bgp->nexthop_cache_table[family2afi(p.family)], &p); if (!rn) { if (BGP_DEBUG(nht, NHT)) - zlog_debug("Cannot find connected NHT node for peer %s", - peer->host); + zlog_debug( + "Cannot find connected NHT node for peer %s(%s)", + peer->host, peer->bgp->name_pretty); return; } bnc = bgp_node_get_bgp_nexthop_info(rn); if (!bnc) { if (BGP_DEBUG(nht, NHT)) - zlog_debug("Cannot find connected NHT node for peer %s on route_node as expected", - peer->host); + zlog_debug( + "Cannot find connected NHT node for peer %s(%s) on route_node as expected", + peer->host, peer->bgp->name_pretty); bgp_unlock_node(rn); return; } @@ -309,8 +293,9 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer) if (bnc->nht_info != peer) { if (BGP_DEBUG(nht, NHT)) zlog_debug( - "Connected NHT %p node for peer %s points to %p", - bnc, peer->host, bnc->nht_info); + "Connected NHT %p node for peer %s(%s) points to %p", + bnc, peer->host, bnc->bgp->name_pretty, + bnc->nht_info); return; } @@ -318,8 +303,9 @@ void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer) if (LIST_EMPTY(&(bnc->paths))) { if (BGP_DEBUG(nht, NHT)) - zlog_debug("Freeing connected NHT node %p for peer %s", - bnc, peer->host); + zlog_debug( + "Freeing connected NHT node %p for peer %s(%s)", + bnc, peer->host, bnc->bgp->name_pretty); unregister_zebra_rnh(bnc, 0); bgp_node_set_bgp_nexthop_info(bnc->node, NULL); bgp_unlock_node(bnc->node); @@ -350,8 +336,8 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { if (BGP_DEBUG(nht, NHT)) - zlog_debug("%s: Failure to decode nexthop update", - __PRETTY_FUNCTION__); + zlog_debug("%s[%s]: Failure to decode nexthop update", + __PRETTY_FUNCTION__, bgp->name_pretty); return; } @@ -368,8 +354,8 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) if (BGP_DEBUG(nht, NHT)) { char buf[PREFIX2STR_BUFFER]; prefix2str(&nhr.prefix, buf, sizeof(buf)); - zlog_debug("parse nexthop update(%s): rn not found", - buf); + zlog_debug("parse nexthop update(%s(%s)): rn not found", + buf, bgp->name_pretty); } return; } @@ -380,8 +366,9 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) char buf[PREFIX2STR_BUFFER]; prefix2str(&nhr.prefix, buf, sizeof(buf)); - zlog_debug("parse nexthop update(%s): bnc node info not found", - buf); + zlog_debug( + "parse nexthop update(%s(%s)): bnc node info not found", + buf, bgp->name_pretty); } bgp_unlock_node(rn); return; @@ -396,9 +383,10 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) char buf[PREFIX2STR_BUFFER]; prefix2str(&nhr.prefix, buf, sizeof(buf)); zlog_debug( - "%u: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", - vrf_id, buf, nhr.metric, bnc->metric, nhr.nexthop_num, - bnc->nexthop_num, bnc->flags); + "%s(%u): Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", + bnc->bgp->name_pretty, vrf_id, buf, nhr.metric, + bnc->metric, nhr.nexthop_num, bnc->nexthop_num, + bnc->flags); } if (nhr.metric != bnc->metric) @@ -622,7 +610,7 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) prefix2str(p, buf, PREFIX2STR_BUFFER); zlog_debug("%s: sending cmd %s for %s (vrf %s)", __func__, zserv_command_string(command), buf, - bnc->bgp->name); + bnc->bgp->name_pretty); } ret = zclient_send_rnh(zclient, command, p, exact_match, @@ -702,8 +690,9 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc) char buf[PREFIX2STR_BUFFER]; bnc_str(bnc, buf, PREFIX2STR_BUFFER); zlog_debug( - "NH update for %s - flags 0x%x chgflags 0x%x - evaluate paths", - buf, bnc->flags, bnc->change_flags); + "NH update for %s(%s) - flags 0x%x chgflags 0x%x - evaluate paths", + buf, bnc->bgp->name_pretty, bnc->flags, + bnc->change_flags); } LIST_FOREACH (path, &(bnc->paths), nh_thread) { @@ -785,13 +774,24 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc) || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED); + if (safi == SAFI_EVPN && + bgp_evpn_is_prefix_nht_supported(&rn->p)) { + if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) + bgp_evpn_import_route(bgp_path, afi, safi, + &rn->p, path); + else + bgp_evpn_unimport_route(bgp_path, afi, safi, + &rn->p, path); + } + bgp_process(bgp_path, rn, afi, safi); } if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) { if (BGP_DEBUG(nht, NHT)) - zlog_debug("%s: Updating peer (%s) status with NHT", - __FUNCTION__, peer->host); + zlog_debug("%s: Updating peer (%s(%s)) status with NHT", + __FUNCTION__, peer->host, + peer->bgp->name_pretty); bgp_fsm_event_update(peer, bgp_isvalid_nexthop(bnc)); SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); } diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 7daae93b25..e39d55567a 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -27,14 +27,6 @@ extern void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id); /** - * bgp_find_nexthop() - lookup the nexthop cache table for the bnc object - * ARGUMENTS: - * p - path for which the nexthop object is being looked up - * connected - True if NH MUST be a connected route - */ -extern int bgp_find_nexthop(struct bgp_path_info *p, int connected); - -/** * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc * object. If not found, create a new object and register with ZEBRA for * nexthop notification. diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index c7c1780c21..5296246b31 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1420,7 +1420,8 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) "%s [FSM] Update packet received under status %s", peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0); + bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -1792,7 +1793,8 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) "%s [Error] Route refresh packet received under status %s", peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0); + bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -1827,7 +1829,8 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) < 5) { zlog_info("%s ORF route refresh length error", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -2061,7 +2064,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, * length. */ if (pnt + 3 > end) { zlog_info("%s Capability length error", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } action = *pnt; @@ -2072,7 +2076,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, && action != CAPABILITY_ACTION_UNSET) { zlog_info("%s Capability Action Value error %d", peer->host, action); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -2084,7 +2089,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, /* Capability length check. */ if ((pnt + hdr->length + 3) > end) { zlog_info("%s Capability length error", peer->host); - bgp_notify_send(peer, BGP_NOTIFY_CEASE, 0); + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } @@ -2188,7 +2194,8 @@ int bgp_capability_receive(struct peer *peer, bgp_size_t size) "%s [Error] Dynamic capability packet received under status %s", peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); - bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0); + bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, + BGP_NOTIFY_SUBCODE_UNSPECIFIC); return BGP_Stop; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index af73a3afc4..4fb4faebc2 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -196,7 +196,8 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) e = *extra; if (e->damp_info) - bgp_damp_info_free(e->damp_info, 0); + bgp_damp_info_free(e->damp_info, 0, e->damp_info->afi, + e->damp_info->safi); e->damp_info = NULL; if (e->parent) { @@ -1243,7 +1244,7 @@ static int bgp_cluster_filter(struct peer *peer, struct attr *attr) static int bgp_input_modifier(struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name, mpls_label_t *label, - uint32_t num_labels) + uint32_t num_labels, struct bgp_node *rn) { struct bgp_filter *filter; struct bgp_path_info rmap_path = { 0 }; @@ -1278,6 +1279,8 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p, rmap_path.peer = peer; rmap_path.attr = attr; rmap_path.extra = &extra; + rmap_path.net = rn; + extra.num_labels = num_labels; if (label && num_labels && num_labels <= BGP_MAX_LABELS) memcpy(extra.label, label, @@ -1639,9 +1642,9 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, return 0; } -#ifdef BGP_SEND_ASPATH_CHECK /* AS path loop check. */ - if (onlypeer && aspath_loop_check(piattr->aspath, onlypeer->as)) { + if (onlypeer && onlypeer->as_path_loop_detection + && aspath_loop_check(piattr->aspath, onlypeer->as)) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( "%s [Update:SEND] suppress announcement to peer AS %u " @@ -1649,7 +1652,6 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, onlypeer->host, onlypeer->as); return 0; } -#endif /* BGP_SEND_ASPATH_CHECK */ /* If we're a CONFED we need to loop check the CONFED ID too */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { @@ -1751,18 +1753,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 = @@ -1791,6 +1797,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, memset(&rmap_path, 0, sizeof(struct bgp_path_info)); rmap_path.peer = peer; rmap_path.attr = attr; + rmap_path.net = rn; if (pi->extra) { memcpy(&dummy_rmap_path_extra, pi->extra, @@ -1938,19 +1945,19 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi, __func__, family2str(family)); subgroup_announce_reset_nhop(family, attr); } + } - /* If IPv6/MP and nexthop does not have any override and happens - * to - * be a link-local address, reset it so that we don't pass along - * the - * source's link-local IPv6 address to recipients who may not be - * on - * the same interface. - */ - if (p->family == AF_INET6 || peer_cap_enhe(peer, afi, safi)) { - if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) - subgroup_announce_reset_nhop(AF_INET6, attr); - } + /* If IPv6/MP and nexthop does not have any override and happens + * to + * be a link-local address, reset it so that we don't pass along + * the + * source's link-local IPv6 address to recipients who may not be + * on + * the same interface. + */ + if (p->family == AF_INET6 || peer_cap_enhe(peer, afi, safi)) { + if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) + subgroup_announce_reset_nhop(AF_INET6, attr); } return 1; @@ -3034,6 +3041,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, int connected = 0; int do_loop_check = 1; int has_valid_label = 0; + afi_t nh_afi; #if ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; #endif @@ -3149,7 +3157,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, * intern * the attr (which takes over the memory references) */ if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL, - label, num_labels) == RMAP_DENY) { + label, num_labels, rn) == RMAP_DENY) { peer->stat_pfx_filter++; reason = "route-map;"; bgp_attr_flush(&new_attr); @@ -3429,8 +3437,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, /* Nexthop reachability check - for unicast and * labeled-unicast.. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { + if (((afi == AFI_IP || afi == AFI_IP6) + && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) + || (safi == SAFI_EVPN && + bgp_evpn_is_prefix_nht_supported(p))) { if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) @@ -3445,8 +3455,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, if (pi->extra && pi->extra->bgp_orig) bgp_nexthop = pi->extra->bgp_orig; - if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, pi, - NULL, connected) + nh_afi = BGP_ATTR_NH_AFI(afi, pi->attr); + + if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, nh_afi, + pi, NULL, connected) || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(rn, pi, BGP_PATH_VALID); else { @@ -3494,7 +3506,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, * updating * the attributes for the route in the VNI(s). */ - if (safi == SAFI_EVPN && !same_attr) + if (safi == SAFI_EVPN && !same_attr && + CHECK_FLAG(pi->flags, BGP_PATH_VALID)) bgp_evpn_import_route(bgp, afi, safi, p, pi); /* Process change. */ @@ -3567,8 +3580,9 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, evpn == NULL ? NULL : &evpn->gw_ip); } /* Nexthop reachability check. */ - if ((afi == AFI_IP || afi == AFI_IP6) - && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) { + if (((afi == AFI_IP || afi == AFI_IP6) + && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) + || (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p))) { if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) @@ -3577,7 +3591,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, else connected = 0; - if (bgp_find_or_add_nexthop(bgp, bgp, afi, new, NULL, connected) + nh_afi = BGP_ATTR_NH_AFI(afi, new->attr); + + if (bgp_find_or_add_nexthop(bgp, bgp, nh_afi, new, NULL, + connected) || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)) bgp_path_info_set_flag(rn, new, BGP_PATH_VALID); else { @@ -3628,7 +3645,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, return -1; /* If this is an EVPN route, process for import. */ - if (safi == SAFI_EVPN) + if (safi == SAFI_EVPN && CHECK_FLAG(new->flags, BGP_PATH_VALID)) bgp_evpn_import_route(bgp, afi, safi, p, new); hook_call(bgp_process, bgp, afi, safi, rn, peer, false); @@ -7880,7 +7897,7 @@ void route_vty_out_overlay(struct vty *vty, struct prefix *p, /* dampening route */ static void damp_route_vty_out(struct vty *vty, struct prefix *p, - struct bgp_path_info *path, int display, + struct bgp_path_info *path, int display, afi_t afi, safi_t safi, bool use_json, json_object *json) { struct attr *attr; @@ -7911,13 +7928,13 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p, } if (use_json) - bgp_damp_reuse_time_vty(vty, path, timebuf, BGP_UPTIME_LEN, - use_json, json); + bgp_damp_reuse_time_vty(vty, path, timebuf, BGP_UPTIME_LEN, afi, + safi, use_json, json); else vty_out(vty, "%s ", bgp_damp_reuse_time_vty(vty, path, timebuf, - BGP_UPTIME_LEN, use_json, - json)); + BGP_UPTIME_LEN, afi, safi, + use_json, json)); /* Print attribute */ attr = path->attr; @@ -7944,7 +7961,7 @@ static void damp_route_vty_out(struct vty *vty, struct prefix *p, /* flap route */ static void flap_route_vty_out(struct vty *vty, struct prefix *p, - struct bgp_path_info *path, int display, + struct bgp_path_info *path, int display, afi_t afi, safi_t safi, bool use_json, json_object *json) { struct attr *attr; @@ -8003,12 +8020,13 @@ static void flap_route_vty_out(struct vty *vty, struct prefix *p, && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) { if (use_json) bgp_damp_reuse_time_vty(vty, path, timebuf, - BGP_UPTIME_LEN, use_json, json); + BGP_UPTIME_LEN, afi, safi, + use_json, json); else vty_out(vty, "%s ", bgp_damp_reuse_time_vty(vty, path, timebuf, - BGP_UPTIME_LEN, - use_json, json)); + BGP_UPTIME_LEN, afi, + safi, use_json, json)); } else { if (!use_json) vty_out(vty, "%*s ", 8, " "); @@ -8876,7 +8894,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, } if (path->extra && path->extra->damp_info) - bgp_damp_info_vty(vty, path, json_path); + bgp_damp_info_vty(vty, path, afi, safi, json_path); /* Remote Label */ if (path->extra && bgp_is_valid_label(&path->extra->label[0]) @@ -9289,11 +9307,11 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, } if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) - damp_route_vty_out(vty, &rn->p, pi, display, + damp_route_vty_out(vty, &rn->p, pi, display, AFI_IP, safi, use_json, json_paths); else if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_neighbor) - flap_route_vty_out(vty, &rn->p, pi, display, + flap_route_vty_out(vty, &rn->p, pi, display, AFI_IP, safi, use_json, json_paths); else route_vty_out(vty, &rn->p, pi, display, safi, @@ -10545,7 +10563,7 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp, } ret = bgp_show(vty, bgp, afi, safi, type, p, 0); - prefix_free(p); + prefix_free(&p); return ret; } @@ -11106,7 +11124,7 @@ DEFUN (show_bgp_l2vpn_evpn_route_prefix, argv_find(argv, argc, "X:X::X:X", &idx)) network = argv[idx]->arg; else if (argv_find(argv, argc, "A.B.C.D/M", &idx) || - argv_find(argv, argc, "A.B.C.D/M", &idx)) { + argv_find(argv, argc, "X:X::X:X/M", &idx)) { network = argv[idx]->arg; prefix_check = 1; } else { @@ -11294,7 +11312,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi, /* Filter prefix using route-map */ ret = bgp_input_modifier(peer, &rn->p, &attr, - afi, safi, rmap_name, NULL, 0); + afi, safi, rmap_name, NULL, 0, + NULL); if (type == bgp_show_adj_route_filtered && !route_filtered && ret != RMAP_DENY) { @@ -11923,6 +11942,32 @@ uint8_t bgp_distance_apply(struct prefix *p, struct bgp_path_info *pinfo, } } +/* If we enter `distance bgp (1-255) (1-255) (1-255)`, + * we should tell ZEBRA update the routes for a specific + * AFI/SAFI to reflect changes in RIB. + */ +static void bgp_announce_routes_distance_update(struct bgp *bgp, + afi_t update_afi, + safi_t update_safi) +{ + afi_t afi; + safi_t safi; + + FOREACH_AFI_SAFI (afi, safi) { + if (!bgp_fibupd_safi(safi)) + continue; + + if (afi != update_afi && safi != update_safi) + continue; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "%s: Announcing routes due to distance change afi/safi (%d/%d)", + __func__, afi, safi); + bgp_zebra_announce_table(bgp, afi, safi); + } +} + DEFUN (bgp_distance, bgp_distance_cmd, "distance bgp (1-255) (1-255) (1-255)", @@ -11936,15 +11981,23 @@ DEFUN (bgp_distance, int idx_number = 2; int idx_number_2 = 3; int idx_number_3 = 4; + int distance_ebgp = atoi(argv[idx_number]->arg); + int distance_ibgp = atoi(argv[idx_number_2]->arg); + int distance_local = atoi(argv[idx_number_3]->arg); afi_t afi; safi_t safi; afi = bgp_node_afi(vty); safi = bgp_node_safi(vty); - bgp->distance_ebgp[afi][safi] = atoi(argv[idx_number]->arg); - bgp->distance_ibgp[afi][safi] = atoi(argv[idx_number_2]->arg); - bgp->distance_local[afi][safi] = atoi(argv[idx_number_3]->arg); + if (bgp->distance_ebgp[afi][safi] != distance_ebgp + || bgp->distance_ibgp[afi][safi] != distance_ibgp + || bgp->distance_local[afi][safi] != distance_local) { + bgp->distance_ebgp[afi][safi] = distance_ebgp; + bgp->distance_ibgp[afi][safi] = distance_ibgp; + bgp->distance_local[afi][safi] = distance_local; + bgp_announce_routes_distance_update(bgp, afi, safi); + } return CMD_SUCCESS; } @@ -11965,9 +12018,14 @@ DEFUN (no_bgp_distance, afi = bgp_node_afi(vty); safi = bgp_node_safi(vty); - bgp->distance_ebgp[afi][safi] = 0; - bgp->distance_ibgp[afi][safi] = 0; - bgp->distance_local[afi][safi] = 0; + if (bgp->distance_ebgp[afi][safi] != 0 + || bgp->distance_ibgp[afi][safi] != 0 + || bgp->distance_local[afi][safi] != 0) { + bgp->distance_ebgp[afi][safi] = 0; + bgp->distance_ibgp[afi][safi] = 0; + bgp->distance_local[afi][safi] = 0; + bgp_announce_routes_distance_update(bgp, afi, safi); + } return CMD_SUCCESS; } @@ -12196,7 +12254,7 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, pi_temp = pi->next; bgp_damp_info_free( pi->extra->damp_info, - 1); + 1, afi, safi); pi = pi_temp; } else pi = pi->next; @@ -12216,7 +12274,7 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, pi_temp = pi->next; bgp_damp_info_free( pi->extra->damp_info, - 1); + 1, afi, safi); pi = pi_temp; } else pi = pi->next; @@ -12238,7 +12296,7 @@ DEFUN (clear_ip_bgp_dampening, BGP_STR "Clear route flap dampening information\n") { - bgp_damp_info_clean(); + bgp_damp_info_clean(AFI_IP, SAFI_UNICAST); return CMD_SUCCESS; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index d0cea547ec..4d73faa87c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -969,6 +969,63 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = { "evpn route-type", route_match_evpn_route_type, route_match_evpn_route_type_compile, route_match_evpn_route_type_free}; +/* `match rd' */ + +/* Match function should return 1 if match is success else return zero. */ +static enum route_map_cmd_result_t +route_match_rd(void *rule, const struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct prefix_rd *prd_rule = NULL; + struct prefix_rd *prd_route = NULL; + struct bgp_path_info *path = NULL; + + if (type == RMAP_BGP) { + if (prefix->family != AF_EVPN) + return RMAP_NOMATCH; + + prd_rule = (struct prefix_rd *)rule; + path = (struct bgp_path_info *)object; + + if (path->net == NULL || path->net->prn == NULL) + return RMAP_NOMATCH; + + prd_route = (struct prefix_rd *)&path->net->prn->p; + if (memcmp(prd_route->val, prd_rule->val, ECOMMUNITY_SIZE) == 0) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +/* Route map `rd' match statement. */ +static void *route_match_rd_compile(const char *arg) +{ + struct prefix_rd *prd; + int ret; + + prd = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct prefix_rd)); + + ret = str2prefix_rd(arg, prd); + if (!ret) { + XFREE(MTYPE_ROUTE_MAP_COMPILED, prd); + return NULL; + } + + return prd; +} + +/* Free route map's compiled `rd' value. */ +static void route_match_rd_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for rd matching. */ +struct route_map_rule_cmd route_match_evpn_rd_cmd = { + "evpn rd", route_match_rd, route_match_rd_compile, + route_match_rd_free}; + /* Route map commands for VRF route leak with source vrf matching */ static enum route_map_cmd_result_t route_match_vrl_source_vrf(void *rule, const struct prefix *prefix, @@ -1038,8 +1095,10 @@ route_match_local_pref(void *rule, const struct prefix *prefix, return RMAP_NOMATCH; } -/* Route map `match local-preference' match statement. - `arg' is local-pref value */ +/* + * Route map `match local-preference' match statement. + * `arg' is local-pref value + */ static void *route_match_local_pref_compile(const char *arg) { uint32_t *local_pref; @@ -3666,6 +3725,31 @@ DEFUN (no_match_evpn_default_route, RMAP_EVENT_MATCH_DELETED); } +DEFUN (match_evpn_rd, + match_evpn_rd_cmd, + "match evpn rd ASN:NN_OR_IP-ADDRESS:NN", + MATCH_STR + EVPN_HELP_STR + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n") +{ + return bgp_route_match_add(vty, "evpn rd", argv[3]->arg, + RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_evpn_rd, + no_match_evpn_rd_cmd, + "no match evpn rd ASN:NN_OR_IP-ADDRESS:NN", + NO_STR + MATCH_STR + EVPN_HELP_STR + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n") +{ + return bgp_route_match_delete(vty, "evpn rd", argv[4]->arg, + RMAP_EVENT_MATCH_DELETED); +} + DEFPY(match_vrl_source_vrf, match_vrl_source_vrf_cmd, "match source-vrf NAME$vrf_name", @@ -5216,6 +5300,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_mac_address_cmd); route_map_install_match(&route_match_evpn_vni_cmd); route_map_install_match(&route_match_evpn_route_type_cmd); + route_map_install_match(&route_match_evpn_rd_cmd); route_map_install_match(&route_match_evpn_default_route_cmd); route_map_install_match(&route_match_vrl_source_vrf_cmd); @@ -5256,6 +5341,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_evpn_vni_cmd); install_element(RMAP_NODE, &match_evpn_route_type_cmd); install_element(RMAP_NODE, &no_match_evpn_route_type_cmd); + install_element(RMAP_NODE, &match_evpn_rd_cmd); + install_element(RMAP_NODE, &no_match_evpn_rd_cmd); install_element(RMAP_NODE, &match_evpn_default_route_cmd); install_element(RMAP_NODE, &no_match_evpn_default_route_cmd); install_element(RMAP_NODE, &match_vrl_source_vrf_cmd); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 1267e35097..3b89e50ce4 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -406,7 +406,7 @@ static int bgpd_sync_callback(struct thread *thread) } } - prefix_free(prefix); + prefix_free(&prefix); return 0; } diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 4b6af935e0..5f3f5cde9a 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -917,7 +917,7 @@ static void update_subgroup_remove_peer_internal(struct update_subgroup *subgrp, if (BGP_DEBUG(update_groups, UPDATE_GROUPS)) zlog_debug("peer %s deleted from subgroup s%" - PRIu64 "peer cnt %d", + PRIu64 " peer cnt %d", paf->peer->host, subgrp->id, subgrp->peer_count); SUBGRP_INCR_STAT(subgrp, prune_events); } diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index e48eda7231..f922d066c3 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -106,6 +106,9 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, if (bgp_node_get_bgp_path_info(rm) == NULL) continue; + if (!attr) + continue; + if (header) { if (use_json) { json_object_int_add( diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 9e81831ac7..3116e7cad0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3146,14 +3146,16 @@ DEFUN (no_neighbor, * interface. */ if (peer->ifp) bgp_zebra_terminate_radv(peer->bgp, peer); + peer_notify_unconfig(peer); peer_delete(peer); return CMD_SUCCESS; } group = peer_group_lookup(bgp, argv[idx_peer]->arg); - if (group) + if (group) { + peer_group_notify_unconfig(group); peer_group_delete(group); - else { + } else { vty_out(vty, "%% Create the peer-group first\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -3167,9 +3169,12 @@ DEFUN (no_neighbor, } other = peer->doppelganger; + peer_notify_unconfig(peer); peer_delete(peer); - if (other && other->status != Deleted) + if (other && other->status != Deleted) { + peer_notify_unconfig(other); peer_delete(other); + } } } @@ -3201,6 +3206,7 @@ DEFUN (no_neighbor_interface_config, /* Request zebra to terminate IPv6 RAs on this interface. */ if (peer->ifp) bgp_zebra_terminate_radv(peer->bgp, peer); + peer_notify_unconfig(peer); peer_delete(peer); } else { vty_out(vty, "%% Create the bgp interface first\n"); @@ -3222,9 +3228,10 @@ DEFUN (no_neighbor_peer_group, struct peer_group *group; group = peer_group_lookup(bgp, argv[idx_word]->arg); - if (group) + if (group) { + peer_group_notify_unconfig(group); peer_group_delete(group); - else { + } else { vty_out(vty, "%% Create the peer-group first\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -3582,6 +3589,7 @@ DEFUN (no_neighbor_set_peer_group, return CMD_WARNING_CONFIG_FAILED; } + peer_notify_unconfig(peer); ret = peer_delete(peer); return bgp_vty_return(vty, ret); @@ -6381,6 +6389,44 @@ ALIAS_HIDDEN(no_neighbor_addpath_tx_bestpath_per_as, NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Use addpath to advertise the bestpath per each neighboring AS\n") +DEFPY( + neighbor_aspath_loop_detection, neighbor_aspath_loop_detection_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor sender-as-path-loop-detection", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Detect AS loops before sending to neighbor\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + peer->as_path_loop_detection = true; + + return CMD_SUCCESS; +} + +DEFPY( + no_neighbor_aspath_loop_detection, + no_neighbor_aspath_loop_detection_cmd, + "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor sender-as-path-loop-detection", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Detect AS loops before sending to neighbor\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + peer->as_path_loop_detection = false; + + return CMD_SUCCESS; +} + static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv, struct ecommunity **list) { @@ -13678,6 +13724,10 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); + /* "neighbor sender-as-path-loop-detection" commands. */ + install_element(BGP_NODE, &neighbor_aspath_loop_detection_cmd); + install_element(BGP_NODE, &no_neighbor_aspath_loop_detection_cmd); + /* "neighbor passive" commands. */ install_element(BGP_NODE, &neighbor_passive_cmd); install_element(BGP_NODE, &no_neighbor_passive_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 7923f076c1..d0a732b153 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -357,7 +357,7 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) bgp_connected_delete(bgp, ifc); } - connected_free(ifc); + connected_free(&ifc); return 0; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a2d4c0101e..d4e60b4093 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2562,6 +2562,30 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, return 0; } +int peer_notify_unconfig(struct peer *peer) +{ + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) + bgp_notify_send(peer, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_PEER_UNCONFIG); + return 0; +} + +int peer_group_notify_unconfig(struct peer_group *group) +{ + struct peer *peer, *other; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + other = peer->doppelganger; + if (other && other->status != Deleted) { + other->group = NULL; + peer_notify_unconfig(other); + } else + peer_notify_unconfig(peer); + } + return 0; +} + int peer_group_delete(struct peer_group *group) { struct bgp *bgp; @@ -2586,7 +2610,7 @@ int peer_group_delete(struct peer_group *group) for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (ALL_LIST_ELEMENTS(group->listen_range[afi], node, nnode, prefix)) { - prefix_free(prefix); + prefix_free(&prefix); } list_delete(&group->listen_range[afi]); } @@ -7166,6 +7190,11 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, /* strict-capability-match */ if (peergroup_flag_check(peer, PEER_FLAG_STRICT_CAP_MATCH)) vty_out(vty, " neighbor %s strict-capability-match\n", addr); + + /* Sender side AS path loop detection. */ + if (peer->as_path_loop_detection) + vty_out(vty, " neighbor %s sender-as-path-loop-detection\n", + addr); } /* BGP peer configuration display function. */ @@ -7261,6 +7290,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, vty_out(vty, "\n"); } + /* BGP flag dampening. */ + if (CHECK_FLAG(bgp->af_flags[afi][safi], + BGP_CONFIG_DAMPENING)) + bgp_config_write_damp(vty, afi, safi); + /* Route reflector client. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT)) { @@ -7734,11 +7768,6 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); - /* BGP flag dampening. */ - if (CHECK_FLAG(bgp->af_flags[AFI_IP][SAFI_UNICAST], - BGP_CONFIG_DAMPENING)) - bgp_config_write_damp(vty); - /* BGP timers configuration. */ if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE && bgp->default_holdtime != BGP_DEFAULT_HOLDTIME) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 9f6148488c..e27018407f 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1225,6 +1225,9 @@ struct peer { char *hostname; char *domainname; + /* Sender side AS path loop detection. */ + bool as_path_loop_detection; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(peer) @@ -1447,9 +1450,6 @@ struct bgp_nlri { #define BGP_VTY_PORT 2605 #define BGP_DEFAULT_CONFIG "bgpd.conf" -/* Check AS path loop when we send NLRI. */ -/* #define BGP_SEND_ASPATH_CHECK */ - /* BGP Dynamic Neighbors feature */ #define BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT 100 #define BGP_DYNAMIC_NEIGHBORS_LIMIT_MIN 1 @@ -1638,9 +1638,11 @@ extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *, int, afi_t, safi_t); extern int peer_group_remote_as(struct bgp *, const char *, as_t *, int); extern int peer_delete(struct peer *peer); +extern int peer_notify_unconfig(struct peer *peer); extern int peer_group_delete(struct peer_group *); extern int peer_group_remote_as_delete(struct peer_group *); extern int peer_group_listen_range_add(struct peer_group *, struct prefix *); +extern int peer_group_notify_unconfig(struct peer_group *group); extern int peer_activate(struct peer *, afi_t, safi_t); extern int peer_deactivate(struct peer *, afi_t, safi_t); diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index fe8e874440..660442b492 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -1512,7 +1512,7 @@ static int rfapiNhlAddNodeRoutes( } seen_nexthops = - skiplist_new(0, vnc_prefix_cmp, (void (*)(void *))prefix_free); + skiplist_new(0, vnc_prefix_cmp, prefix_free_lists); for (bpi = rn->info; bpi; bpi = bpi->next) { @@ -4359,7 +4359,7 @@ rfapiImportTableRefAdd(struct bgp *bgp, struct ecommunity *rt_import_list, it->rt_import_list = ecommunity_dup(rt_import_list); it->rfg = rfg; it->monitor_exterior_orphans = - skiplist_new(0, NULL, (void (*)(void *))prefix_free); + skiplist_new(0, NULL, prefix_free_lists); /* * fill import route tables from RIBs diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index df06105535..6e8969ad18 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -1807,8 +1807,7 @@ static void vnc_import_bgp_exterior_add_route_it( RFAPI_MONITOR_EXTERIOR(rn)->source = skiplist_new( 0, NULL, - (void (*)(void *)) - prefix_free); + prefix_free_lists); agg_lock_node(rn); /* for skiplist */ } agg_lock_node(rn); /* for skiplist entry */ @@ -2194,8 +2193,7 @@ void vnc_import_bgp_exterior_add_route_interior( ->source) { RFAPI_MONITOR_EXTERIOR(rn_interior) ->source = skiplist_new( - 0, NULL, - (void (*)(void *))prefix_free); + 0, NULL, prefix_free_lists); agg_lock_node(rn_interior); } skiplist_insert( @@ -2337,8 +2335,7 @@ void vnc_import_bgp_exterior_add_route_interior( if (!RFAPI_MONITOR_EXTERIOR(rn_interior)->source) { RFAPI_MONITOR_EXTERIOR(rn_interior)->source = skiplist_new( - 0, NULL, - (void (*)(void *))prefix_free); + 0, NULL, prefix_free_lists); agg_lock_node(rn_interior); /* sl */ } skiplist_insert( @@ -2527,8 +2524,7 @@ void vnc_import_bgp_exterior_del_route_interior( if (!RFAPI_MONITOR_EXTERIOR(par)->source) { RFAPI_MONITOR_EXTERIOR(par)->source = skiplist_new( - 0, NULL, - (void (*)(void *))prefix_free); + 0, NULL, prefix_free_lists); agg_lock_node(par); /* sl */ } skiplist_insert(RFAPI_MONITOR_EXTERIOR(par)->source, diff --git a/debian/copyright b/debian/copyright index d1f28a65a2..edd73020bd 100644 --- a/debian/copyright +++ b/debian/copyright @@ -12,6 +12,7 @@ Copyright: 1996-2003 by the original Zebra authors: 2016-2018 by the FRRouting Project Adam Fitzgerald 2017 Alex Couloumbis 2017 + Alexandre Cassen 2001-2017 Alexandre Chappuis 2011 Alexis Fasquel 2015 Ali Rezaee 2018 @@ -47,6 +48,7 @@ Copyright: 1996-2003 by the original Zebra authors: Christoffer Hansen 2018 Christoph Dwertmann 2018 Colin Petrie 2016 + Cumulus Networks 2013-2019 Daniel Kozlowski 2012 Daniel Ng 2008 Daniel Walton 2015-2018 @@ -153,6 +155,7 @@ Copyright: 1996-2003 by the original Zebra authors: Olivier Cochard-Labbé 2014 Olivier Dugeon 2014-2018 Ondrej Zajicek 2009 + Open Source Routing / NetDEF 2012-2017 Pascal Mathis 2018 Paul Jakma 2002-2016 Paul P Komkoff Jr 2008 @@ -266,7 +269,7 @@ Copyright: Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek -Files: babeld/babel_errors.* babeld/babel_memory.* +Files: babeld/babel_errors.* License: GPL-2+ Copyright: Copyright (C) 2017-2018 Donald Sharp, Cumulus Networks, Inc. diff --git a/doc/developer/next-hop-tracking.rst b/doc/developer/next-hop-tracking.rst index a9af5e749c..99e1d65c2b 100644 --- a/doc/developer/next-hop-tracking.rst +++ b/doc/developer/next-hop-tracking.rst @@ -111,8 +111,6 @@ provides the following APIs: +============================+==================================================+ | bgp_find_or_add_nexthop() | find or add a nexthop in BGP nexthop table | +----------------------------+--------------------------------------------------+ -| bgp_find_nexthop() | find a nexthop in BGP nexthop table | -+----------------------------+--------------------------------------------------+ | bgp_parse_nexthop_update() | parse a nexthop update message coming from zebra | +----------------------------+--------------------------------------------------+ diff --git a/doc/developer/testing.rst b/doc/developer/testing.rst index 6396faf9a6..5865a6becc 100644 --- a/doc/developer/testing.rst +++ b/doc/developer/testing.rst @@ -8,3 +8,4 @@ Testing :maxdepth: 2 topotests + topotests-jsontopo diff --git a/doc/developer/topotests-jsontopo.rst b/doc/developer/topotests-jsontopo.rst index 130f072b62..bbae80f11d 100644 --- a/doc/developer/topotests-jsontopo.rst +++ b/doc/developer/topotests-jsontopo.rst @@ -1,53 +1,50 @@ -.. role:: raw-html-m2r(raw) - :format: html +.. _topotests-json: -************************************* -FRRouting Topology Tests with Mininet -************************************* +Topotests with JSON +=================== Overview -======== +-------- On top of current topotests framework following enhancements are done: -#. Creating the topology and assigning IPs to router' interfaces dynamically.\ :raw-html-m2r:`<br>` - It is achieved by using json file, in which user specify the number of routers, - links to each router, interfaces for the routers and protocol configurations for - all routers. +* Creating the topology and assigning IPs to router' interfaces dynamically. + It is achieved by using json file, in which user specify the number of + routers, links to each router, interfaces for the routers and protocol + configurations for all routers. -#. Creating the configurations dynamically. It is achieved by using - /usr/lib/frr/frr-reload.py utility, which takes running configuration and the - newly created configuration for any particular router and creates a delta - file(diff file) and loads it to router. +* Creating the configurations dynamically. It is achieved by using + :file:`/usr/lib/frr/frr-reload.py` utility, which takes running configuration + and the newly created configuration for any particular router and creates a + delta file(diff file) and loads it to router. Logging of test case executions -=============================== +------------------------------- - -#. User can enable logging of testcases execution messages into log file by - adding "frrtest_log_dir = /tmp/topotests/" in pytest.ini file -#.Router's current configuration can be displyed on console or sent to logs by - adding "show_router_config = True" in pytest.ini file +* The user can enable logging of testcases execution messages into log file by + adding ``frrtest_log_dir = /tmp/topotests/`` in :file:`pytest.ini`. +* Router's current configuration can be displyed on console or sent to logs by + adding ``show_router_config = True`` in :file:`pytest.ini`. Log file name will be displayed when we start execution: .. code-block:: console - root@test:~/topotests/example-topojson-test/test_topo_json_single_link# python - test_topo_json_single_link.py Logs will be sent to logfile: + root@test:# python ./test_topo_json_single_link.py + + Logs will be sent to logfile: /tmp/topotests/test_topo_json_single_link_11:57:01.353797 Note: directory "/tmp/topotests/" is created by topotests by default, making use of same directory to save execution logs. - Guidelines -========== +---------- Writing New Tests ------------------ +^^^^^^^^^^^^^^^^^ This section will guide you in all recommended steps to produce a standard topology test. @@ -60,29 +57,30 @@ This is the recommended test writing routine: * Write the tests * Create a Pull Request + File Hierarchy --------------- +^^^^^^^^^^^^^^ Before starting to write any tests one must know the file hierarchy. The repository hierarchy looks like this: -.. code-block:: - - $ cd path/to/topotests - $ find ./* - ... - ./example-topojson-test # the basic example test topology-1 - ./example-topojson-test/test_example_topojson.json # input json file, having - topology, interfaces, bgp and other configuration - ./example-topojson-test/test_example_topojson.py # test script to write and - execute testcases - ... - ./lib # shared test/topology functions - ./lib/topojson.py # library to create topology and configurations dynamically - from json file - ./lib/common_config.py # library to create protocol's common configurations ex- - static_routes, prefix_lists, route_maps etc. - ./lib/bgp.py # library to create only bgp configurations +.. code-block:: console + + $ cd path/to/topotests + $ find ./* + ... + ./example-topojson-test # the basic example test topology-1 + ./example-topojson-test/test_example_topojson.json # input json file, having + topology, interfaces, bgp and other configuration + ./example-topojson-test/test_example_topojson.py # test script to write and + execute testcases + ... + ./lib # shared test/topology functions + ./lib/topojson.py # library to create topology and configurations dynamically + from json file + ./lib/common_config.py # library to create protocol's common configurations ex- + static_routes, prefix_lists, route_maps etc. + ./lib/bgp.py # library to create only bgp configurations Defining the Topology and initial configuration in JSON file ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +323,7 @@ BGP neighborship with Multiple phy-links, sample JSON file:: ... -JSON File Explained +JSON File Explained """"""""""""""""""" Mandatory keywords/options in JSON: @@ -466,7 +464,7 @@ Example: * ``__main__`` initialization code (to support running the script directly) .. code-block:: python - + if **name** == '\ **main**\ ': sys.exit(pytest.main(["-s"])) diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index c2e3724df2..6eef7532b3 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -163,6 +163,34 @@ releases have support for this feature request. Moreover, introducing features requests may result in breaking the stability of the branch. LTS branches are first done to bring long term support for stability. +Development Branches +-------------------- + +Occassionally the community will desire the ability to work together +on a feature that is considered useful to FRR. In this case the +parties may ask the Maintainers for the creation of a development +branch in the main FRR repository. Requirements for this to happen +are: + +- A one paragraph description of the feature being implemented to + allow for the facilitation of discussion about the feature. This + might include pointers to relevant RFC's or presentations that + explain what is planned. This is intended to set a somewhat + low bar for organization. +- A branch maintainer must be named. This person is responsible for + keeping the branch up to date, and general communication about the + project with the other FRR Maintainers. Additionally this person + must already be a FRR Maintainer. +- Commits to this branch must follow the normal PR and commit process + as outlined in other areas of this document. The goal of this is + to prevent the current state where large features are submitted + and are so large they are difficult to review. + +After a development branch has completed the work together, a final +review can be made and the branch merged into master. If a development +branch is becomes un-maintained or not being actively worked on after +three months then the Maintainers can decide to remove the branch. + Changelog --------- The changelog will be the base for the release notes. A changelog entry for diff --git a/doc/user/basic.rst b/doc/user/basic.rst index c7d722164a..f946c37a73 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -238,6 +238,17 @@ Basic Config Commands Set default motd string. +.. index:: banner motd file FILE +.. clicmd:: banner motd file FILE + + Set motd string from file. The file must be in directory specified + under ``--sysconfdir``. + +.. index:: banner motd line LINE +.. clicmd:: banner motd line LINE + + Set motd string from an input. + .. index:: no banner motd .. clicmd:: no banner motd diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index b916fcf413..4b3113cf3b 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -440,6 +440,9 @@ Route Flap Dampening The route-flap damping algorithm is compatible with :rfc:`2439`. The use of this command is not recommended nowadays. + At the moment, route-flap dampening is not working per VRF and is working only + for IPv4 unicast and multicast. + .. seealso:: https://www.ripe.net/publications/docs/ripe-378 @@ -836,11 +839,16 @@ Redistribution Redistribute OSPF route to BGP process. -.. index:: redistribute vpn -.. clicmd:: redistribute vpn +.. index:: redistribute vnc +.. clicmd:: redistribute vnc Redistribute VNC routes to BGP process. +.. index:: redistribute vnc-direct +.. clicmd:: redistribute vnc-direct + + Redistribute VNC direct (not via zebra) routes to BGP process. + .. index:: update-delay MAX-DELAY .. clicmd:: update-delay MAX-DELAY @@ -1137,6 +1145,14 @@ Peer Filtering on reflected routes. This option allows the modifications to be reflected as well. Once enabled, it affects all reflected routes. +.. index:: [no] neighbor PEER sender-as-path-loop-detection +.. clicmd:: [no] neighbor PEER sender-as-path-loop-detection + + Enable the detection of sender side AS path loops and filter the + bad routes before they are sent. + + This setting is disabled by default. + .. _bgp-peer-group: Peer Groups diff --git a/doc/user/overview.rst b/doc/user/overview.rst index 24d9ece93b..03d7299bf7 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -64,6 +64,21 @@ The ultimate goal of the FRR project is making a production-grade, high quality, featureful and free IP routing software suite. +How to get FRR +============== + +The official FRR website is located at |PACKAGE_URL| and contains further +information, as well as links to additional resources. + +Several distributions provide packages for FRR. Check your distribution's +repositories to find out if a suitable version is available. + +Up-to-date Debian packages are available at https://deb.frrouting.org/. + +For instructions on installing from source, refer to the +`developer documentation <http://docs.frrouting.org/projects/dev-guide/en/latest/>`_. + + System Architecture =================== @@ -242,13 +257,15 @@ The indicators have the following semantics: * :mark:`N` - daemon/feature not supported by operating system -Known Kernel Issues: -==================== +Known Kernel Issues +------------------- + +- Linux < 4.11 -- Linux - v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 route deletion when you - have ecmp routes installed into the kernel. This especially becomes apparent if the route is being - transformed from one ecmp path to another. + v6 Route Replacement - Linux kernels before 4.11 can cause issues with v6 + route deletion when you have ECMP routes installed into the kernel. This + especially becomes apparent if the route is being transformed from one ECMP + path to another. .. _supported-rfcs: @@ -348,15 +365,6 @@ FRR implements the following RFCs: - :rfc:`2741` :t:`Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.` -How to get FRR -============== - -The official FRR website is located at |PACKAGE_URL| and contains further -information, as well as links to additional resources. - -Several distributions provide packages for FRR. Check your distribution's -repositories to find out if a suitable version is available. - Mailing Lists ============= diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index 3e09ec41bb..324f309290 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -327,8 +327,7 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p) if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->u.prefix4)) return 0; - prefix_ipv4_free(rn->info); - rn->info = NULL; + prefix_ipv4_free((struct prefix_ipv4 **)&rn->info); route_unlock_node(rn); /* initial reference */ /* Find interfaces that not configured already. */ diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index ba8271d46e..6367ef58ab 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -485,7 +485,7 @@ int eigrp_read(struct thread *thread) struct eigrp_header *eigrph; struct interface *ifp; struct eigrp_neighbor *nbr; - + struct in_addr srcaddr; uint16_t opcode = 0; uint16_t length = 0; @@ -511,6 +511,7 @@ int eigrp_read(struct thread *thread) if (iph->ip_v == 4) length = (iph->ip_len) - 20U; + srcaddr = iph->ip_src; /* IP Header dump. */ if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV) @@ -526,7 +527,7 @@ int eigrp_read(struct thread *thread) and also platforms (such as Solaris 8) that claim to support ifindex retrieval but do not. */ - c = if_lookup_address((void *)&iph->ip_src, AF_INET, + c = if_lookup_address((void *)&srcaddr, AF_INET, eigrp->vrf_id); if (c == NULL) @@ -549,11 +550,11 @@ int eigrp_read(struct thread *thread) /* Self-originated packet should be discarded silently. */ if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src) - || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address.u.prefix4))) { + || (IPV4_ADDR_SAME(&srcaddr, &ei->address.u.prefix4))) { if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) zlog_debug( "eigrp_read[%s]: Dropping self-originated packet", - inet_ntoa(iph->ip_src)); + inet_ntoa(srcaddr)); return 0; } diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index 9cc612eaf1..56dbe3d85e 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -197,7 +197,7 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table, list_delete(&pe->entries); list_delete(&pe->rij); eigrp_zebra_route_delete(eigrp, pe->destination); - prefix_free(pe->destination); + prefix_free(&pe->destination); rn->info = NULL; route_unlock_node(rn); // Lookup above diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 9a0fdda0f9..3205f13922 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -189,7 +189,7 @@ static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS) if (prefix_cmp(&ei->address, c->address) == 0) eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA); - connected_free(c); + connected_free(&c); return 0; } 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..8343f7d85f 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) @@ -337,7 +338,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, if (ip) { listnode_delete(circuit->ip_addrs, ip); - prefix_ipv4_free(ip); + prefix_ipv4_free(&ip); if (circuit->area) lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); @@ -357,7 +358,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, zlog_warn("End of addresses"); } - prefix_ipv4_free(ipv4); + prefix_ipv4_free(&ipv4); } if (connected->address->family == AF_INET6) { ipv6 = prefix_ipv6_new(); @@ -373,7 +374,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, } if (ip6) { listnode_delete(circuit->ipv6_link, ip6); - prefix_ipv6_free(ip6); + prefix_ipv6_free(&ip6); found = 1; } } else { @@ -385,7 +386,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, } if (ip6) { listnode_delete(circuit->ipv6_non_link, ip6); - prefix_ipv6_free(ip6); + prefix_ipv6_free(&ip6); found = 1; } } @@ -416,7 +417,7 @@ void isis_circuit_del_addr(struct isis_circuit *circuit, lsp_regenerate_schedule(circuit->area, circuit->is_type, 0); - prefix_ipv6_free(ipv6); + prefix_ipv6_free(&ipv6); } return; } 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/isis_zebra.c b/isisd/isis_zebra.c index bdf6869f5c..b4c699ccbb 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -128,7 +128,7 @@ static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS) if (if_is_operative(ifp)) isis_circuit_del_addr(circuit_scan_by_ifp(ifp), c); - connected_free(c); + connected_free(&c); return 0; } 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/ldpd/labelmapping.c b/ldpd/labelmapping.c index 5e1b422a41..a656626356 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -723,6 +723,14 @@ tlv_decode_fec_elm(struct nbr *nbr, struct ldp_msg *msg, char *buf, /* Prefix Length */ map->fec.prefix.prefixlen = buf[off]; off += sizeof(uint8_t); + if ((map->fec.prefix.af == AF_IPV4 + && map->fec.prefix.prefixlen > IPV4_MAX_PREFIXLEN) + || (map->fec.prefix.af == AF_IPV6 + && map->fec.prefix.prefixlen > IPV6_MAX_PREFIXLEN)) { + session_shutdown(nbr, S_BAD_TLV_VAL, msg->id, + msg->type); + return (-1); + } if (len < off + PREFIX_SIZE(map->fec.prefix.prefixlen)) { session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type); diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 4df1fc0304..946b51e4ee 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -368,7 +368,7 @@ ldp_interface_address_delete(ZAPI_CALLBACK_ARGS) ifp = ifc->ifp; ifc2kaddr(ifp, ifc, &ka); - connected_free(ifc); + connected_free(&ifc); /* Filter invalid addresses. */ if (bad_addr(ka.af, &ka.addr)) @@ -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"; @@ -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/command.c b/lib/command.c index e52893f0ba..59668e95fc 100644 --- a/lib/command.c +++ b/lib/command.c @@ -198,9 +198,6 @@ static struct cmd_node enable_node = { static struct cmd_node config_node = {CONFIG_NODE, "%s(config)# ", 1}; -/* Default motd string. */ -static const char *default_motd = FRR_DEFAULT_MOTD; - static const struct facility_map { int facility; const char *name; @@ -592,6 +589,10 @@ static int config_write_host(struct vty *vty) if (host.motdfile) vty_out(vty, "banner motd file %s\n", host.motdfile); + else if (host.motd + && strncmp(host.motd, FRR_DEFAULT_MOTD, + strlen(host.motd))) + vty_out(vty, "banner motd line %s\n", host.motd); else if (!host.motd) vty_out(vty, "no banner motd\n"); } @@ -2668,6 +2669,13 @@ int cmd_banner_motd_file(const char *file) return success; } +void cmd_banner_motd_line(const char *line) +{ + if (host.motd) + XFREE(MTYPE_HOST, host.motd); + host.motd = XSTRDUP(MTYPE_HOST, line); +} + DEFUN (banner_motd_file, banner_motd_file_cmd, "banner motd file FILE", @@ -2688,6 +2696,26 @@ DEFUN (banner_motd_file, return cmd; } +DEFUN (banner_motd_line, + banner_motd_line_cmd, + "banner motd line LINE...", + "Set banner\n" + "Banner for motd\n" + "Banner from an input\n" + "Text\n") +{ + int idx = 0; + char *motd; + + argv_find(argv, argc, "LINE", &idx); + motd = argv_concat(argv, argc, idx); + + cmd_banner_motd_line(motd); + XFREE(MTYPE_TMP, motd); + + return CMD_SUCCESS; +} + DEFUN (banner_motd_default, banner_motd_default_cmd, "banner motd default", @@ -2695,7 +2723,7 @@ DEFUN (banner_motd_default, "Strings for motd\n" "Default string\n") { - host.motd = default_motd; + cmd_banner_motd_line(FRR_DEFAULT_MOTD); return CMD_SUCCESS; } @@ -2864,7 +2892,7 @@ void cmd_init(int terminal) host.config = NULL; host.noconfig = (terminal < 0); host.lines = -1; - host.motd = default_motd; + cmd_banner_motd_line(FRR_DEFAULT_MOTD); host.motdfile = NULL; /* Install top nodes. */ @@ -2944,6 +2972,7 @@ void cmd_init(int terminal) install_element(CONFIG_NODE, &no_service_password_encrypt_cmd); install_element(CONFIG_NODE, &banner_motd_default_cmd); install_element(CONFIG_NODE, &banner_motd_file_cmd); + install_element(CONFIG_NODE, &banner_motd_line_cmd); install_element(CONFIG_NODE, &no_banner_motd_cmd); install_element(CONFIG_NODE, &service_terminal_length_cmd); install_element(CONFIG_NODE, &no_service_terminal_length_cmd); @@ -2988,6 +3017,7 @@ void cmd_terminate(void) XFREE(MTYPE_HOST, host.logfile); XFREE(MTYPE_HOST, host.motdfile); XFREE(MTYPE_HOST, host.config); + XFREE(MTYPE_HOST, host.motd); list_delete(&varhandlers); qobj_finish(); diff --git a/lib/command.h b/lib/command.h index 2176b14615..68ac86f769 100644 --- a/lib/command.h +++ b/lib/command.h @@ -78,7 +78,7 @@ struct host { int encrypt; /* Banner configuration. */ - const char *motd; + char *motd; char *motdfile; }; @@ -499,6 +499,7 @@ extern void host_config_set(const char *); extern void print_version(const char *); extern int cmd_banner_motd_file(const char *); +extern void cmd_banner_motd_line(const char *line); /* struct host global, ick */ extern struct host host; diff --git a/lib/filter.c b/lib/filter.c index 8c210bd7ad..ed3ffe9c67 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -2147,7 +2147,7 @@ DEFUN (no_access_list_any, "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n") { - int idx_word = 1; + int idx_word = 2; int idx = 0; char *seq = NULL; char *permit_deny = NULL; @@ -2352,7 +2352,7 @@ DEFUN (no_ipv6_access_list_exact, { int idx = 0; int exact = 0; - int idx_word = 2; + int idx_word = 3; char *seq = NULL; char *permit_deny = NULL; char *prefix = NULL; @@ -2394,7 +2394,7 @@ DEFUN (no_ipv6_access_list_any, "Specify packets to forward\n" "Any prefixi to match\n") { - int idx_word = 2; + int idx_word = 3; int idx = 0; char *seq = NULL; char *permit_deny = NULL; @@ -140,6 +140,13 @@ static int if_cmp_index_func(const struct interface *ifp1, return ifp1->ifindex - ifp2->ifindex; } +static void ifp_connected_free(void *arg) +{ + struct connected *c = arg; + + connected_free(&c); +} + /* Create new interface structure. */ static struct interface *if_new(vrf_id_t vrf_id) { @@ -153,7 +160,7 @@ static struct interface *if_new(vrf_id_t vrf_id) ifp->vrf_id = vrf_id; ifp->connected = list_new(); - ifp->connected->del = (void (*)(void *))connected_free; + ifp->connected->del = ifp_connected_free; ifp->nbr_connected = list_new(); ifp->nbr_connected->del = (void (*)(void *))nbr_connected_free; @@ -178,7 +185,7 @@ void if_destroy_via_zapi(struct interface *ifp) if_set_index(ifp, IFINDEX_INTERNAL); if (!ifp->configured) - if_delete(ifp); + if_delete(&ifp); } void if_up_via_zapi(struct interface *ifp) @@ -276,27 +283,29 @@ void if_delete_retain(struct interface *ifp) } /* Delete and free interface structure. */ -void if_delete(struct interface *ifp) +void if_delete(struct interface **ifp) { + struct interface *ptr = *ifp; struct vrf *vrf; - vrf = vrf_lookup_by_id(ifp->vrf_id); + vrf = vrf_lookup_by_id(ptr->vrf_id); assert(vrf); - IFNAME_RB_REMOVE(vrf, ifp); - if (ifp->ifindex != IFINDEX_INTERNAL) - IFINDEX_RB_REMOVE(vrf, ifp); + IFNAME_RB_REMOVE(vrf, ptr); + if (ptr->ifindex != IFINDEX_INTERNAL) + IFINDEX_RB_REMOVE(vrf, ptr); - if_delete_retain(ifp); + if_delete_retain(ptr); - list_delete(&ifp->connected); - list_delete(&ifp->nbr_connected); + list_delete(&ptr->connected); + list_delete(&ptr->nbr_connected); - if_link_params_free(ifp); + if_link_params_free(ptr); - XFREE(MTYPE_TMP, ifp->desc); + XFREE(MTYPE_TMP, ptr->desc); - XFREE(MTYPE_IF, ifp); + XFREE(MTYPE_IF, ptr); + *ifp = NULL; } /* Used only internally to check within VRF only */ @@ -866,24 +875,27 @@ struct nbr_connected *nbr_connected_new(void) } /* Free connected structure. */ -void connected_free(struct connected *connected) +void connected_free(struct connected **connected) { - if (connected->address) - prefix_free(connected->address); + struct connected *ptr = *connected; - if (connected->destination) - prefix_free(connected->destination); + if (ptr->address) + prefix_free(&ptr->address); - XFREE(MTYPE_CONNECTED_LABEL, connected->label); + if (ptr->destination) + prefix_free(&ptr->destination); - XFREE(MTYPE_CONNECTED, connected); + XFREE(MTYPE_CONNECTED_LABEL, ptr->label); + + XFREE(MTYPE_CONNECTED, ptr); + *connected = NULL; } /* Free nbr connected structure. */ void nbr_connected_free(struct nbr_connected *connected) { if (connected->address) - prefix_free(connected->address); + prefix_free(&connected->address); XFREE(MTYPE_NBR_CONNECTED, connected); } @@ -959,6 +971,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) { @@ -1145,7 +1171,7 @@ void if_terminate(struct vrf *vrf) ifp->node->info = NULL; route_unlock_node(ifp->node); } - if_delete(ifp); + if_delete(&ifp); } } @@ -1527,7 +1553,7 @@ static int lib_interface_destroy(enum nb_event event, ifp = nb_running_unset_entry(dnode); ifp->configured = false; - if_delete(ifp); + if_delete(&ifp); break; } @@ -513,7 +513,7 @@ extern void if_delete_retain(struct interface *); /* Delete and free the interface structure: calls if_delete_retain and then deletes it from the interface list and frees the structure. */ -extern void if_delete(struct interface *); +extern void if_delete(struct interface **ifp); extern int if_is_up(const struct interface *ifp); extern int if_is_running(const struct interface *ifp); @@ -543,7 +543,7 @@ extern ifindex_t ifname2ifindex(const char *ifname, vrf_id_t vrf_id); /* Connected address functions. */ extern struct connected *connected_new(void); -extern void connected_free(struct connected *); +extern void connected_free(struct connected **connected); extern void connected_add(struct interface *, struct connected *); extern struct connected * connected_add_by_prefix(struct interface *, struct prefix *, struct prefix *); @@ -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/lib/prefix.c b/lib/prefix.c index 5071ca8201..e2bf3b949c 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -905,9 +905,9 @@ struct prefix_ipv4 *prefix_ipv4_new(void) } /* Free prefix_ipv4 structure. */ -void prefix_ipv4_free(struct prefix_ipv4 *p) +void prefix_ipv4_free(struct prefix_ipv4 **p) { - prefix_free((struct prefix *)p); + prefix_free((struct prefix **)p); } /* If given string is valid return 1 else return 0 */ @@ -1077,9 +1077,9 @@ struct prefix_ipv6 *prefix_ipv6_new(void) } /* Free prefix for IPv6. */ -void prefix_ipv6_free(struct prefix_ipv6 *p) +void prefix_ipv6_free(struct prefix_ipv6 **p) { - prefix_free((struct prefix *)p); + prefix_free((struct prefix **)p); } /* If given string is valid return 1 else return 0 */ @@ -1484,10 +1484,18 @@ struct prefix *prefix_new(void) return p; } +void prefix_free_lists(void *arg) +{ + struct prefix *p = arg; + + prefix_free(&p); +} + /* Free prefix structure. */ -void prefix_free(struct prefix *p) +void prefix_free(struct prefix **p) { - XFREE(MTYPE_PREFIX, p); + XFREE(MTYPE_PREFIX, *p); + *p = NULL; } /* Utility function to convert ipv4 prefixes to Classful prefixes */ diff --git a/lib/prefix.h b/lib/prefix.h index 784927616a..7a93c766a3 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -396,7 +396,11 @@ extern unsigned int prefix6_bit(const struct in6_addr *prefix, const uint16_t prefixlen); extern struct prefix *prefix_new(void); -extern void prefix_free(struct prefix *); +extern void prefix_free(struct prefix **p); +/* + * Function to handle prefix_free being used as a del function. + */ +extern void prefix_free_lists(void *arg); extern const char *prefix_family_str(const struct prefix *); extern int prefix_blen(const struct prefix *); extern int str2prefix(const char *, struct prefix *); @@ -435,7 +439,7 @@ extern void prefix2sockunion(const struct prefix *, union sockunion *); extern int str2prefix_eth(const char *, struct prefix_eth *); extern struct prefix_ipv4 *prefix_ipv4_new(void); -extern void prefix_ipv4_free(struct prefix_ipv4 *); +extern void prefix_ipv4_free(struct prefix_ipv4 **p); extern int str2prefix_ipv4(const char *, struct prefix_ipv4 *); extern void apply_mask_ipv4(struct prefix_ipv4 *); @@ -460,7 +464,7 @@ extern in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen); extern int netmask_str2prefix_str(const char *, const char *, char *); extern struct prefix_ipv6 *prefix_ipv6_new(void); -extern void prefix_ipv6_free(struct prefix_ipv6 *); +extern void prefix_ipv6_free(struct prefix_ipv6 **p); extern int str2prefix_ipv6(const char *, struct prefix_ipv6 *); extern void apply_mask_ipv6(struct prefix_ipv6 *); diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index e4f614c7c4..9f828a1c7d 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -364,7 +364,7 @@ int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS) nhrp_interface_update_address( ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0); - connected_free(ifc); + connected_free(&ifc); return 0; } 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/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index d8a6a39e1e..6832737ada 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -143,7 +143,7 @@ static int ospf6_zebra_if_address_update_delete(ZAPI_CALLBACK_ARGS) ospf6_interface_state_update(c->ifp); } - connected_free(c); + connected_free(&c); return 0; } diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index f06e45392e..1ace0977bc 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -246,13 +246,6 @@ void msg_print(struct msg *msg) return; } -#ifdef ORIGINAL_CODING - zlog_debug( - "msg=%p msgtype=%d msglen=%d msgseq=%d streamdata=%p streamsize=%lu\n", - msg, msg->hdr.msgtype, ntohs(msg->hdr.msglen), - ntohl(msg->hdr.msgseq), STREAM_DATA(msg->s), - STREAM_SIZE(msg->s)); -#else /* ORIGINAL_CODING */ /* API message common header part. */ zlog_debug("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%zd)", ospf_api_typename(msg->hdr.msgtype), msg->hdr.msgtype, @@ -260,16 +253,7 @@ void msg_print(struct msg *msg) (unsigned long)ntohl(msg->hdr.msgseq), STREAM_DATA(msg->s), STREAM_SIZE(msg->s)); -/* API message body part. */ -#ifdef ndef - /* Generic Hex/Ascii dump */ - DumpBuf(STREAM_DATA(msg->s), STREAM_SIZE(msg->s)); /* Sorry, deleted! */ -#else /* ndef */ -/* Message-type dependent dump function. */ -#endif /* ndef */ - return; -#endif /* ORIGINAL_CODING */ } void msg_free(struct msg *msg) diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h index c99923e7b8..0fc683a5db 100644 --- a/ospfd/ospf_api.h +++ b/ospfd/ospf_api.h @@ -140,16 +140,10 @@ struct msg_unregister_opaque_type { * Power2[0] is not used. */ -#ifdef ORIGINAL_CODING -static const uint16_t Power2[] = {0x0, 0x1, 0x2, 0x4, 0x8, 0x10, - 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, - 0x800, 0x1000, 0x2000, 0x4000, 0x8000}; -#else static const uint16_t Power2[] = { 0, (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10), (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15)}; -#endif /* ORIGINAL_CODING */ struct lsa_filter_type { uint16_t typemask; /* bitmask for selecting LSA types (1..16) */ diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index ea919017d3..a60af36564 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -238,20 +238,23 @@ struct ospf_lsa *ospf_external_info_find_lsa(struct ospf *ospf, /* Update ASBR status. */ void ospf_asbr_status_update(struct ospf *ospf, uint8_t status) { - zlog_info("ASBR[Status:%d]: Update", status); + zlog_info("ASBR[%s:Status:%d]: Update", + ospf_get_name(ospf), status); /* ASBR on. */ if (status) { /* Already ASBR. */ if (IS_OSPF_ASBR(ospf)) { - zlog_info("ASBR[Status:%d]: Already ASBR", status); + zlog_info("ASBR[%s:Status:%d]: Already ASBR", + ospf_get_name(ospf), status); return; } SET_FLAG(ospf->flags, OSPF_FLAG_ASBR); } else { /* Already non ASBR. */ if (!IS_OSPF_ASBR(ospf)) { - zlog_info("ASBR[Status:%d]: Already non ASBR", status); + zlog_info("ASBR[%s:Status:%d]: Already non ASBR", + ospf_get_name(ospf), status); return; } UNSET_FLAG(ospf->flags, OSPF_FLAG_ASBR); diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index a17975270a..b9e78f4cd3 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -202,8 +202,9 @@ static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) struct interface *ifp; struct ospf_interface *oi; struct ospf_if_params *params; - struct ospf_neighbor *nbr; + struct ospf_neighbor *nbr = NULL; struct route_node *node; + struct route_node *n_node; struct prefix p; int status; int old_status; @@ -231,7 +232,28 @@ static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) if ((oi = node->info) == NULL) continue; - nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &p.u.prefix4); + /* walk the neighbor list for point-to-point network */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { + for (n_node = route_top(oi->nbrs); n_node; + n_node = route_next(n_node)) { + nbr = n_node->info; + if (nbr) { + /* skip myself */ + if (nbr == oi->nbr_self) { + nbr = NULL; + continue; + } + + /* Found the matching neighbor */ + if (nbr->src.s_addr == + p.u.prefix4.s_addr) + break; + } + } + } else { + nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &p.u.prefix4); + } + if (!nbr || !nbr->bfd_info) continue; @@ -240,7 +262,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/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index f74d9733ee..dffcb930e4 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -501,23 +501,6 @@ static void ospf_packet_ls_ack_dump(struct stream *s, uint16_t length) stream_set_getp(s, sp); } -/* Expects header to be in host order */ -void ospf_ip_header_dump(struct ip *iph) -{ - /* IP Header dump. */ - zlog_debug("ip_v %d", iph->ip_v); - zlog_debug("ip_hl %d", iph->ip_hl); - zlog_debug("ip_tos %d", iph->ip_tos); - zlog_debug("ip_len %d", iph->ip_len); - zlog_debug("ip_id %u", (uint32_t)iph->ip_id); - zlog_debug("ip_off %u", (uint32_t)iph->ip_off); - zlog_debug("ip_ttl %d", iph->ip_ttl); - zlog_debug("ip_p %d", iph->ip_p); - zlog_debug("ip_sum 0x%x", (uint32_t)iph->ip_sum); - zlog_debug("ip_src %s", inet_ntoa(iph->ip_src)); - zlog_debug("ip_dst %s", inet_ntoa(iph->ip_dst)); -} - static void ospf_header_dump(struct ospf_header *ospfh) { char buf[9]; diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h index 397f666f69..6b2ebb125a 100644 --- a/ospfd/ospf_dump.h +++ b/ospfd/ospf_dump.h @@ -108,11 +108,6 @@ (conf_debug_ospf_packet[a] & OSPF_DEBUG_##b) #define IS_CONF_DEBUG_OSPF(a, b) (conf_debug_ospf_##a & OSPF_DEBUG_##b) -#ifdef ORIGINAL_CODING -#else /* ORIGINAL_CODING */ -struct stream; -#endif /* ORIGINAL_CODING */ - #define AREA_NAME(A) ospf_area_name_string ((A)) #define IF_NAME(I) ospf_if_name_string ((I)) @@ -138,7 +133,6 @@ extern const char *ospf_if_name_string(struct ospf_interface *); extern void ospf_nbr_state_message(struct ospf_neighbor *, char *, size_t); extern const char *ospf_timer_dump(struct thread *, char *, size_t); extern const char *ospf_timeval_dump(struct timeval *, char *, size_t); -extern void ospf_ip_header_dump(struct ip *); extern void ospf_packet_dump(struct stream *); extern void ospf_debug_init(void); diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 1d85a04984..381fb6820f 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -157,9 +157,9 @@ static void ospf_process_self_originated_lsa(struct ospf *ospf, if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[Type%d:%s]: Process self-originated LSA seq 0x%x", - new->data->type, inet_ntoa(new->data->id), - ntohl(new->data->ls_seqnum)); + "%s:LSA[Type%d:%s]: Process self-originated LSA seq 0x%x", + ospf_get_name(ospf), new->data->type, + inet_ntoa(new->data->id), ntohl(new->data->ls_seqnum)); /* If we're here, we installed a self-originated LSA that we received from a neighbor, i.e. it's more recent. We must see whether we want @@ -276,8 +276,8 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr, if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", - inet_ntoa(nbr->router_id), + "%s:LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", + ospf_get_name(ospf), inet_ntoa(nbr->router_id), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), (void *)current, dump_lsa_key(new)); @@ -295,15 +295,16 @@ int ospf_flood(struct ospf *ospf, struct ospf_neighbor *nbr, == OSPF_INITIAL_SEQUENCE_NUMBER)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[Flooding]: Got a self-originated LSA, " - "while local one is initial instance."); + "%s:LSA[Flooding]: Got a self-originated LSA, while local one is initial instance.", + ospf_get_name(ospf)); ; /* Accept this LSA for quick LSDB resynchronization. */ } else if (monotime_since(¤t->tv_recv, NULL) < ospf->min_ls_arrival * 1000LL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "LSA[Flooding]: LSA is received recently."); + "%s:LSA[Flooding]: LSA is received recently.", + ospf_get_name(ospf)); return -1; } } @@ -376,9 +377,8 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "ospf_flood_through_interface(): " - "considering int %s, INBR(%s), LSA[%s] AGE %u", - IF_NAME(oi), inbr ? inet_ntoa(inbr->router_id) : "NULL", + "%s:ospf_flood_through_interface(): considering int %s, INBR(%s), LSA[%s] AGE %u", + ospf_get_name(oi->ospf), IF_NAME(oi), inbr ? inet_ntoa(inbr->router_id) : "NULL", dump_lsa_key(lsa), ntohs(lsa->data->ls_age)); if (!ospf_if_is_enable(oi)) @@ -399,8 +399,9 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, onbr = rn->info; if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "ospf_flood_through_interface(): considering nbr %s (%s)", + "ospf_flood_through_interface(): considering nbr %s(%s) (%s)", inet_ntoa(onbr->router_id), + ospf_get_name(oi->ospf), lookup_msg(ospf_nsm_state_msg, onbr->state, NULL)); @@ -454,13 +455,8 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, } } -/* If the new LSA was received from this neighbor, - examine the next neighbor. */ -#ifdef ORIGINAL_CODING - if (inbr) - if (IPV4_ADDR_SAME(&inbr->router_id, &onbr->router_id)) - continue; -#else /* ORIGINAL_CODING */ + /* If the new LSA was received from this neighbor, + examine the next neighbor. */ if (inbr) { /* * Triggered by LSUpd message parser "ospf_ls_upd ()". @@ -486,7 +482,6 @@ static int ospf_flood_through_interface(struct ospf_interface *oi, continue; } } -#endif /* ORIGINAL_CODING */ /* Add the new LSA to the Link state retransmission list for the adjacency. The LSA will be retransmitted @@ -691,43 +686,14 @@ int ospf_flood_through(struct ospf *ospf, struct ospf_neighbor *inbr, { int lsa_ack_flag = 0; -/* Type-7 LSA's for NSSA are flooded throughout the AS here, and - upon return are updated in the LSDB for Type-7's. Later, - re-fresh will re-send them (and also, if ABR, packet code will - translate to Type-5's) + /* Type-7 LSA's for NSSA are flooded throughout the AS here, and + upon return are updated in the LSDB for Type-7's. Later, + re-fresh will re-send them (and also, if ABR, packet code will + translate to Type-5's) - As usual, Type-5 LSA's (if not DISCARDED because we are STUB or - NSSA) are flooded throughout the AS, and are updated in the - global table. */ -#ifdef ORIGINAL_CODING - switch (lsa->data->type) { - case OSPF_ROUTER_LSA: - case OSPF_NETWORK_LSA: - case OSPF_SUMMARY_LSA: - case OSPF_ASBR_SUMMARY_LSA: - case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */ - case OSPF_OPAQUE_AREA_LSA: - lsa_ack_flag = - ospf_flood_through_area(inbr->oi->area, inbr, lsa); - break; - case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ - case OSPF_OPAQUE_AS_LSA: - lsa_ack_flag = ospf_flood_through_as(ospf, inbr, lsa); - break; - /* Type-7 Only received within NSSA, then flooded */ - case OSPF_AS_NSSA_LSA: - /* Any P-bit was installed with the Type-7. */ - lsa_ack_flag = - ospf_flood_through_area(inbr->oi->area, inbr, lsa); - - if (IS_DEBUG_OSPF_NSSA) - zlog_debug( - "ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); - break; - default: - break; - } -#else /* ORIGINAL_CODING */ + As usual, Type-5 LSA's (if not DISCARDED because we are STUB or + NSSA) are flooded throughout the AS, and are updated in the + global table. */ /* * At the common sub-sub-function "ospf_flood_through_interface()", * a parameter "inbr" will be used to distinguish the called context @@ -757,7 +723,6 @@ int ospf_flood_through(struct ospf *ospf, struct ospf_neighbor *inbr, lsa_ack_flag = ospf_flood_through_area(lsa->area, inbr, lsa); break; } -#endif /* ORIGINAL_CODING */ return (lsa_ack_flag); } @@ -773,9 +738,10 @@ void ospf_ls_request_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) * the common function "ospf_lsdb_add()" -- endo. */ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RqstL(%lu)++, NBR(%s), LSA[%s]", + zlog_debug("RqstL(%lu)++, NBR(%s(%s)), LSA[%s]", ospf_ls_request_count(nbr), - inet_ntoa(nbr->router_id), dump_lsa_key(lsa)); + inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); ospf_lsdb_add(&nbr->ls_req, lsa); } @@ -799,9 +765,10 @@ void ospf_ls_request_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) } if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RqstL(%lu)--, NBR(%s), LSA[%s]", + zlog_debug("RqstL(%lu)--, NBR(%s(%s)), LSA[%s]", ospf_ls_request_count(nbr), - inet_ntoa(nbr->router_id), dump_lsa_key(lsa)); + inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); ospf_lsdb_delete(&nbr->ls_req, lsa); } @@ -859,6 +826,12 @@ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) if (ospf_lsa_more_recent(old, lsa) < 0) { if (old) { old->retransmit_counter--; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu)--, NBR(%s(%s)), LSA[%s]", + ospf_ls_retransmit_count(nbr), + inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), + dump_lsa_key(old)); ospf_lsdb_delete(&nbr->ls_rxmt, old); } lsa->retransmit_counter++; @@ -871,9 +844,10 @@ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) * the common function "ospf_lsdb_add()" -- endo. */ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)++, NBR(%s), LSA[%s]", + zlog_debug("RXmtL(%lu)++, NBR(%s(%s)), LSA[%s]", ospf_ls_retransmit_count(nbr), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); ospf_lsdb_add(&nbr->ls_rxmt, lsa); } @@ -885,9 +859,10 @@ void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) if (ospf_ls_retransmit_lookup(nbr, lsa)) { lsa->retransmit_counter--; if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RXmtL(%lu)--, NBR(%s), LSA[%s]", + zlog_debug("RXmtL(%lu)--, NBR(%s(%s)), LSA[%s]", ospf_ls_retransmit_count(nbr), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); ospf_lsdb_delete(&nbr->ls_rxmt, lsa); } diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 1f5e0da944..7ddffbcdbd 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -273,7 +273,7 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u created", __PRETTY_FUNCTION__, ifp->name, - ospf_vrf_id_to_name(ospf->vrf_id), ospf->vrf_id); + ospf_get_name(ospf), ospf->vrf_id); return oi; } @@ -832,7 +832,7 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf, struct prefix_ipv4 *p; if (IS_DEBUG_OSPF_EVENT) - zlog_debug("ospf_vl_new(): Start"); + zlog_debug("ospf_vl_new()(%s): Start", ospf_get_name(ospf)); if (vlink_count == OSPF_VL_MAX_COUNT) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( @@ -902,11 +902,10 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf, static void ospf_vl_if_delete(struct ospf_vl_data *vl_data) { - struct interface *ifp = vl_data->vl_oi->ifp; vl_data->vl_oi->address->u.prefix4.s_addr = 0; vl_data->vl_oi->address->prefixlen = 0; ospf_if_free(vl_data->vl_oi); - if_delete(ifp); + if_delete(&vl_data->vl_oi->ifp); vlink_count--; } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 5ab0927e71..3e3f288023 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -3202,45 +3202,6 @@ int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2) return 0; } -#ifdef ORIGINAL_CODING -void ospf_lsa_flush_self_originated(struct ospf_neighbor *nbr, - struct ospf_lsa *self, struct ospf_lsa *new) -{ - uint32_t seqnum; - - /* Adjust LS Sequence Number. */ - seqnum = ntohl(new->data->ls_seqnum) + 1; - self->data->ls_seqnum = htonl(seqnum); - - /* Recalculate LSA checksum. */ - ospf_lsa_checksum(self->data); - - /* Reflooding LSA. */ - /* RFC2328 Section 13.3 - On non-broadcast networks, separate Link State Update - packets must be sent, as unicasts, to each adjacent neighbor - (i.e., those in state Exchange or greater). The destination - IP addresses for these packets are the neighbors' IP - addresses. */ - if (nbr->oi->type == OSPF_IFTYPE_NBMA) { - struct route_node *rn; - struct ospf_neighbor *onbr; - - for (rn = route_top(nbr->oi->nbrs); rn; rn = route_next(rn)) - if ((onbr = rn->info) != NULL) - if (onbr != nbr->oi->nbr_self - && onbr->status >= NSM_Exchange) - ospf_ls_upd_send_lsa( - onbr, self, - OSPF_SEND_PACKET_DIRECT); - } else - ospf_ls_upd_send_lsa(nbr, self, OSPF_SEND_PACKET_INDIRECT); - - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug("LSA[Type%d:%s]: Flush self-originated LSA", - self->data->type, inet_ntoa(self->data->id)); -} -#else /* ORIGINAL_CODING */ int ospf_lsa_flush_schedule(struct ospf *ospf, struct ospf_lsa *lsa) { if (lsa == NULL || !IS_LSA_SELF(lsa)) @@ -3345,7 +3306,6 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf) return; } -#endif /* ORIGINAL_CODING */ /* If there is self-originated LSA, then return 1, otherwise return 0. */ /* An interface-independent version of ospf_lsa_is_self_originated */ diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index a58bd93b6e..a9247dd0ec 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -402,12 +402,14 @@ void ospf_renegotiate_optional_capabilities(struct ospf *top) struct ospf_neighbor *ospf_nbr_lookup(struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh) { + struct in_addr srcaddr = iph->ip_src; + if (oi->type == OSPF_IFTYPE_VIRTUALLINK || oi->type == OSPF_IFTYPE_POINTOPOINT) return (ospf_nbr_lookup_by_routerid(oi->nbrs, &ospfh->router_id)); else - return (ospf_nbr_lookup_by_addr(oi->nbrs, &iph->ip_src)); + return (ospf_nbr_lookup_by_addr(oi->nbrs, &srcaddr)); } static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi, diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index ee27ec0942..110738802c 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -65,8 +65,9 @@ static int ospf_inactivity_timer(struct thread *thread) nbr->t_inactivity = NULL; if (IS_DEBUG_OSPF(nsm, NSM_TIMERS)) - zlog_debug("NSM[%s:%s]: Timer (Inactivity timer expire)", - IF_NAME(nbr->oi), inet_ntoa(nbr->router_id)); + zlog_debug("NSM[%s:%s:%s]: Timer (Inactivity timer expire)", + IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf)); OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); @@ -81,8 +82,9 @@ static int ospf_db_desc_timer(struct thread *thread) nbr->t_db_desc = NULL; if (IS_DEBUG_OSPF(nsm, NSM_TIMERS)) - zlog_debug("NSM[%s:%s]: Timer (DD Retransmit timer expire)", - IF_NAME(nbr->oi), inet_ntoa(nbr->src)); + zlog_debug("NSM[%s:%s:%s]: Timer (DD Retransmit timer expire)", + IF_NAME(nbr->oi), inet_ntoa(nbr->src), + ospf_get_name(nbr->oi->ospf)); /* resent last send DD packet. */ assert(nbr->last_send); @@ -387,9 +389,10 @@ static int nsm_kill_nbr(struct ospf_neighbor *nbr) if (IS_DEBUG_OSPF(nsm, NSM_EVENTS)) zlog_debug( - "NSM[%s:%s]: Down (PollIntervalTimer scheduled)", + "NSM[%s:%s:%s]: Down (PollIntervalTimer scheduled)", IF_NAME(nbr->oi), - inet_ntoa(nbr->address.u.prefix4)); + inet_ntoa(nbr->address.u.prefix4), + ospf_get_name(nbr->oi->ospf)); } return 0; @@ -585,8 +588,9 @@ static void nsm_notice_state_change(struct ospf_neighbor *nbr, int next_state, { /* Logging change of status. */ if (IS_DEBUG_OSPF(nsm, NSM_STATUS)) - zlog_debug("NSM[%s:%s]: State change %s -> %s (%s)", + zlog_debug("NSM[%s:%s:%s]: State change %s -> %s (%s)", IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), lookup_msg(ospf_nsm_state_msg, next_state, NULL), ospf_nsm_event_str[event]); @@ -595,8 +599,9 @@ static void nsm_notice_state_change(struct ospf_neighbor *nbr, int next_state, if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) || (next_state == NSM_Full) || (next_state < nbr->state))) - zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)", - inet_ntoa(nbr->router_id), IF_NAME(nbr->oi), + zlog_notice("AdjChg: Nbr %s(%s) on %s: %s -> %s (%s)", + inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), IF_NAME(nbr->oi), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), lookup_msg(ospf_nsm_state_msg, next_state, NULL), ospf_nsm_event_str[event]); @@ -677,9 +682,10 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) zlog_info( - "%s:(%s, %s -> %s): " + "%s:[%s:%s], %s -> %s): " "scheduling new router-LSA origination", __PRETTY_FUNCTION__, inet_ntoa(nbr->router_id), + ospf_get_name(oi->ospf), lookup_msg(ospf_nsm_state_msg, old_state, NULL), lookup_msg(ospf_nsm_state_msg, state, NULL)); @@ -723,6 +729,13 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) nbr->dd_flags = OSPF_DD_FLAG_I | OSPF_DD_FLAG_M | OSPF_DD_FLAG_MS; + if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) + zlog_info( + "%s: Intializing [DD]: %s with seqnum:%x , flags:%x", + (oi->ospf->name) ? oi->ospf->name + : VRF_DEFAULT_NAME, + inet_ntoa(nbr->router_id), nbr->dd_seqnum, + nbr->dd_flags); ospf_db_desc_send(nbr); } @@ -746,8 +759,9 @@ int ospf_nsm_event(struct thread *thread) event = THREAD_VAL(thread); if (IS_DEBUG_OSPF(nsm, NSM_EVENTS)) - zlog_debug("NSM[%s:%s]: %s (%s)", IF_NAME(nbr->oi), + zlog_debug("NSM[%s:%s:%s]: %s (%s)", IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), ospf_nsm_event_str[event]); @@ -770,9 +784,10 @@ int ospf_nsm_event(struct thread *thread) */ flog_err( EC_OSPF_FSM_INVALID_STATE, - "NSM[%s:%s]: %s (%s): " + "NSM[%s:%s:%s]: %s (%s): " "Warning: action tried to change next_state to %s", IF_NAME(nbr->oi), inet_ntoa(nbr->router_id), + ospf_get_name(nbr->oi->ospf), lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), ospf_nsm_event_str[event], diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 147773ce23..a989b8468c 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -430,9 +430,9 @@ void ospf_delete_opaque_functab(uint8_t lsa_type, uint8_t opaque_type) /* Cleanup internal control information, if it * still remains. */ if (functab->oipt != NULL) { + free_opaque_info_owner(functab->oipt); free_opaque_info_per_type( functab->oipt); - free_opaque_info_owner(functab->oipt); } /* Dequeue listnode entry from the list. */ @@ -554,8 +554,8 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab, case OSPF_OPAQUE_AS_LSA: top = ospf_lookup_by_vrf_id(new->vrf_id); if (new->area != NULL && (top = new->area->ospf) == NULL) { - free_opaque_info_per_type((void *)oipt); free_opaque_info_owner(oipt); + free_opaque_info_per_type(oipt); oipt = NULL; goto out; /* This case may not exist. */ } @@ -567,8 +567,8 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab, EC_OSPF_LSA_UNEXPECTED, "register_opaque_info_per_type: Unexpected LSA-type(%u)", new->data->type); - free_opaque_info_per_type((void *)oipt); free_opaque_info_owner(oipt); + free_opaque_info_per_type(oipt); oipt = NULL; goto out; /* This case may not exist. */ } diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index a508ae657f..8634589b11 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -614,13 +614,6 @@ static void ospf_write_frags(int fd, struct ospf_packet *op, struct ip *iph, "ospf_write_frags: sent id %d, off %d, len %d to %s\n", iph->ip_id, iph->ip_off, iph->ip_len, inet_ntoa(iph->ip_dst)); - if (IS_DEBUG_OSPF_PACKET(type - 1, DETAIL)) { - zlog_debug( - "-----------------IP Header Dump----------------------"); - ospf_ip_header_dump(iph); - zlog_debug( - "-----------------------------------------------------"); - } } iph->ip_off += offset; @@ -824,7 +817,6 @@ static int ospf_write(struct thread *thread) if (IS_DEBUG_OSPF_PACKET(type - 1, DETAIL)) { zlog_debug( "-----------------------------------------------------"); - ospf_ip_header_dump(&iph); stream_set_getp(op->s, 0); ospf_packet_dump(op->s); } @@ -1357,6 +1349,14 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived); + if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) + zlog_info( + "%s:Packet[DD]: Neighbor %s state is %s, seq_num:0x%x, local:0x%x", + (oi->ospf->name) ? oi->ospf->name : VRF_DEFAULT_NAME, + inet_ntoa(nbr->router_id), + lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), + ntohl(dd->dd_seqnum), nbr->dd_seqnum); + /* Process DD packet by neighbor status. */ switch (nbr->state) { case NSM_Down: @@ -1497,10 +1497,6 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, /* Check DD Options. */ if (dd->options != nbr->options) { -#ifdef ORIGINAL_CODING - /* Save the new options for debugging */ - nbr->options = dd->options; -#endif /* ORIGINAL_CODING */ flog_warn(EC_OSPF_PACKET, "Packet[DD]: Neighbor %s options mismatch.", inet_ntoa(nbr->router_id)); @@ -2314,10 +2310,12 @@ static struct stream *ospf_recv_packet(struct ospf *ospf, int fd, msgh.msg_control = (caddr_t)buff; msgh.msg_controllen = sizeof(buff); - ret = stream_recvmsg(ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE + 1); + ret = stream_recvmsg(ibuf, fd, &msgh, MSG_DONTWAIT, + OSPF_MAX_PACKET_SIZE + 1); if (ret < 0) { - flog_warn(EC_OSPF_PACKET, "stream_recvmsg failed: %s", - safe_strerror(errno)); + if (errno != EAGAIN && errno != EWOULDBLOCK) + flog_warn(EC_OSPF_PACKET, "stream_recvmsg failed: %s", + safe_strerror(errno)); return NULL; } if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */ @@ -2377,6 +2375,10 @@ static struct stream *ospf_recv_packet(struct ospf *ospf, int fd, return NULL; } + if (IS_DEBUG_OSPF_PACKET(0, RECV)) + zlog_debug("%s: fd %d(%s) on interface %d(%s)", + __PRETTY_FUNCTION__, fd, ospf_get_name(ospf), + ifindex, *ifp ? (*ifp)->name : "Unknown"); return ibuf; } @@ -2935,56 +2937,60 @@ static int ospf_verify_header(struct stream *ibuf, struct ospf_interface *oi, return 0; } -/* Starting point of packet process function. */ -int ospf_read(struct thread *thread) +enum ospf_read_return_enum { + OSPF_READ_ERROR, + OSPF_READ_CONTINUE, +}; + +static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf) { int ret; struct stream *ibuf; - struct ospf *ospf; struct ospf_interface *oi; struct ip *iph; struct ospf_header *ospfh; uint16_t length; - struct interface *ifp = NULL; struct connected *c; - - /* first of all get interface pointer. */ - ospf = THREAD_ARG(thread); - - /* prepare for next packet. */ - ospf->t_read = NULL; - thread_add_read(master, ospf_read, ospf, ospf->fd, &ospf->t_read); + struct interface *ifp = NULL; stream_reset(ospf->ibuf); ibuf = ospf_recv_packet(ospf, ospf->fd, &ifp, ospf->ibuf); if (ibuf == NULL) - return -1; - /* This raw packet is known to be at least as big as its IP header. */ + return OSPF_READ_ERROR; - /* Note that there should not be alignment problems with this assignment - because this is at the beginning of the stream data buffer. */ + /* + * This raw packet is known to be at least as big as its + * IP header. Note that there should not be alignment problems with + * this assignment because this is at the beginning of the + * stream data buffer. + */ iph = (struct ip *)STREAM_DATA(ibuf); - /* Note that sockopt_iphdrincl_swab_systoh was called in - * ospf_recv_packet. */ - + /* + * Note that sockopt_iphdrincl_swab_systoh was called in + * ospf_recv_packet. + */ if (ifp == NULL) { - /* Handle cases where the platform does not support retrieving - the ifindex, - and also platforms (such as Solaris 8) that claim to support - ifindex - retrieval but do not. */ + /* + * Handle cases where the platform does not support + * retrieving the ifindex, and also platforms (such as + * Solaris 8) that claim to support ifindex retrieval but do + * not. + */ c = if_lookup_address((void *)&iph->ip_src, AF_INET, ospf->vrf_id); if (c) ifp = c->ifp; - if (ifp == NULL) - return 0; + if (ifp == NULL) { + if (IS_DEBUG_OSPF_PACKET(0, RECV)) + zlog_debug( + "%s: Unable to determine incoming interface from: %s(%s)", + __PRETTY_FUNCTION__, + inet_ntoa(iph->ip_src), + ospf_get_name(ospf)); + return OSPF_READ_CONTINUE; + } } - /* IP Header dump. */ - if (IS_DEBUG_OSPF_PACKET(0, RECV)) - ospf_ip_header_dump(iph); - /* Self-originated packet should be discarded silently. */ if (ospf_if_lookup_by_local_addr(ospf, NULL, iph->ip_src)) { if (IS_DEBUG_OSPF_PACKET(0, RECV)) { @@ -2992,30 +2998,32 @@ int ospf_read(struct thread *thread) "ospf_read[%s]: Dropping self-originated packet", inet_ntoa(iph->ip_src)); } - return 0; + return OSPF_READ_CONTINUE; } - /* Advance from IP header to OSPF header (iph->ip_hl has been verified - by ospf_recv_packet() to be correct). */ + /* + * Advance from IP header to OSPF header (iph->ip_hl has + * been verified by ospf_recv_packet() to be correct). + */ stream_forward_getp(ibuf, iph->ip_hl * 4); ospfh = (struct ospf_header *)stream_pnt(ibuf); if (MSG_OK - != ospf_packet_examin( - ospfh, stream_get_endp(ibuf) - stream_get_getp(ibuf))) - return -1; + != ospf_packet_examin(ospfh, stream_get_endp(ibuf) + - stream_get_getp(ibuf))) + return OSPF_READ_CONTINUE; /* Now it is safe to access all fields of OSPF packet header. */ /* associate packet with ospf interface */ oi = ospf_if_lookup_recv_if(ospf, iph->ip_src, ifp); - /* ospf_verify_header() relies on a valid "oi" and thus can be called - only - after the passive/backbone/other checks below are passed. These - checks - in turn access the fields of unverified "ospfh" structure for their - own - purposes and must remain very accurate in doing this. */ + /* + * ospf_verify_header() relies on a valid "oi" and thus can be called + * only after the passive/backbone/other checks below are passed. + * These checks in turn access the fields of unverified "ospfh" + * structure for their own purposes and must remain very accurate + * in doing this. + */ /* If incoming interface is passive one, ignore it. */ if (oi && OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_PASSIVE) { @@ -3023,8 +3031,7 @@ int ospf_read(struct thread *thread) if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "ignoring packet from router %s sent to %s, " - "received on a passive interface, %s", + "ignoring packet from router %s sent to %s, received on a passive interface, %s", inet_ntop(AF_INET, &ospfh->router_id, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], @@ -3040,7 +3047,7 @@ int ospf_read(struct thread *thread) OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); ospf_if_set_multicast(oi); } - return 0; + return OSPF_READ_CONTINUE; } @@ -3048,34 +3055,35 @@ int ospf_read(struct thread *thread) * or header area is backbone but ospf_interface is not * check for VLINK interface */ - if ((oi == NULL) || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id) - && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))) { + if ((oi == NULL) + || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id) + && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))) { if ((oi = ospf_associate_packet_vl(ospf, ifp, iph, ospfh)) == NULL) { if (!ospf->instance && IS_DEBUG_OSPF_EVENT) zlog_debug( - "Packet from [%s] received on link %s" - " but no ospf_interface", + "Packet from [%s] received on link %s but no ospf_interface", inet_ntoa(iph->ip_src), ifp->name); - return 0; + return OSPF_READ_CONTINUE; } } - /* else it must be a local ospf interface, check it was received on - * correct link + /* + * else it must be a local ospf interface, check it was + * received on correct link */ else if (oi->ifp != ifp) { if (IS_DEBUG_OSPF_EVENT) flog_warn(EC_OSPF_PACKET, "Packet from [%s] received on wrong link %s", inet_ntoa(iph->ip_src), ifp->name); - return 0; + return OSPF_READ_CONTINUE; } else if (oi->state == ISM_Down) { char buf[2][INET_ADDRSTRLEN]; + flog_warn( EC_OSPF_PACKET, - "Ignoring packet from %s to %s received on interface that is " - "down [%s]; interface flags are %s", + "Ignoring packet from %s to %s received on interface that is down [%s]; interface flags are %s", inet_ntop(AF_INET, &iph->ip_src, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], @@ -3088,13 +3096,15 @@ int ospf_read(struct thread *thread) OI_MEMBER_JOINED(oi, MEMBER_DROUTERS); if (oi->multicast_memberships) ospf_if_set_multicast(oi); - return 0; + return OSPF_READ_CONTINUE; } /* - * If the received packet is destined for AllDRouters, the packet - * should be accepted only if the received ospf interface state is - * either DR or Backup -- endo. + * If the received packet is destined for AllDRouters, the + * packet should be accepted only if the received ospf + * interface state is either DR or Backup -- endo. + * + * I wonder who endo is? */ if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS) && (oi->state != ISM_DR && oi->state != ISM_Backup)) { @@ -3106,7 +3116,7 @@ int ospf_read(struct thread *thread) /* Try to fix multicast membership. */ SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS); ospf_if_set_multicast(oi); - return 0; + return OSPF_READ_CONTINUE; } /* Verify more OSPF header fields. */ @@ -3117,7 +3127,7 @@ int ospf_read(struct thread *thread) "ospf_read[%s]: Header check failed, " "dropping.", inet_ntoa(iph->ip_src)); - return ret; + return OSPF_READ_CONTINUE; } /* Show debug receiving packet. */ @@ -3144,7 +3154,8 @@ int ospf_read(struct thread *thread) /* Adjust size to message length. */ length = ntohs(ospfh->length) - OSPF_HEADER_SIZE; - /* Read rest of the packet and call each sort of packet routine. */ + /* Read rest of the packet and call each sort of packet routine. + */ switch (ospfh->type) { case OSPF_MSG_HELLO: ospf_hello(iph, ospfh, ibuf, oi, length); @@ -3162,12 +3173,41 @@ int ospf_read(struct thread *thread) ospf_ls_ack(iph, ospfh, ibuf, oi, length); break; default: - flog_warn(EC_OSPF_PACKET, - "interface %s: OSPF packet header type %d is illegal", - IF_NAME(oi), ospfh->type); + flog_warn( + EC_OSPF_PACKET, + "interface %s(%s): OSPF packet header type %d is illegal", + IF_NAME(oi), ospf_get_name(ospf), ospfh->type); break; } + return OSPF_READ_CONTINUE; +} + +/* Starting point of packet process function. */ +int ospf_read(struct thread *thread) +{ + struct ospf *ospf; + int32_t count = 0; + enum ospf_read_return_enum ret; + + /* first of all get interface pointer. */ + ospf = THREAD_ARG(thread); + + /* prepare for next packet. */ + thread_add_read(master, ospf_read, ospf, ospf->fd, &ospf->t_read); + + while (count < ospf->write_oi_count) { + count++; + ret = ospf_read_helper(ospf); + switch (ret) { + case OSPF_READ_ERROR: + return -1; + break; + case OSPF_READ_CONTINUE: + break; + } + } + return 0; } @@ -3825,6 +3865,12 @@ void ospf_db_desc_send(struct ospf_neighbor *nbr) ospf_packet_free(nbr->last_send); nbr->last_send = ospf_packet_dup(op); monotime(&nbr->last_send_ts); + if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) + zlog_info( + "%s:Packet[DD]: %s DB Desc send with seqnum:%x , flags:%x", + (oi->ospf->name) ? oi->ospf->name : VRF_DEFAULT_NAME, + inet_ntoa(nbr->router_id), nbr->dd_seqnum, + nbr->dd_flags); } /* Re-send Database Description. */ @@ -3839,6 +3885,12 @@ void ospf_db_desc_resend(struct ospf_neighbor *nbr) /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON(oi->ospf); + if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) + zlog_info( + "%s:Packet[DD]: %s DB Desc resend with seqnum:%x , flags:%x", + (oi->ospf->name) ? oi->ospf->name : VRF_DEFAULT_NAME, + inet_ntoa(nbr->router_id), nbr->dd_seqnum, + nbr->dd_flags); } /* Send Link State Request. */ diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 5678d545ba..68d9d3bf83 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -150,7 +150,7 @@ static int ospf_interface_address_delete(ZAPI_CALLBACK_ARGS) rn = route_node_lookup(IF_OIFS(ifp), &p); if (!rn) { - connected_free(c); + connected_free(&c); return 0; } @@ -163,7 +163,7 @@ static int ospf_interface_address_delete(ZAPI_CALLBACK_ARGS) ospf_if_interface(c->ifp); - connected_free(c); + connected_free(&c); return 0; } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index b12fa63723..5058886f36 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -2173,3 +2173,11 @@ const char *ospf_vrf_id_to_name(vrf_id_t vrf_id) return vrf ? vrf->name : "NIL"; } + +const char *ospf_get_name(const struct ospf *ospf) +{ + if (ospf->name) + return ospf->name; + else + return VRF_DEFAULT_NAME; +} diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index b31ad30375..937d363b4c 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -572,4 +572,5 @@ extern void ospf_vrf_unlink(struct ospf *ospf, struct vrf *vrf); const char *ospf_vrf_id_to_name(vrf_id_t vrf_id); int ospf_area_nssa_no_summary_set(struct ospf *, struct in_addr); +const char *ospf_get_name(const struct ospf *ospf); #endif /* _ZEBRA_OSPFD_H */ diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 069b3e6c9b..e0fd147b0e 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -133,10 +133,8 @@ DEFPY(pbr_map_match_src, pbr_map_match_src_cmd, if (!pbrms->src) pbrms->src = prefix_new(); prefix_copy(pbrms->src, prefix); - } else { - prefix_free(pbrms->src); - pbrms->src = 0; - } + } else + prefix_free(&pbrms->src); pbr_map_check(pbrms); @@ -162,10 +160,8 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd, if (!pbrms->dst) pbrms->dst = prefix_new(); prefix_copy(pbrms->dst, prefix); - } else { - prefix_free(pbrms->dst); - pbrms->dst = NULL; - } + } else + prefix_free(&pbrms->dst); pbr_map_check(pbrms); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 39e92467ab..719374e3b9 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -109,7 +109,7 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS) "%s: %s deleted %s", __PRETTY_FUNCTION__, c->ifp->name, prefix2str(c->address, buf, sizeof(buf))); - connected_free(c); + connected_free(&c); return 0; } 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..e7e0573968 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, @@ -7379,12 +7381,14 @@ static int pim_cmd_interface_add(struct interface *ifp) struct pim_interface *pim_ifp = ifp->info; if (!pim_ifp) - (void)pim_if_new(ifp, false, true, false, false); + pim_ifp = pim_if_new(ifp, false, true, false, false); else PIM_IF_DO_PIM(pim_ifp->options); pim_if_addr_add_all(ifp); pim_if_membership_refresh(ifp); + + pim_if_create_pimreg(pim_ifp->pim); return 1; } diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 66e64cefa0..48bd031f1e 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -191,11 +191,13 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) pim_upstream_del(pim_ifp->pim, ch->upstream, __PRETTY_FUNCTION__); - else - zlog_warn("%s: Avoiding deletion of upstream with ref_count %d " - "from ifchannel(%s): %s", __PRETTY_FUNCTION__, - ch->upstream->ref_count, ch->interface->name, - ch->sg_str); + else { + if (PIM_DEBUG_PIM_TRACE) + zlog_debug("%s: Avoiding deletion of upstream with ref_count %d " + "from ifchannel(%s): %s", __PRETTY_FUNCTION__, + ch->upstream->ref_count, ch->interface->name, + ch->sg_str); + } ch->upstream = NULL; @@ -617,7 +619,7 @@ static int on_ifjoin_expiry_timer(struct thread *t) ch = THREAD_ARG(t); - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: ifchannel %s expiry timer", __PRETTY_FUNCTION__, ch->sg_str); @@ -636,7 +638,7 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) ch = THREAD_ARG(t); - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: IFCHANNEL%s %s Prune Pending Timer Popped", __PRETTY_FUNCTION__, pim_str_sg_dump(&ch->sg), @@ -945,7 +947,7 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, ch = pim_ifchannel_find(ifp, sg); if (!ch && !(source_flags & PIM_ENCODE_RPT_BIT)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Received prune with no relevant ifchannel %s%s state: %d", __PRETTY_FUNCTION__, ifp->name, diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 7dfd26ea65..3602d98a3e 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -312,6 +312,13 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, return 0; } + if (if_lookup_address(&from, AF_INET, ifp->vrf_id)) { + if (PIM_DEBUG_IGMP_PACKETS) + zlog_debug("Recv IGMP query on interface: %s from ourself %s", + ifp->name, from_str); + return 0; + } + /* Collecting IGMP Rx stats */ switch (query_version) { case 1: @@ -471,21 +478,14 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ - if (PIM_DEBUG_IGMP_PACKETS) { - zlog_debug( - "Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d", - from_str, to_str, igmp->interface->name, len, ip_hlen, - ip_hdr->ip_p); - } - igmp_msg = buf + ip_hlen; msg_type = *igmp_msg; igmp_msg_len = len - ip_hlen; if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug( - "Recv IGMP packet from %s to %s on %s: ttl=%d msg_type=%d msg_size=%d", - from_str, to_str, igmp->interface->name, ip_hdr->ip_ttl, + "Recv IGMP packet from %s to %s on %s: size=%zu ttl=%d msg_type=%d msg_size=%d", + from_str, to_str, igmp->interface->name, len, ip_hdr->ip_ttl, msg_type, igmp_msg_len); } diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index d9b940bba7..2d58340c8c 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -1927,7 +1927,7 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from, if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug( - "Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s", + " Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s", from_str, ifp->name, i, rec_type, rec_auxdatalen, rec_num_sources, inet_ntoa(rec_group)); @@ -1954,7 +1954,7 @@ int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from, sprintf(src_str, "<source?>"); zlog_debug( - "Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s", + " Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s", from_str, ifp->name, i, inet_ntoa(rec_group), src_str); } diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 686475fefe..842d6684b5 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -332,7 +332,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct pim_upstream *up = sg_ch->upstream; PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags); if (up) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: SGRpt flag is set, del inherit oif from up %s", __PRETTY_FUNCTION__, diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index 06a9e6d0d6..418f66df05 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -217,7 +217,7 @@ void pim_jp_agg_upstream_verification(struct pim_upstream *up, bool ignore) struct pim_instance *pim; if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); return; diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index a235ed0569..ec06cd7346 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -300,7 +300,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, } if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); return 0; diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 722ecb2a72..3f2aaf2bbe 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -767,7 +767,7 @@ static void delete_from_neigh_addr(struct interface *ifp, other_neigh_str, ifp->name); listnode_delete(neigh->prefix_list, p); - prefix_free(p); + prefix_free(&p); } } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index cd2d306f3d..342c0a74e0 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -190,6 +190,12 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) no_fwd = header->Nbit; if (header->type == PIM_MSG_TYPE_REGISTER) { + if (pim_msg_len < PIM_MSG_REGISTER_LEN) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("PIM Register Message size=%d shorther than min length %d", + pim_msg_len, PIM_MSG_REGISTER_LEN); + return -1; + } /* First 8 byte header checksum */ checksum = in_cksum(pim_msg, PIM_MSG_REGISTER_LEN); if (checksum != pim_checksum) { diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 4b66616490..aff3fbed6c 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -232,7 +232,7 @@ void pim_null_register_send(struct pim_upstream *up) pim_ifp = up->rpf.source_nexthop.interface->info; if (!pim_ifp) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Cannot send null-register for %s no valid iif", __PRETTY_FUNCTION__, up->sg_str); @@ -241,7 +241,7 @@ void pim_null_register_send(struct pim_upstream *up) rpg = RP(pim_ifp->pim, up->sg.grp); if (!rpg) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Cannot send null-register for %s no RPF to the RP", __PRETTY_FUNCTION__, up->sg_str); @@ -260,7 +260,7 @@ void pim_null_register_send(struct pim_upstream *up) src = pim_ifp->primary_address; if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(up->flags)) { if (!pim_vxlan_get_register_src(pim_ifp->pim, up, &src)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Cannot send null-register for %s vxlan-aa PIP unavailable", __PRETTY_FUNCTION__, up->sg_str); diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 5542db27c9..39493b189b 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -131,7 +131,7 @@ void pim_rp_init(struct pim_instance *pim) rn = route_node_get(pim->rp_table, &rp_info->group); rn->info = rp_info; - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "Allocated: %p for rp_info: %p(224.0.0.0/4) Lock: %d", rn, rp_info, rn->lock); @@ -245,7 +245,7 @@ struct rp_info *pim_rp_find_match_group(struct pim_instance *pim, } rp_info = rn->info; - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX_STRLEN]; route_unlock_node(rn); @@ -348,7 +348,7 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) pim_rp_set_upstream_addr(pim, &new_upstream_addr, up->sg.src, up->sg.grp); - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: pim upstream update for old upstream %s", __PRETTY_FUNCTION__, inet_ntoa(old_upstream_addr)); @@ -366,7 +366,7 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4 = old_upstream_addr; - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX2STR_BUFFER]; prefix2str(&nht_p, buf, sizeof(buf)); @@ -457,6 +457,10 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, struct pim_upstream *up; struct listnode *upnode; + if (rp_addr.s_addr == INADDR_ANY || + rp_addr.s_addr == INADDR_NONE) + return PIM_RP_BAD_ADDRESS; + rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info)); rp_info->rp.rpf_addr.family = AF_INET; @@ -646,7 +650,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, rn = route_node_get(pim->rp_table, &rp_info->group); rn->info = rp_info; - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX_STRLEN]; zlog_debug("Allocated: %p for rp_info: %p(%s) Lock: %d", rn, @@ -751,7 +755,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, was_plist = true; } - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: Delete RP %s for the group %s", __PRETTY_FUNCTION__, rp_str, grp_str); @@ -765,7 +769,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, if (bsgrp) { bsrp = listnode_head(bsgrp->bsrp_list); if (bsrp) { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char bsrp_str[INET_ADDRSTRLEN]; if (!inet_ntop(AF_INET, bsrp, bsrp_str, @@ -780,7 +784,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, group, RP_SRC_BSR); } } else { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: BSM RP not found for the group %s", __PRETTY_FUNCTION__, grp_str); @@ -839,7 +843,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, EC_LIB_DEVELOPMENT, "Expected rn->info to be equal to rp_info"); - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX_STRLEN]; zlog_debug( @@ -1261,7 +1265,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) json = json_object_new_object(); else vty_out(vty, - "RP address group/prefix-list OIF I am RP Source\n"); + "RP address group/prefix-list OIF I am RP Source\n"); for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (!pim_rpf_addr_is_inaddr_none(&rp_info->rp)) { char buf[48]; @@ -1338,7 +1342,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) vty_out(vty, "%-16s ", "(Unknown)"); if (rp_info->i_am_rp) - vty_out(vty, "yes\n"); + vty_out(vty, "yes"); else vty_out(vty, "no"); diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 357ad6ba46..d383ef5249 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -42,7 +42,7 @@ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); void pim_rpf_set_refresh_time(struct pim_instance *pim) { pim->last_route_change_time = pim_time_monotonic_usec(); - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: vrf(%s) New last route change time: %" PRId64, __PRETTY_FUNCTION__, pim->vrf->name, pim->last_route_change_time); @@ -69,7 +69,7 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, if ((nexthop->last_lookup.s_addr == addr.s_addr) && (nexthop->last_lookup_time > pim->last_route_change_time)) { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); @@ -85,7 +85,7 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, pim->nexthop_lookups_avoided++; return true; } else { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_NHT) { char addr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index d93a360448..4fe3237395 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -757,8 +757,7 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, */ if (!*hello_option_addr_list) { *hello_option_addr_list = list_new(); - (*hello_option_addr_list)->del = - (void (*)(void *))prefix_free; + (*hello_option_addr_list)->del = prefix_free_lists; } /* diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index c0651561ac..40b7e3d236 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -159,7 +159,7 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, bool notify_msdp = false; struct prefix nht_p; - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s(%s): Delete %s[%s] ref count: %d , flags: %d c_oil ref count %d (Pre decrement)", __PRETTY_FUNCTION__, name, up->sg_str, pim->vrf->name, @@ -231,7 +231,7 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4 = up->upstream_addr; - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char buf[PREFIX2STR_BUFFER]; prefix2str(&nht_p, buf, sizeof(buf)); zlog_debug("%s: Deregister upstream %s addr %s with Zebra NHT", @@ -248,13 +248,13 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, void pim_upstream_send_join(struct pim_upstream *up) { if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); return; } - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char rpf_str[PREFIX_STRLEN]; pim_addr_dump("<rpf?>", &up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); @@ -280,7 +280,7 @@ static int on_join_timer(struct thread *t) up = THREAD_ARG(t); if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); return 0; @@ -381,7 +381,7 @@ void pim_upstream_join_suppress(struct pim_upstream *up, long join_timer_remain_msec; if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); return; @@ -393,7 +393,7 @@ void pim_upstream_join_suppress(struct pim_upstream *up, join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char rpf_str[INET_ADDRSTRLEN]; pim_inet4_dump("<rpf?>", rpf_addr, rpf_str, sizeof(rpf_str)); zlog_debug( @@ -403,7 +403,7 @@ void pim_upstream_join_suppress(struct pim_upstream *up, } if (join_timer_remain_msec < t_joinsuppress_msec) { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { zlog_debug( "%s %s: suppressing Join(S,G)=%s for %ld msec", __FILE__, __PRETTY_FUNCTION__, up->sg_str, @@ -421,7 +421,7 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, int t_override_msec; if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); return; @@ -431,7 +431,7 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface); - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char rpf_str[INET_ADDRSTRLEN]; pim_inet4_dump("<rpf?>", up->rpf.rpf_addr.u.prefix4, rpf_str, sizeof(rpf_str)); @@ -442,7 +442,7 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, } if (join_timer_remain_msec > t_override_msec) { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { zlog_debug( "%s: decreasing (S,G)=%s join timer to t_override=%d msec", debug_label, up->sg_str, t_override_msec); @@ -494,7 +494,7 @@ static int pim_upstream_could_register(struct pim_upstream *up) if (up->rpf.source_nexthop.interface) pim_ifp = up->rpf.source_nexthop.interface->info; else { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); } @@ -694,7 +694,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, */ if (!pim_rp_set_upstream_addr(pim, &up->upstream_addr, sg->src, sg->grp)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: Received a (*,G) with no RP configured", __PRETTY_FUNCTION__); } @@ -752,7 +752,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, } else if (up->upstream_addr.s_addr != INADDR_ANY) { rpf_result = pim_rpf_update(pim, up, NULL); if (rpf_result == PIM_RPF_FAILURE) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Attempting to create upstream(%s), Unable to RPF for source", __PRETTY_FUNCTION__, up->sg_str); @@ -770,7 +770,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, listnode_add_sort(pim->upstream_list, up); - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { zlog_debug( "%s: Created Upstream %s upstream_addr %s ref count %d increment", __PRETTY_FUNCTION__, up->sg_str, @@ -806,7 +806,7 @@ struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, if (!(up->flags & flags)) { up->flags |= flags; up->ref_count++; - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s(%s): upstream %s ref count %d increment", __PRETTY_FUNCTION__, name, up->sg_str, @@ -823,7 +823,7 @@ void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name) { up->flags |= flags; ++up->ref_count; - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s(%s): upstream %s ref count %d increment", __PRETTY_FUNCTION__, name, up->sg_str, up->ref_count); @@ -846,7 +846,7 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim, up = pim_upstream_new(pim, sg, incoming, flags, ch); } - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { if (up) { char buf[PREFIX2STR_BUFFER]; prefix2str(&up->rpf.rpf_addr, buf, sizeof(buf)); @@ -999,7 +999,7 @@ void pim_upstream_rpf_genid_changed(struct pim_instance *pim, */ for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char neigh_str[INET_ADDRSTRLEN]; char rpf_addr_str[PREFIX_STRLEN]; pim_inet4_dump("<neigh?>", neigh_addr, neigh_str, @@ -1108,7 +1108,7 @@ static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim, if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) return; - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("kat expired on %s; clear fhr reg state", up->sg_str); @@ -1128,7 +1128,7 @@ static void pim_upstream_fhr_kat_expiry(struct pim_instance *pim, static void pim_upstream_fhr_kat_start(struct pim_upstream *up) { if (pim_upstream_could_register(up)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "kat started on %s; set fhr reg state to joined", up->sg_str); @@ -1174,7 +1174,7 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc( /* if entry was created because of activity we need to deref it */ if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { pim_upstream_fhr_kat_expiry(pim, up); - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "kat expired on %s[%s]; remove stream reference", up->sg_str, pim->vrf->name); @@ -1222,7 +1222,7 @@ static int pim_upstream_keep_alive_timer(struct thread *t) void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time) { if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("kat start on %s with no stream reference", up->sg_str); } @@ -1326,7 +1326,7 @@ void pim_upstream_set_sptbit(struct pim_upstream *up, // iif == RPF_interfvace(S) if (up->rpf.source_nexthop.interface != incoming) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Incoming Interface: %s is different than RPF_interface(S) %s", __PRETTY_FUNCTION__, incoming->name, @@ -1336,7 +1336,7 @@ void pim_upstream_set_sptbit(struct pim_upstream *up, // AND JoinDesired(S,G) == true if (!pim_upstream_evaluate_join_desired(up->channel_oil->pim, up)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: %s Join is not Desired", __PRETTY_FUNCTION__, up->sg_str); return; @@ -1345,7 +1345,7 @@ void pim_upstream_set_sptbit(struct pim_upstream *up, // DirectlyConnected(S) == true if (pim_if_connected_to_source(up->rpf.source_nexthop.interface, up->sg.src)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: %s is directly connected to the source", __PRETTY_FUNCTION__, up->sg_str); up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; @@ -1358,7 +1358,7 @@ void pim_upstream_set_sptbit(struct pim_upstream *up, .interface != starup->rpf.source_nexthop.interface) { struct pim_upstream *starup = up->parent; - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: %s RPF_interface(S) != RPF_interface(RP(G))", __PRETTY_FUNCTION__, up->sg_str); @@ -1371,7 +1371,7 @@ void pim_upstream_set_sptbit(struct pim_upstream *up, // OR inherited_olist(S,G,rpt) == NULL if (pim_upstream_is_sg_rpt(up) && pim_upstream_empty_inherited_olist(up)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: %s OR inherited_olist(S,G,rpt) == NULL", __PRETTY_FUNCTION__, up->sg_str); up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; @@ -1381,7 +1381,7 @@ void pim_upstream_set_sptbit(struct pim_upstream *up, // OR ( ( RPF'(S,G) == RPF'(*,G) ) AND // ( RPF'(S,G) != NULL ) ) if (up->parent && pim_rpf_is_same(&up->rpf, &up->parent->rpf)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: %s RPF'(S,G) is the same as RPF'(*,G)", __PRETTY_FUNCTION__, up->sg_str); up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE; @@ -1434,7 +1434,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) up = THREAD_ARG(t); pim = up->channel_oil->pim; - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { char state_str[PIM_REG_STATE_STR_LEN]; zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s", __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, @@ -1452,7 +1452,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) break; case PIM_REG_PRUNE: if (!up->rpf.source_nexthop.interface) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); return 0; @@ -1460,7 +1460,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) pim_ifp = up->rpf.source_nexthop.interface->info; if (!pim_ifp) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Interface: %s is not configured for pim", __PRETTY_FUNCTION__, @@ -1473,7 +1473,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) if (((up->channel_oil->cc.lastused / 100) > pim->keep_alive_time) && (I_am_RP(pim_ifp->pim, up->sg.grp))) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Stop sending the register, because I am the RP and we haven't seen a packet in a while", __PRETTY_FUNCTION__); @@ -1503,7 +1503,7 @@ void pim_upstream_start_register_stop_timer(struct pim_upstream *up, } else time = PIM_REGISTER_PROBE_PERIOD; - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { zlog_debug( "%s: (S,G)=%s Starting upstream register stop timer %d", __PRETTY_FUNCTION__, up->sg_str, time); @@ -1521,7 +1521,7 @@ int pim_upstream_inherited_olist_decide(struct pim_instance *pim, int output_intf = 0; if (!up->rpf.source_nexthop.interface) - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: up %s RPF is not present", __PRETTY_FUNCTION__, up->sg_str); @@ -1611,7 +1611,7 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim) */ for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) { if (up->upstream_addr.s_addr == INADDR_ANY) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: RP not configured for Upstream %s", __PRETTY_FUNCTION__, up->sg_str); @@ -1619,7 +1619,7 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim) } if (pim_rpf_addr_is_inaddr_any(&up->rpf)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Upstream %s without a path to send join, checking", __PRETTY_FUNCTION__, up->sg_str); @@ -1725,7 +1725,7 @@ static void pim_upstream_sg_running(void *arg) // No packet can have arrived here if this is the case if (!up->channel_oil->installed) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug("%s: %s%s is not installed in mroute", __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name); @@ -1741,7 +1741,7 @@ static void pim_upstream_sg_running(void *arg) * to get us up and working for the moment */ if (up->channel_oil->oil_inherited_rescan) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "%s: Handling unscanned inherited_olist for %s[%s]", __PRETTY_FUNCTION__, up->sg_str, @@ -1754,7 +1754,7 @@ static void pim_upstream_sg_running(void *arg) // Have we seen packets? if ((up->channel_oil->cc.oldpktcnt >= up->channel_oil->cc.pktcnt) && (up->channel_oil->cc.lastused / 100 > 30)) { - if (PIM_DEBUG_TRACE) { + if (PIM_DEBUG_PIM_TRACE) { zlog_debug( "%s[%s]: %s old packet count is equal or lastused is greater than 30, (%ld,%ld,%lld)", __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name, @@ -1769,7 +1769,7 @@ static void pim_upstream_sg_running(void *arg) /* Add a source reference to the stream if * one doesn't already exist */ if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { - if (PIM_DEBUG_TRACE) + if (PIM_DEBUG_PIM_TRACE) zlog_debug( "source reference created on kat restart %s[%s]", up->sg_str, pim->vrf->name); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index dadcbbe65d..b297615435 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -233,7 +233,7 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS) pim_i_am_rp_re_evaluate(pim); } - connected_free(c); + connected_free(&c); return 0; } @@ -855,27 +855,24 @@ void igmp_source_forward_start(struct pim_instance *pim, } } - result = pim_channel_add_oif(source->source_channel_oil, - group->group_igmp_sock->interface, - PIM_OIF_FLAG_PROTO_IGMP); - if (result) { - if (PIM_DEBUG_MROUTE) { - zlog_warn("%s: add_oif() failed with return=%d", - __func__, result); + if (PIM_I_am_DR(pim_oif)) { + result = pim_channel_add_oif(source->source_channel_oil, + group->group_igmp_sock->interface, + PIM_OIF_FLAG_PROTO_IGMP); + if (result) { + if (PIM_DEBUG_MROUTE) { + zlog_warn("%s: add_oif() failed with return=%d", + __func__, result); + } + return; } - return; - } - - if (!(PIM_I_am_DR(pim_oif))) { + } else { if (PIM_DEBUG_IGMP_TRACE) zlog_debug("%s: %s was received on %s interface but we are not DR for that interface", __PRETTY_FUNCTION__, pim_str_sg_dump(&sg), group->group_igmp_sock->interface->name); - pim_channel_del_oif(source->source_channel_oil, - group->group_igmp_sock->interface, - PIM_OIF_FLAG_PROTO_IGMP); return; } /* 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_interface.c b/ripd/rip_interface.c index 3173277ba7..4d48740606 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -648,7 +648,7 @@ int rip_interface_address_delete(ZAPI_CALLBACK_ARGS) rip_apply_address_del(ifc); } - connected_free(ifc); + connected_free(&ifc); } return 0; 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_interface.c b/ripngd/ripng_interface.c index 9209a76460..97113a180f 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -430,7 +430,7 @@ int ripng_interface_address_delete(ZAPI_CALLBACK_ARGS) /* Check wether this prefix needs to be removed. */ ripng_apply_address_del(ifc); } - connected_free(ifc); + connected_free(&ifc); } return 0; 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/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index da2aa2f539..cd577e9051 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -73,7 +73,7 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS) if (!c) return 0; - connected_free(c); + connected_free(&c); return 0; } diff --git a/staticd/static_vty.c b/staticd/static_vty.c index f926e1d9cd..48ad10e90c 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -426,15 +426,15 @@ static int static_route_leak( /* Null0 static route. */ if (ifname != NULL) { - if (strncasecmp(ifname, "Null0", strlen(ifname)) == 0 - || strncasecmp(ifname, "reject", strlen(ifname)) == 0 - || strncasecmp(ifname, "blackhole", strlen(ifname)) == 0) { + if (strcasecmp(ifname, "Null0") == 0 + || strcasecmp(ifname, "reject") == 0 + || strcasecmp(ifname, "blackhole") == 0) { if (vty) vty_out(vty, - "%% Nexthop interface cannot be Null0, reject or blackhole\n"); + "%% Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)\n"); else zlog_warn( - "%s: Nexthop interface cannot be Null0, reject or blackhole for %s", + "%s: %s: Nexthop interface name can not be from reserved keywords (Null0, reject, blackhole)\n", __PRETTY_FUNCTION__, dest_str); return CMD_WARNING_CONFIG_FAILED; } diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 976f892efb..a474613b4d 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -79,7 +79,7 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS) if (!c) return 0; - connected_free(c); + connected_free(&c); return 0; } @@ -260,7 +260,7 @@ static void static_nht_hash_free(void *data) { struct static_nht_data *nhtd = data; - prefix_free(nhtd->nh); + prefix_free(&nhtd->nh); XFREE(MTYPE_TMP, nhtd); } 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/tests/topotests/bgp-path-attributes-topo1/bgp_path_attributes.json b/tests/topotests/bgp-path-attributes-topo1/bgp_path_attributes.json index 15b7ec13be..de2bffa33d 100644 --- a/tests/topotests/bgp-path-attributes-topo1/bgp_path_attributes.json +++ b/tests/topotests/bgp-path-attributes-topo1/bgp_path_attributes.json @@ -12,6 +12,17 @@ "r2":{"ipv4":"auto", "ipv6":"auto"}, "r3":{"ipv4":"auto", "ipv6":"auto"} }, + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + } + ] + }, "bgp":{ "local_as":"555", "address_family": { @@ -20,8 +31,34 @@ "neighbor": { "r2": { "dest_link": { + "r1": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r3": { + "dest_link": { "r1": {} } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } }, "r3": { "dest_link": { @@ -65,6 +102,27 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r3": { + "dest_link": { + "r2": {} + } + }, + "r4": { + "dest_link": { + "r2-link1": {} + } + } + } + } } } } @@ -99,6 +157,27 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r2": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } } } } @@ -128,6 +207,22 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": {} + } + }, + "r6": { + "dest_link": { + "r4": {} + } + } + } + } } } } @@ -156,6 +251,22 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + }, + "r7": { + "dest_link": { + "r5": {} + } + } + } + } } } } @@ -184,6 +295,22 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": {} + } + }, + "r7": { + "dest_link": { + "r6": {} + } + } + } + } } } } @@ -212,6 +339,22 @@ } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r7": {} + } + }, + "r6": { + "dest_link": { + "r7": {} + } + } + } + } } } } diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py index 9f92b4b290..3b2d9c25d7 100755 --- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py +++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py @@ -76,13 +76,14 @@ from lib.common_config import ( write_test_footer, reset_config_on_routers, verify_rib, create_static_routes, create_prefix_lists, verify_prefix_lists, - create_route_maps + create_route_maps, check_address_types ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, clear_bgp_and_verify, verify_best_path_as_per_bgp_attribute, - verify_best_path_as_per_admin_distance + verify_best_path_as_per_admin_distance, modify_as_number, + verify_as_numbers ) from lib.topojson import build_topo_from_json, build_config_from_json @@ -95,6 +96,8 @@ try: except IOError: assert False, "Could not read file {}".format(jsonFile) +# Address read from env variables +ADDR_TYPES = check_address_types() #### class CreateTopo(Topo): @@ -119,6 +122,8 @@ def setup_module(mod): * `mod`: module name """ + global ADDR_TYPES + testsuite_run_time = time.asctime(time.localtime(time.time())) logger.info("Testsuite start time: %s", testsuite_run_time) logger.info("=" * 40) @@ -170,6 +175,7 @@ def teardown_module(): ## Testcases ## ##################################################### + def test_next_hop_attribute(request): """ Verifying route are not getting installed in, as next_hop is @@ -193,7 +199,7 @@ def test_next_hop_attribute(request): # Api call to advertise networks input_dict = { "r7": { - "bgp":{ + "bgp": { "address_family": { "ipv4": { "unicast": { @@ -206,6 +212,18 @@ def test_next_hop_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -218,9 +236,12 @@ def test_next_hop_attribute(request): # Verifying RIB routes dut = "r1" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False) - assert result is not True, "Testcase {} : Failed \n Error: Routes still" \ - " present in RIB".format(tc_name) + # Verification should fail as nexthop-self is not enabled + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n Error: "\ + "{} routes are not present in RIB".format(addr_type, tc_name) # Configure next-hop-self to bgp neighbor input_dict_1 = { @@ -237,6 +258,17 @@ def test_next_hop_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -254,11 +286,23 @@ def test_next_hop_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } } } + result = create_router_bgp(tgen, topo, input_dict_1) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -266,9 +310,11 @@ def test_next_hop_attribute(request): # Verifying RIB routes dut = "r1" protocol = "bgp" - result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + for addr_type in ADDR_TYPES: + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) write_test_footer(tc_name) @@ -305,6 +351,18 @@ def test_aspath_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -322,6 +380,17 @@ def test_aspath_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -339,6 +408,17 @@ def test_aspath_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } @@ -351,11 +431,136 @@ def test_aspath_attribute(request): # Verifying best path dut = "r1" attribute = "aspath" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, - input_dict, attribute) + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Modify AS-Path and verify best path is changed + # Create Prefix list + + input_dict_2 = { + "r3": { + "prefix_lists": { + "ipv4": { + "pf_ls_1_ipv4": [{ + "seqid": 10, + "network": "200.0.0.0/8", + "le": "32", + "action": "permit" + }] + }, + "ipv6": { + "pf_ls_1_ipv6": [{ + "seqid": 10, + "network": "200::/8", + "le": "128", + "action": "permit" + }] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Create route map + input_dict_3 = { + "r3": { + "route_maps": { + "RMAP_AS_PATH": [{ + "action": "permit", + "match": { + "ipv4": { + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "aspath": { + "as_num": "111 222", + "as_action": "prepend" + } + } + }, + { + "action": "permit", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" + } + }, + "set": { + "aspath": { + "as_num": "111 222", + "as_action": "prepend" + } + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Configure neighbor for route map + input_dict_4 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": "RMAP_AS_PATH", + "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": "RMAP_AS_PATH", + "direction": "in"} + ] + } + } + } + } + } + } + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_4) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) + # Verifying best path + dut = "r1" + attribute = "aspath" + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + write_test_footer(tc_name) @@ -391,6 +596,18 @@ def test_localpref_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -408,6 +625,17 @@ def test_localpref_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -425,11 +653,23 @@ def test_localpref_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } } } + result = create_router_bgp(tgen, topo, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -439,12 +679,20 @@ def test_localpref_attribute(request): "r2": { "prefix_lists": { "ipv4": { - "pf_ls_1": [{ + "pf_ls_1_ipv4": [{ "seqid": 10, "network": "200.0.0.0/8", "le": "32", "action": "permit" }] + }, + "ipv6": { + "pf_ls_1_ipv6": [{ + "seqid": 10, + "network": "200::/8", + "le": "128", + "action": "permit" + }] } } } @@ -459,13 +707,26 @@ def test_localpref_attribute(request): "route_maps": { "RMAP_LOCAL_PREF": [{ "action": "permit", + "seq_id": "10", "match": { "ipv4": { - "prefix_lists": "pf_ls_1" + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "localpref": 1111 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" } }, "set": { - "localpref": 1000 + "localpref": 1111 } }] } @@ -483,9 +744,25 @@ def test_localpref_attribute(request): "ipv4": { "unicast": { "neighbor": { - "r1": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [ + {"name": "RMAP_LOCAL_PREF", + "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { "dest_link": { - "r2": { + "r2-link1": { "route_maps": [ {"name": "RMAP_LOCAL_PREF", "direction": "in"} @@ -500,7 +777,6 @@ def test_localpref_attribute(request): } } } - result = create_router_bgp(tgen, topo, input_dict_4) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -508,16 +784,66 @@ def test_localpref_attribute(request): # Verifying best path dut = "r1" attribute = "localpref" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, - input_dict, attribute) + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Modify route map + input_dict_3 = { + "r2": { + "route_maps": { + "RMAP_LOCAL_PREF": [{ + "action": "permit", + "seq_id": "10", + "match": { + "ipv4": { + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "localpref": 50 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" + } + }, + "set": { + "localpref": 50 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) + # Verifying best path + dut = "r1" + attribute = "localpref" + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + write_test_footer(tc_name) def test_weight_attribute(request): - " Verifying WEIGHT attribute functionality" + """ + Test configure/modify weight attribute and + verify best path is installed as per highest weight + """ tgen = get_topogen() @@ -548,6 +874,18 @@ def test_weight_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -565,6 +903,17 @@ def test_weight_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -582,6 +931,17 @@ def test_weight_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } @@ -596,12 +956,20 @@ def test_weight_attribute(request): "r1": { "prefix_lists": { "ipv4": { - "pf_ls_1": [{ + "pf_ls_1_ipv4": [{ "seqid": 10, "network": "200.0.0.0/8", "le": "32", "action": "permit" }] + }, + "ipv6": { + "pf_ls_1_ipv6": [{ + "seqid": 10, + "network": "200::/8", + "le": "128", + "action": "permit" + }] } } } @@ -616,9 +984,22 @@ def test_weight_attribute(request): "route_maps": { "RMAP_WEIGHT": [{ "action": "permit", + "seq_id": "5", "match": { "ipv4": { - "prefix_lists": "pf_ls_1" + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "weight": 500 + } + }, + { + "action": "permit", + "seq_id": "10", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" } }, "set": { @@ -652,6 +1033,22 @@ def test_weight_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": { + "route_maps": [ + {"name": "RMAP_WEIGHT", + "direction": "in"} + ] + } + } + } + } + } } } } @@ -664,16 +1061,66 @@ def test_weight_attribute(request): # Verifying best path dut = "r1" attribute = "weight" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, - input_dict, attribute) + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Modify route map + input_dict_3 = { + "r1": { + "route_maps": { + "RMAP_WEIGHT": [{ + "action": "permit", + "seq_id": "5", + "match": { + "ipv4": { + "prefix_lists": "pf_ls_1_ipv4" + } + }, + "set": { + "weight": 1000 + } + }, + { + "action": "permit", + "seq_id": "10", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_1_ipv6" + } + }, + "set": { + "weight": 1000 + } + }] + } + } + } + result = create_route_maps(tgen, input_dict_3) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) + # Verifying best path + dut = "r1" + attribute = "weight" + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r7": input_dict["r7"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + write_test_footer(tc_name) def test_origin_attribute(request): - " Verifying ORIGIN attribute functionality" + """ + Test origin attribute and verify best path is + installed as per IGP>EGP>INCOMPLETE rule + """ tgen = get_topogen() @@ -704,6 +1151,18 @@ def test_origin_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } @@ -721,6 +1180,17 @@ def test_origin_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } + } + } + } } } } @@ -738,6 +1208,17 @@ def test_origin_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + } + } + } } } } @@ -752,6 +1233,14 @@ def test_origin_attribute(request): {"redist_type": "connected"} ] } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } } } } @@ -767,11 +1256,19 @@ def test_origin_attribute(request): "static_routes": [ { "network": "200.50.2.0/32", - "next_hop": "10.0.0.26" + "next_hop": "Null0" }, { "network": "200.60.2.0/32", - "next_hop": "10.0.0.26" + "next_hop": "Null0" + }, + { + "network": "200:50:2::/128", + "next_hop": "Null0" + }, + { + "network": "200:60:2::/128", + "next_hop": "Null0" } ] } @@ -780,23 +1277,24 @@ def test_origin_attribute(request): assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) - # Api call to redistribute static routes - - # Configure next-hop-self to bgp neighbor - # Verifying best path dut = "r1" attribute = "origin" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, - input_dict, attribute) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + {"r4": input_dict["r4"]}, + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) write_test_footer(tc_name) def test_med_attribute(request): - " Verifying MED attribute functionality" + """ + Test configure/modify MED attribute and verify best path + is installed as per lowest med value + """ tgen = get_topogen() @@ -814,7 +1312,7 @@ def test_med_attribute(request): # Api call to advertise networks input_dict = { "r4": { - "bgp":{ + "bgp": { "address_family": { "ipv4": { "unicast": { @@ -827,49 +1325,102 @@ def test_med_attribute(request): } ] } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } + } + } + } + }, + "r5": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + { + "network": "200.50.2.0/32" + }, + { + "network": "200.60.2.0/32" + } + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "200:50:2::/128" + }, + { + "network": "200:60:2::/128" + } + ] + } } } } } } + result = create_router_bgp(tgen, topo, input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) - # Api call to advertise networks - - - # Configure next-hop-self to bgp neighbor - - # Create Prefix list - input_dict_3 = { + input_dict_2 = { "r2": { "prefix_lists": { "ipv4": { - "pf_ls_r2": [{ + "pf_ls_r2_ipv4": [{ "seqid": 10, "network": "200.0.0.0/8", "le": "32", "action": "permit" }] + }, + "ipv6": { + "pf_ls_r2_ipv6": [{ + "seqid": 20, + "network": "200::/8", + "le": "128", + "action": "permit" + }] } } }, "r3": { "prefix_lists": { "ipv4": { - "pf_ls_r3": [{ + "pf_ls_r3_ipv4": [{ "seqid": 10, "network": "200.0.0.0/8", "le": "32", "action": "permit" }] + }, + "ipv6": { + "pf_ls_r3_ipv6": [{ + "seqid": 20, + "network": "200::/8", + "le": "128", + "action": "permit" + }] } } } } - result = create_prefix_lists(tgen, input_dict_3) + result = create_prefix_lists(tgen, input_dict_2) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -879,9 +1430,22 @@ def test_med_attribute(request): "route_maps": { "RMAP_MED_R2": [{ "action": "permit", + "seq_id": "10", "match": { "ipv4": { - "prefix_lists": "pf_ls_r2" + "prefix_lists": "pf_ls_r2_ipv4" + } + }, + "set": { + "med": 100 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_r2_ipv6" } }, "set": { @@ -894,9 +1458,22 @@ def test_med_attribute(request): "route_maps": { "RMAP_MED_R3": [{ "action": "permit", + "seq_id": "10", "match": { "ipv4": { - "prefix_lists": "pf_ls_r3" + "prefix_lists": "pf_ls_r3_ipv4" + } + }, + "set": { + "med": 10 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_r3_ipv6" } }, "set": { @@ -912,28 +1489,31 @@ def test_med_attribute(request): # Configure neighbor for route map input_dict_4 = { - "r5": { + "r2": { "bgp": { "address_family": { "ipv4": { "unicast": { - "advertise_networks": [ - { - "network": "200.50.2.0/32" + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [ + {"name": "RMAP_MED_R2", + "direction": "in"} + ] + } + } }, - { - "network": "200.60.2.0/32" + "r1": { + "dest_link": { + "r2": {"next_hop_self": True} + } } - ] + } } - } - } - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { + }, + "ipv6": { "unicast": { "neighbor": { "r4": { @@ -980,11 +1560,33 @@ def test_med_attribute(request): } } } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"next_hop_self": True} + } + }, + "r5": { + "dest_link": { + "r3": { + "route_maps": [ + {"name": "RMAP_MED_R3", + "direction": "in"} + ] + } + } + } + } + } } } } } } + result = create_router_bgp(tgen, topo, input_dict_4) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) @@ -992,12 +1594,58 @@ def test_med_attribute(request): # Verifying best path dut = "r1" attribute = "med" - result = verify_best_path_as_per_bgp_attribute(tgen, "ipv4", dut, + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, input_dict, attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + # Modify route-map to set med value + input_dict_3 = { + "r3": { + "route_maps": { + "RMAP_MED_R3": [{ + "action": "permit", + "seq_id": "10", + "match": { + "ipv4": { + "prefix_lists": "pf_ls_r3_ipv4" + } + }, + "set": { + "med": 200 + } + }, + { + "action": "permit", + "seq_id": "20", + "match": { + "ipv6": { + "prefix_lists": "pf_ls_r3_ipv6" + } + }, + "set": { + "med": 200 + } + }] + } + } + } + + result = create_route_maps(tgen, input_dict_3) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) - logger.info("Testcase %s :Passed \n", tc_name) + # Verifying best path + dut = "r1" + attribute = "med" + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut, + input_dict, attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + + write_test_footer(tc_name) # Uncomment next line for debugging # tgen.mininet_cli() @@ -1032,6 +1680,16 @@ def test_admin_distance(request): "network": "200.50.2.0/32", "admin_distance": 60, "next_hop": "10.0.0.18" + }, + { + "network": "200:50:2::/128", + "admin_distance": 80, + "next_hop": "fd00::1" + }, + { + "network": "200:50:2::/128", + "admin_distance": 60, + "next_hop": "fd00::1" } ] } @@ -1052,6 +1710,14 @@ def test_admin_distance(request): {"redist_type": "connected"} ] } + }, + "ipv6": { + "unicast": { + "redistribute": [ + {"redist_type": "static"}, + {"redist_type": "connected"} + ] + } } } } @@ -1064,10 +1730,45 @@ def test_admin_distance(request): # Verifying best path dut = "r1" attribute = "admin_distance" - result = verify_best_path_as_per_admin_distance(tgen, "ipv4", dut, - input_dict, attribute) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result) + + input_dict = { + "ipv4": { + "r2": { + "static_routes": [{ + "network": "200.50.2.0/32", + "admin_distance": 80, + "next_hop": "10.0.0.14" + }, + { + "network": "200.50.2.0/32", + "admin_distance": 60, + "next_hop": "10.0.0.18" + } + ] + } + }, + "ipv6": { + "r2": { + "static_routes": [{ + "network": "200:50:2::/128", + "admin_distance": 80, + "next_hop": "fd00::1" + }, + { + "network": "200:50:2::/128", + "admin_distance": 60, + "next_hop": "fd00::1" + }] + } + } + } + + for addr_type in ADDR_TYPES: + result = verify_best_path_as_per_admin_distance(tgen, addr_type, dut, + input_dict[addr_type], + attribute) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) write_test_footer(tc_name) diff --git a/tests/topotests/bgp_distance_change/__init__.py b/tests/topotests/bgp_distance_change/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_distance_change/__init__.py diff --git a/tests/topotests/bgp_distance_change/r1/bgpd.conf b/tests/topotests/bgp_distance_change/r1/bgpd.conf new file mode 100644 index 0000000000..67994702bc --- /dev/null +++ b/tests/topotests/bgp_distance_change/r1/bgpd.conf @@ -0,0 +1,4 @@ +router bgp 65000 + neighbor 192.168.255.2 remote-as 65001 + exit-address-family +! diff --git a/tests/topotests/bgp_distance_change/r1/zebra.conf b/tests/topotests/bgp_distance_change/r1/zebra.conf new file mode 100644 index 0000000000..6e9b0b4a7e --- /dev/null +++ b/tests/topotests/bgp_distance_change/r1/zebra.conf @@ -0,0 +1,6 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_distance_change/r2/bgpd.conf b/tests/topotests/bgp_distance_change/r2/bgpd.conf new file mode 100644 index 0000000000..206f626da4 --- /dev/null +++ b/tests/topotests/bgp_distance_change/r2/bgpd.conf @@ -0,0 +1,6 @@ +router bgp 65001 + neighbor 192.168.255.1 remote-as 65000 + address-family ipv4 + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_distance_change/r2/zebra.conf b/tests/topotests/bgp_distance_change/r2/zebra.conf new file mode 100644 index 0000000000..93e3590448 --- /dev/null +++ b/tests/topotests/bgp_distance_change/r2/zebra.conf @@ -0,0 +1,9 @@ +! +interface lo + ip address 172.16.255.254/32 +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py new file mode 100644 index 0000000000..cf95aec098 --- /dev/null +++ b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python + +# +# bgp_distance_change.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +bgp_distance_change.py: + +Test if works the following commands: +router bgp 65031 + address-family ipv4 unicast + distance bgp 123 123 123 + +Changed distance should reflect to RIB after changes. +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_maximum_prefix_invalid(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears['r1'] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) + expected = { + '192.168.255.2': { + 'bgpState': 'Established', + 'addressFamilyInfo': { + 'ipv4Unicast': { + 'acceptedPrefixCounter': 2 + } + } + } + } + return topotest.json_cmp(output, expected) + + def _bgp_distance_change(router): + router.vtysh_cmd(""" + configure terminal + router bgp 65000 + address-family ipv4 unicast + distance bgp 123 123 123 + """) + + def _bgp_check_distance_change(router): + output = json.loads(router.vtysh_cmd("show ip route 172.16.255.254/32 json")) + expected = { + '172.16.255.254/32': [ + { + 'protocol': 'bgp', + 'distance': 123 + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + + assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) + + _bgp_distance_change(router) + + test_func = functools.partial(_bgp_check_distance_change, router) + success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + + assert result is None, 'Failed to see applied BGP distance in RIB "{}"'.format(router) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/__init__.py b/tests/topotests/bgp_sender-as-path-loop-detection/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/__init__.py diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf new file mode 100644 index 0000000000..a91b564bff --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf @@ -0,0 +1,12 @@ +! exit1 +router bgp 65001 + neighbor 192.168.255.1 remote-as 65002 + address-family ipv4 unicast + neighbor 192.168.255.1 route-map prepend out + redistribute connected + exit-address-family + ! +! +route-map prepend permit 10 + set as-path prepend 65003 +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r1/zebra.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r1/zebra.conf new file mode 100644 index 0000000000..9904bb4e16 --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r1/zebra.conf @@ -0,0 +1,9 @@ +! exit1 +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf new file mode 100644 index 0000000000..6e8e89360f --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf @@ -0,0 +1,8 @@ +! spine +router bgp 65002 + neighbor 192.168.255.2 remote-as 65001 + neighbor 192.168.255.2 solo + neighbor 192.168.254.2 remote-as 65003 + neighbor 192.168.254.2 solo + neighbor 192.168.254.2 sender-as-path-loop-detection +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r2/zebra.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r2/zebra.conf new file mode 100644 index 0000000000..f0d357c5ff --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r2/zebra.conf @@ -0,0 +1,9 @@ +! spine +interface r2-eth0 + ip address 192.168.255.1/30 +! +interface r2-eth1 + ip address 192.168.254.1/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf new file mode 100644 index 0000000000..8962befad2 --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf @@ -0,0 +1,4 @@ +! exit2 +router bgp 65003 + neighbor 192.168.254.1 remote-as 65002 +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r3/zebra.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r3/zebra.conf new file mode 100644 index 0000000000..a10fe3a3c7 --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/r3/zebra.conf @@ -0,0 +1,6 @@ +! exit2 +interface r3-eth0 + ip address 192.168.254.2/30 +! +ip forwarding +! diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py new file mode 100644 index 0000000000..708464864a --- /dev/null +++ b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python + +# +# test_bgp_sender-as-path-loop-detection.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2019 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if neighbor <neighbor> sender-as-path-loop-detection +command works as expeced. +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 4): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + + switch = tgen.add_switch('s2') + switch.add_link(tgen.gears['r2']) + switch.add_link(tgen.gears['r3']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + + tgen.start_router() + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + +def test_bgp_sender_as_path_loop_detection(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears['r2'] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json")) + expected = { + '192.168.255.2': { + 'bgpState': 'Established', + 'addressFamilyInfo': { + 'ipv4Unicast': { + 'acceptedPrefixCounter': 2 + } + } + } + } + return topotest.json_cmp(output, expected) + + def _bgp_has_route_from_r1(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.254/32 json")) + expected = { + 'paths': [ + { + 'aspath': { + 'segments': [ + { + 'type': 'as-sequence', + 'list': [ + 65001, + 65003 + ] + } + ], + 'length': 2 + } + } + ] + } + return topotest.json_cmp(output, expected) + + def _bgp_suppress_route_to_r3(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.254.2 advertised-routes json")) + expected = { + 'totalPrefixCounter': 0 + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed bgp convergence in "{}"'.format(router) + + test_func = functools.partial(_bgp_has_route_from_r1, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed to see a route from r1 in "{}"'.format(router) + + test_func = functools.partial(_bgp_suppress_route_to_r3, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Route 172.16.255.254/32 should not be sent to r3 "{}"'.format(router) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ldp-vpls-topo1/r1/zebra.conf b/tests/topotests/ldp-vpls-topo1/r1/zebra.conf index edfa1780a9..ea047355ad 100644 --- a/tests/topotests/ldp-vpls-topo1/r1/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r1/zebra.conf @@ -14,17 +14,14 @@ interface lo ! interface r1-eth0 description to s1 - no link-detect ! interface r1-eth1 description to s4 ip address 10.0.1.1/24 - no link-detect ! interface r1-eth2 description to s5 ip address 10.0.2.1/24 - no link-detect ! ip forwarding ! diff --git a/tests/topotests/ldp-vpls-topo1/r2/zebra.conf b/tests/topotests/ldp-vpls-topo1/r2/zebra.conf index 6b95efdce8..c244442876 100644 --- a/tests/topotests/ldp-vpls-topo1/r2/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r2/zebra.conf @@ -13,17 +13,14 @@ interface lo ! interface r2-eth0 description to s2 - no link-detect ! interface r2-eth1 description to s4 ip address 10.0.1.2/24 - no link-detect ! interface r2-eth2 description to s6 ip address 10.0.3.2/24 - no link-detect ! ip forwarding ! diff --git a/tests/topotests/ldp-vpls-topo1/r3/zebra.conf b/tests/topotests/ldp-vpls-topo1/r3/zebra.conf index 85ec68ff32..6b1eaa2ca0 100644 --- a/tests/topotests/ldp-vpls-topo1/r3/zebra.conf +++ b/tests/topotests/ldp-vpls-topo1/r3/zebra.conf @@ -13,17 +13,14 @@ interface lo ! interface r3-eth0 description to s3 - no link-detect ! interface r3-eth1 description to s5 ip address 10.0.2.3/24 - no link-detect ! interface r3-eth2 description to s6 ip address 10.0.3.3/24 - no link-detect ! ip forwarding ! diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py index ce651c50cd..0fae64402a 100755 --- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py @@ -257,6 +257,7 @@ def test_ldp_pseudowires_after_link_down(): # Shut down r1-r2 link */ tgen = get_topogen() tgen.gears['r1'].peer_link_enable('r1-eth1', False) + topotest.sleep(5, "Waiting for the network to reconverge") # check if the pseudowire is still up (using an alternate path for nexthop resolution) for rname in ['r1', 'r2', 'r3']: diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 7ec584bf5f..a8354f4c77 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -112,6 +112,8 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False): input_dict = deepcopy(topo) else: topo = topo["routers"] + input_dict = deepcopy(input_dict) + for router in input_dict.keys(): if "bgp" not in input_dict[router]: logger.debug("Router %s: 'bgp' not present in input_dict", router) @@ -220,7 +222,7 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, logger.debug("Entering lib API: __create_bgp_unicast_neighbor()") add_neigh = True - if "router bgp "in config_data: + if "router bgp" in config_data: add_neigh = False bgp_data = input_dict[router]["bgp"]["address_family"] @@ -1366,7 +1368,7 @@ def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name, logger.debug("Exiting lib API: verify_bgp_attributes()") return True -@retry(attempts=3, wait=2, return_is_str=True) +@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2) def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, attribute): """ @@ -1422,16 +1424,14 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, rnode = tgen.routers()[router] - # TODO get addr_type from address - # Verifying show bgp json command = "show bgp {} json".format(addr_type) - sleep(2) + sleep(5) logger.info("Verifying router %s RIB for best path:", router) sh_ip_bgp_json = run_frr_cmd(rnode, command, isjson=True) for route_val in input_dict.values(): - net_data = route_val["bgp"]["address_family"]["ipv4"]["unicast"] + net_data = route_val["bgp"]["address_family"][addr_type]["unicast"] networks = net_data["advertise_networks"] for network in networks: route = network["network"] @@ -1503,8 +1503,8 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, if route in rib_routes_json: st_found = True # Verify next_hop in rib_routes_json - if rib_routes_json[route][0]["nexthops"][0]["ip"] == \ - _next_hop: + if rib_routes_json[route][0]["nexthops"][0]["ip"] in \ + attribute_dict: nh_found = True else: errormsg = "Incorrect Nexthop for BGP route {} in " \ @@ -1526,7 +1526,6 @@ def verify_best_path_as_per_bgp_attribute(tgen, addr_type, router, input_dict, return True -@retry(attempts=3, wait=2, return_is_str=True) def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict, attribute): """ @@ -1568,7 +1567,7 @@ def verify_best_path_as_per_admin_distance(tgen, addr_type, router, input_dict, rnode = tgen.routers()[router] - sleep(2) + sleep(5) logger.info("Verifying router %s RIB for best path:", router) # Show ip route cmd diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 38b97cba2d..9f2fef52ea 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1202,6 +1202,7 @@ def create_route_maps(tgen, input_dict, build=False): "large_comm_list", {}) set_action = set_data.setdefault("set_action", None) nexthop = set_data.setdefault("nexthop", None) + origin = set_data.setdefault("origin", None) # Local Preference if local_preference: @@ -1212,6 +1213,10 @@ def create_route_maps(tgen, input_dict, build=False): if metric: rmap_data.append("set metric {} \n".format(metric)) + # Origin + if origin: + rmap_data.append("set origin {} \n".format(origin)) + # AS Path Prepend if as_path: as_num = as_path.setdefault("as_num", None) @@ -1628,9 +1633,10 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): static_routes = input_dict[routerInput]["static_routes"] st_found = False nh_found = False - found_routes = [] - missing_routes = [] for static_route in static_routes: + found_routes = [] + missing_routes = [] + network = static_route["network"] if "no_of_ip" in static_route: no_of_ip = static_route["no_of_ip"] @@ -1667,6 +1673,7 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): return errormsg else: missing_routes.append(st_rt) + if nh_found: logger.info("Found next_hop %s for all routes in RIB of" " router %s\n", next_hop, dut) @@ -1679,37 +1686,69 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None): logger.info("Verified routes in router %s RIB, found routes" " are: %s\n", dut, found_routes) - advertise_network = input_dict[routerInput].setdefault( - "advertise_networks", {}) - if advertise_network: - found_routes = [] - missing_routes = [] - found = False - for advertise_network_dict in advertise_network: - start_ip = advertise_network_dict["network"] - if "no_of_network" in advertise_network_dict: - no_of_network = advertise_network_dict["no_of_network"] - else: - no_of_network = 0 + continue - # Generating IPs for verification - ip_list = generate_ips(start_ip, no_of_network) - for st_rt in ip_list: - st_rt = str(ipaddr.IPNetwork(unicode(st_rt))) + if "bgp" in input_dict[routerInput]: + if 'advertise_networks' in input_dict[routerInput]["bgp"]\ + ["address_family"][addr_type]["unicast"]: - if st_rt in rib_routes_json: - found = True - found_routes.append(st_rt) + found_routes = [] + missing_routes = [] + advertise_network = input_dict[routerInput]["bgp"]\ + ["address_family"][addr_type]["unicast"]\ + ["advertise_networks"] + + for advertise_network_dict in advertise_network: + start_ip = advertise_network_dict["network"] + if "no_of_network" in advertise_network_dict: + no_of_network = advertise_network_dict["no_of_network"] else: - missing_routes.append(st_rt) + no_of_network = 1 + + # Generating IPs for verification + ip_list = generate_ips(start_ip, no_of_network) + for st_rt in ip_list: + st_rt = str(ipaddr.IPNetwork(unicode(st_rt))) + + found = False + nh_found = False + if st_rt in rib_routes_json: + found = True + found_routes.append(st_rt) + + if next_hop: + if type(next_hop) is not list: + next_hop = [next_hop] + + for index, nh in enumerate(next_hop): + if rib_routes_json[st_rt][0]\ + ['nexthops'][index]['ip'] == nh: + nh_found = True + else: + errormsg=("Nexthop {} is Missing" + " for {} route {} in " + "RIB of router {}\n".\ + format(next_hop, + protocol, + st_rt, dut)) + return errormsg - if not found and len(missing_routes) > 0: - errormsg = "Missing route in RIB of router {}, are: {}" \ - " \n".format(dut, missing_routes) - return errormsg + else: + missing_routes.append(st_rt) - logger.info("Verified routes in router %s RIB, found routes" - " are: %s", dut, found_routes) + if nh_found: + logger.info("Found next_hop {} for all routes in RIB" + " of router {}\n".format(next_hop, dut)) + + if not found and len(missing_routes) > 0: + errormsg = ("Missing {} route in RIB of router {}, " + "routes: {} \n".\ + format(addr_type, dut, missing_routes)) + return errormsg + + logger.info("Verified {} routes in router {} RIB, found" + " routes are: {}\n".\ + format(addr_type, dut, found_routes)) logger.debug("Exiting lib API: verify_rib()") return True diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index d7145c3be0..6859f5a076 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -61,6 +61,7 @@ from mininet.cli import CLI from lib import topotest from lib.topolog import logger, logger_config +from lib.topotest import set_sysctl CWD = os.path.dirname(os.path.realpath(__file__)) @@ -676,6 +677,10 @@ class TopoRouter(TopoGear): if result != '': self.tgen.set_error(result) + else: + # Enable MPLS processing on all interfaces. + for interface in self.links.keys(): + set_sysctl(nrouter, 'net.mpls.conf.{}.input'.format(interface), 1) return result diff --git a/tools/frr-reload.py b/tools/frr-reload.py index cc383e06d8..412cde0910 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -776,9 +776,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if re_nbr_bfd_timers: nbr = re_nbr_bfd_timers.group(1) bfd_nbr = "neighbor %s" % nbr + bfd_search_string = bfd_nbr + r' bfd (\S+) (\S+) (\S+)' for (ctx_keys, add_line) in lines_to_add: - re_add_nbr_bfd_timers = re.search(r'neighbor (\S+) bfd (\S+) (\S+) (\S+)', add_line) + re_add_nbr_bfd_timers = re.search(bfd_search_string, add_line) if re_add_nbr_bfd_timers: found_add_bfd_nbr = line_exist(lines_to_add, ctx_keys, bfd_nbr, False) 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/tools/tarsource.sh b/tools/tarsource.sh index eee2a9739b..4843fe88b0 100755 --- a/tools/tarsource.sh +++ b/tools/tarsource.sh @@ -301,6 +301,11 @@ if $debian; then --format='3.0 (custom)' --target-format='3.0 (quilt)' \ -b . frr_${PACKAGE_VERSION}.orig.tar.$zip frr_${DEBVER}.debian.tar.$zip + dpkg-genchanges -sa -S > ../frr_${DEBVER}_source.changes + + test -n "$keyid" && debsign ../frr_${DEBVER}_source.changes -k"$keyid" + + mv ../frr_${DEBVER}_source.changes "$outdir" || true mv ../frr_${DEBVER}.dsc "$outdir" || true mv ../frr_${DEBVER}.debian.tar.$zip "$outdir" || true if test -h ../frr_${PACKAGE_VERSION}.orig.tar.$zip; then @@ -309,12 +314,12 @@ if $debian; then ln -s frr-${PACKAGE_VERSION}.tar.$zip "$outdir/frr_${PACKAGE_VERSION}.orig.tar.$zip" || true cd "$outdir" - test -n "$keyid" && debsign -k "$keyid" "frr_${DEBVER}.dsc" lsfiles="$lsfiles \ frr_${DEBVER}.dsc \ frr_${DEBVER}.debian.tar.$zip \ - frr_${PACKAGE_VERSION}.orig.tar.$zip" + frr_${PACKAGE_VERSION}.orig.tar.$zip \ + frr_${DEBVER}_source.changes" fi cd "$outdir" 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/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index d536263db0..c7e1d252c7 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -535,6 +535,9 @@ int main(int argc, char **argv, char **env) /* Do not connect until we have passed authentication. */ if (vtysh_connect_all(daemon_name) <= 0) { fprintf(stderr, "Exiting: failed to connect to any daemons.\n"); + if (geteuid() != 0) + fprintf(stderr, + "Hint: if this seems wrong, try running me as a privileged user!\n"); if (no_error) exit(0); else diff --git a/vtysh/vtysh_user.c b/vtysh/vtysh_user.c index 17e5a7331c..a7067984c4 100644 --- a/vtysh/vtysh_user.c +++ b/vtysh/vtysh_user.c @@ -147,6 +147,26 @@ DEFUN (vtysh_banner_motd_file, return cmd_banner_motd_file(argv[idx_file]->arg); } +DEFUN (vtysh_banner_motd_line, + vtysh_banner_motd_line_cmd, + "banner motd line LINE...", + "Set banner\n" + "Banner for motd\n" + "Banner from an input\n" + "Text\n") +{ + int idx = 0; + char *motd; + + argv_find(argv, argc, "LINE", &idx); + motd = argv_concat(argv, argc, idx); + + cmd_banner_motd_line(motd); + XFREE(MTYPE_TMP, motd); + + return CMD_SUCCESS; +} + DEFUN (username_nopassword, username_nopassword_cmd, "username WORD nopassword", @@ -203,4 +223,5 @@ void vtysh_user_init(void) userlist = list_new(); install_element(CONFIG_NODE, &username_nopassword_cmd); install_element(CONFIG_NODE, &vtysh_banner_motd_file_cmd); + install_element(CONFIG_NODE, &vtysh_banner_motd_line_cmd); } diff --git a/zebra/connected.c b/zebra/connected.c index 75f4f53bc6..0ff474d787 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -65,7 +65,7 @@ static void connected_withdraw(struct connected *ifc) if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED)) { listnode_delete(ifc->ifp->connected, ifc); - connected_free(ifc); + connected_free(&ifc); } } @@ -177,7 +177,7 @@ static void connected_update(struct interface *ifp, struct connected *ifc) */ if (connected_same(current, ifc)) { /* nothing to do */ - connected_free(ifc); + connected_free(&ifc); return; } diff --git a/zebra/interface.c b/zebra/interface.c index daa93e36d1..eea80652e5 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -738,7 +738,7 @@ static void if_delete_connected(struct interface *ifp) ZEBRA_IFC_CONFIGURED)) { listnode_delete(ifp->connected, ifc); - connected_free(ifc); + connected_free(&ifc); } else last = node; } @@ -759,7 +759,7 @@ static void if_delete_connected(struct interface *ifp) last = node; else { listnode_delete(ifp->connected, ifc); - connected_free(ifc); + connected_free(&ifc); } } else { last = node; @@ -829,7 +829,7 @@ void if_delete_update(struct interface *ifp) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("interface %s is being deleted from the system", ifp->name); - if_delete(ifp); + if_delete(&ifp); } } @@ -2878,7 +2878,7 @@ static int ip_address_uninstall(struct vty *vty, struct interface *ifp, if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { listnode_delete(ifp->connected, ifc); - connected_free(ifc); + connected_free(&ifc); return CMD_WARNING_CONFIG_FAILED; } @@ -3103,7 +3103,7 @@ static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp, if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_QUEUED) || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { listnode_delete(ifp->connected, ifc); - connected_free(ifc); + connected_free(&ifc); return CMD_WARNING_CONFIG_FAILED; } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 4e0163f8ac..98603c9693 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -718,8 +718,8 @@ int zebra_import_table(afi_t afi, vrf_id_t vrf_id, uint32_t table_id, if (afi >= AFI_MAX) return (-1); - table = zebra_vrf_table_with_table_id(afi, SAFI_UNICAST, vrf_id, - table_id); + table = zebra_vrf_get_table_with_table_id(afi, SAFI_UNICAST, vrf_id, + table_id); if (table == NULL) { return 0; } else if (IS_ZEBRA_DEBUG_RIB) { @@ -830,8 +830,8 @@ static void zebra_import_table_rm_update_vrf_afi(struct zebra_vrf *zvrf, if ((!rmap_name) || (strcmp(rmap_name, rmap) != 0)) return; - table = zebra_vrf_table_with_table_id(afi, SAFI_UNICAST, - zvrf->vrf->vrf_id, table_id); + table = zebra_vrf_get_table_with_table_id(afi, SAFI_UNICAST, + zvrf->vrf->vrf_id, table_id); if (!table) { if (IS_ZEBRA_DEBUG_RIB_DETAILED) zlog_debug("%s: Table id=%d not found", __func__, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 640802fe31..c9a9a81b18 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, @@ -2451,7 +2456,6 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; } -#if 0 /* Force off kernel nexthop group installs for now */ /** * netlink_request_nexthop() - Request nextop information from the kernel * @zns: Zebra namespace @@ -2510,12 +2514,6 @@ int netlink_nexthop_read(struct zebra_ns *zns) return ret; } -#else -int netlink_nexthop_read(struct zebra_ns *zns) -{ - return 0; -} -#endif int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, diff --git a/zebra/sample_plugin.c b/zebra/sample_plugin.c new file mode 100644 index 0000000000..c96a86cc73 --- /dev/null +++ b/zebra/sample_plugin.c @@ -0,0 +1,134 @@ +/* + * Sample plugin for the FRR zebra dataplane. + * + * Copyright (c) 2019 Volta Networks, Inc. + * + * 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 + */ + +/* + * Should be possible to build this plugin using this sort of command: + * + * gcc -I ~/work/frr/ -I ~/work/frr/lib -I ~/work/frr/zebra \ + * -g -O0 -o sample_plugin.so -shared -fPIC sample_plugin.c + * + * where 'frr' is a configured and built frr sandbox. + * + * Run zebra with '-M /path/to/sample_plugin.so' to load the module. + */ + +#include "config.h" /* Include this explicitly */ +#include "lib/zebra.h" +#include "lib/libfrr.h" +#include "zebra/zebra_dplane.h" +#include "zebra/debug.h" + +static const char *plugin_name = "SAMPLE"; + +static struct zebra_dplane_provider *prov_p; + +/* + * Startup/init callback, called from the dataplane. + */ +static int sample_start(struct zebra_dplane_provider *prov) +{ + /* Nothing special to do - we don't allocate anything. */ + return 0; +} + + +/* + * Shutdown/cleanup callback, called from the dataplane pthread. + */ +static int sample_fini(struct zebra_dplane_provider *prov, bool early) +{ + /* Nothing special to do. */ + return 0; +} + +/* + * Callback from the dataplane to process incoming work; this runs in the + * dplane pthread. + */ +static int sample_process(struct zebra_dplane_provider *prov) +{ + int counter, limit; + struct zebra_dplane_ctx *ctx; + + limit = dplane_provider_get_work_limit(prov_p); + + /* Respect the configured limit on the amount of work to do in + * any one call. + */ + for (counter = 0; counter < limit; counter++) { + ctx = dplane_provider_dequeue_in_ctx(prov_p); + if (!ctx) + break; + + /* Just set 'success' status and return to the dataplane */ + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); + dplane_provider_enqueue_out_ctx(prov_p, ctx); + } + + return 0; +} + +/* + * Init entry point called during zebra startup. This is registered during + * module init. + */ +static int init_sample_plugin(struct thread_master *tm) +{ + int ret; + struct zebra_dplane_provider *prov = NULL; + + /* Note that we don't use or store the thread_master 'tm'. We + * don't use the zebra main pthread: our plugin code will run in + * the zebra dataplane pthread context. + */ + + /* Register the plugin with the dataplane infrastructure. We + * register to be called before the kernel, and we register + * our init, process work, and shutdown callbacks. + */ + ret = dplane_provider_register(plugin_name, DPLANE_PRIO_PRE_KERNEL, + DPLANE_PROV_FLAGS_DEFAULT, + sample_start, + sample_process, + sample_fini, + NULL, + &prov_p); + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("sample plugin register => %d", ret); + + return 0; +} + +/* + * Base FRR loadable module info: basic info including module entry-point. + */ +static int module_init(void) +{ + hook_register(frr_late_init, init_sample_plugin); + return 0; +} + +FRR_MODULE_SETUP( + .name = "dplane_sample", + .version = "0.0.1", + .description = "Dataplane Sample Plugin", + .init = module_init, + ) diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index a88b0a38da..7f993442a6 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -3752,7 +3752,9 @@ void zebra_dplane_shutdown(void) zdplane_info.dg_run = false; - THREAD_OFF(zdplane_info.dg_t_update); + if (zdplane_info.dg_t_update) + thread_cancel_async(zdplane_info.dg_t_update->master, + &zdplane_info.dg_t_update, NULL); frr_pthread_stop(zdplane_info.dg_pthread, NULL); diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 5d88d4eeb4..fa48c03c71 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -498,6 +498,11 @@ static inline void zfpm_write_off(void) THREAD_WRITE_OFF(zfpm_g->t_write); } +static inline void zfpm_connect_off(void) +{ + THREAD_TIMER_OFF(zfpm_g->t_connect); +} + /* * zfpm_conn_up_thread_cb * @@ -731,7 +736,6 @@ static int zfpm_read_cb(struct thread *thread) fpm_msg_hdr_t *hdr; zfpm_g->stats.read_cb_calls++; - zfpm_g->t_read = NULL; /* * Check if async connect is now done. @@ -1157,7 +1161,6 @@ static int zfpm_write_cb(struct thread *thread) int num_writes; zfpm_g->stats.write_cb_calls++; - zfpm_g->t_write = NULL; /* * Check if async connect is now done. @@ -1241,7 +1244,6 @@ static int zfpm_connect_cb(struct thread *t) int sock, ret; struct sockaddr_in serv; - zfpm_g->t_connect = NULL; assert(zfpm_g->state == ZFPM_STATE_ACTIVE); sock = socket(AF_INET, SOCK_STREAM, 0); @@ -2029,11 +2031,24 @@ static int zfpm_init(struct thread_master *master) return 0; } +static int zfpm_fini(void) +{ + zfpm_write_off(); + zfpm_read_off(); + zfpm_connect_off(); + + zfpm_stop_stats_timer(); + + hook_unregister(rib_update, zfpm_trigger_update); + return 0; +} + static int zebra_fpm_module_init(void) { hook_register(rib_update, zfpm_trigger_update); hook_register(zebra_rmac_update, zfpm_trigger_rmac_update); hook_register(frr_late_init, zfpm_init); + hook_register(frr_early_fini, zfpm_fini); return 0; } diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index ef1bd02608..6942a37989 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -2565,6 +2565,16 @@ void zebra_mpls_print_fec(struct vty *vty, struct zebra_vrf *zvrf, fec_print(rn->info, vty); } +static void mpls_zebra_nhg_update(struct route_entry *re, afi_t afi, + struct nexthop_group *new_grp) +{ + struct nhg_hash_entry *nhe; + + nhe = zebra_nhg_rib_find(0, new_grp, afi); + + zebra_nhg_re_update_ref(re, nhe); +} + static bool mpls_ftn_update_nexthop(int add, struct nexthop *nexthop, enum lsp_types_t type, mpls_label_t label) { @@ -2591,7 +2601,6 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, struct route_entry *re; struct nexthop *nexthop; struct nexthop_group new_grp = {}; - struct nhg_hash_entry *nhe = NULL; bool found; afi_t afi = family2afi(prefix->family); @@ -2658,12 +2667,11 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, } if (found) { - nhe = zebra_nhg_rib_find(0, &new_grp, afi); - - zebra_nhg_re_update_ref(re, nhe); - SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + + mpls_zebra_nhg_update(re, afi, &new_grp); + rib_queue_add(rn); } @@ -2680,10 +2688,11 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, struct route_node *rn; struct route_entry *re; struct nexthop *nexthop; + struct nexthop_group new_grp = {}; + afi_t afi = family2afi(prefix->family); /* Lookup table. */ - table = zebra_vrf_table(family2afi(prefix->family), SAFI_UNICAST, - zvrf_id(zvrf)); + table = zebra_vrf_table(afi, SAFI_UNICAST, zvrf_id(zvrf)); if (!table) return -1; @@ -2698,11 +2707,18 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, if (re == NULL) return -1; - for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) + nexthop_group_copy(&new_grp, re->ng); + + for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) nexthop_del_labels(nexthop); SET_FLAG(re->status, ROUTE_ENTRY_CHANGED); SET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); + + mpls_zebra_nhg_update(re, afi, &new_grp); + + nexthops_free(new_grp.nexthop); + rib_queue_add(rn); return 0; @@ -2904,7 +2920,6 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, update = 0; RNODE_FOREACH_RE (rn, re) { struct nexthop_group new_grp = {}; - struct nhg_hash_entry *nhe = NULL; nexthop_group_copy(&new_grp, re->ng); @@ -2920,11 +2935,8 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, update = 1; } - if (CHECK_FLAG(re->status, - ROUTE_ENTRY_LABELS_CHANGED)) { - nhe = zebra_nhg_rib_find(0, &new_grp, afi); - zebra_nhg_re_update_ref(re, nhe); - } + if (CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) + mpls_zebra_nhg_update(re, afi, &new_grp); nexthops_free(new_grp.nexthop); } diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 2bb117b272..2d7521d8be 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -360,6 +360,8 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) { const struct nhg_hash_entry *nhe1 = arg1; const struct nhg_hash_entry *nhe2 = arg2; + struct nexthop *nexthop1; + struct nexthop *nexthop2; /* No matter what if they equal IDs, assume equal */ if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id)) @@ -371,12 +373,47 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) if (nhe1->afi != nhe2->afi) return false; - if (nexthop_group_active_nexthop_num_no_recurse(nhe1->nhg) - != nexthop_group_active_nexthop_num_no_recurse(nhe2->nhg)) - return false; + /* Nexthops should be sorted */ + for (nexthop1 = nhe1->nhg->nexthop, nexthop2 = nhe2->nhg->nexthop; + nexthop1 || nexthop2; + nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) { + if (nexthop1 && !nexthop2) + return false; - if (!nexthop_group_equal_no_recurse(nhe1->nhg, nhe2->nhg)) - return false; + if (!nexthop1 && nexthop2) + return false; + + /* + * We have to check the active flag of each individual one, + * not just the overall active_num. This solves the special case + * issue of a route with a nexthop group with one nexthop + * resolving to itself and thus marking it inactive. If we + * have two different routes each wanting to mark a different + * nexthop inactive, they need to hash to two different groups. + * + * If we just hashed on num_active, they would hash the same + * which is incorrect. + * + * ex) + * 1.1.1.0/24 + * -> 1.1.1.1 dummy1 (inactive) + * -> 1.1.2.1 dummy2 + * + * 1.1.2.0/24 + * -> 1.1.1.1 dummy1 + * -> 1.1.2.1 dummy2 (inactive) + * + * Without checking each individual one, they would hash to + * the same group and both have 1.1.1.1 dummy1 marked inactive. + * + */ + if (CHECK_FLAG(nexthop1->flags, NEXTHOP_FLAG_ACTIVE) + != CHECK_FLAG(nexthop2->flags, NEXTHOP_FLAG_ACTIVE)) + return false; + + if (!nexthop_same(nexthop1, nexthop2)) + return false; + } return true; } @@ -552,20 +589,6 @@ zebra_nhg_find_nexthop(uint32_t id, struct nexthop *nh, afi_t afi, int type) return nhe; } -static struct nhg_ctx *nhg_ctx_new() -{ - struct nhg_ctx *new = NULL; - - new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx)); - - return new; -} - -static void nhg_ctx_free(struct nhg_ctx *ctx) -{ - XFREE(MTYPE_NHG_CTX, ctx); -} - static uint32_t nhg_ctx_get_id(const struct nhg_ctx *ctx) { return ctx->id; @@ -621,6 +644,36 @@ static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx) return ctx->u.grp; } +static struct nhg_ctx *nhg_ctx_new() +{ + struct nhg_ctx *new = NULL; + + new = XCALLOC(MTYPE_NHG_CTX, sizeof(struct nhg_ctx)); + + return new; +} + +static void nhg_ctx_free(struct nhg_ctx **ctx) +{ + struct nexthop *nh; + + if (ctx == NULL) + return; + + assert((*ctx) != NULL); + + if (nhg_ctx_get_count(*ctx)) + goto done; + + nh = nhg_ctx_get_nh(*ctx); + + nexthop_del_labels(nh); + +done: + XFREE(MTYPE_NHG_CTX, *ctx); + *ctx = NULL; +} + static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, struct nh_grp *grp, vrf_id_t vrf_id, afi_t afi, int type, uint8_t count) @@ -869,25 +922,14 @@ static int nhg_ctx_process_del(struct nhg_ctx *ctx) return 0; } -static void nhg_ctx_process_finish(struct nhg_ctx *ctx) +static void nhg_ctx_fini(struct nhg_ctx **ctx) { - struct nexthop *nh; - /* * Just freeing for now, maybe do something more in the future * based on flag. */ - if (nhg_ctx_get_count(ctx)) - goto done; - - nh = nhg_ctx_get_nh(ctx); - - nexthop_del_labels(nh); - -done: - if (ctx) - nhg_ctx_free(ctx); + nhg_ctx_free(ctx); } static int queue_add(struct nhg_ctx *ctx) @@ -942,7 +984,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx) nhg_ctx_set_status(ctx, (ret ? NHG_CTX_FAILURE : NHG_CTX_SUCCESS)); - nhg_ctx_process_finish(ctx); + nhg_ctx_fini(&ctx); return ret; } @@ -971,7 +1013,7 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, return nhg_ctx_process(ctx); if (queue_add(ctx)) { - nhg_ctx_process_finish(ctx); + nhg_ctx_fini(&ctx); return -1; } @@ -988,7 +1030,7 @@ int zebra_nhg_kernel_del(uint32_t id) nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL); if (queue_add(ctx)) { - nhg_ctx_process_finish(ctx); + nhg_ctx_fini(&ctx); return -1; } @@ -1001,6 +1043,9 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) struct nexthop *lookup = NULL; struct nhg_hash_entry *nhe = NULL; + if (!nh) + goto done; + copy_nexthops(&lookup, nh, NULL); /* Clear it, in case its a group */ @@ -1013,6 +1058,7 @@ static struct nhg_hash_entry *depends_find(struct nexthop *nh, afi_t afi) nexthops_free(lookup); +done: return nhe; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index e0bf1a58f2..781963793e 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -570,14 +570,6 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, nexthops_free(old->fib_ng.nexthop); old->fib_ng.nexthop = NULL; } - - if (!RIB_SYSTEM_ROUTE(old)) { - /* Clear old route's FIB flags */ - for (ALL_NEXTHOPS_PTR(old->ng, nexthop)) { - UNSET_FLAG(nexthop->flags, - NEXTHOP_FLAG_FIB); - } - } } if (zvrf) @@ -1575,10 +1567,9 @@ rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx) /* Locate rn and re(s) from ctx */ - table = zebra_vrf_table_with_table_id(dplane_ctx_get_afi(ctx), - dplane_ctx_get_safi(ctx), - dplane_ctx_get_vrf(ctx), - dplane_ctx_get_table(ctx)); + table = zebra_vrf_lookup_table_with_table_id( + dplane_ctx_get_afi(ctx), dplane_ctx_get_safi(ctx), + dplane_ctx_get_vrf(ctx), dplane_ctx_get_table(ctx)); if (table == NULL) { if (IS_ZEBRA_DEBUG_DPLANE) { zlog_debug("Failed to find route for ctx: no table for afi %d, safi %d, vrf %u", @@ -2664,7 +2655,8 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); /* Lookup table. */ - table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); + table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id, + re->table); if (!table) { if (re->ng) nexthop_group_delete(&re->ng); @@ -2809,7 +2801,8 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); /* Lookup table. */ - table = zebra_vrf_table_with_table_id(afi, safi, vrf_id, table_id); + table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id, + table_id); if (!table) return; diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index f425c0e49e..c392303760 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -343,13 +343,12 @@ int zebra_vrf_has_config(struct zebra_vrf *zvrf) * - case VRF backend is default : on default VRF only * - case VRF backend is netns : on all VRFs */ -struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, - vrf_id_t vrf_id, - uint32_t table_id) +struct route_table *zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi, + vrf_id_t vrf_id, + uint32_t table_id) { struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); struct other_route_table ort, *otable; - struct route_table *table; if (!zvrf) return NULL; @@ -364,9 +363,28 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, ort.safi = safi; ort.table_id = table_id; otable = otable_find(&zvrf->other_tables, &ort); + if (otable) return otable->table; + return NULL; +} + +struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, safi_t safi, + vrf_id_t vrf_id, + uint32_t table_id) +{ + struct zebra_vrf *zvrf = vrf_info_lookup(vrf_id); + struct other_route_table *otable; + struct route_table *table; + + table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id, + table_id); + + if (table) + goto done; + + /* Create it as an `other` table */ table = zebra_router_get_table(zvrf, table_id, afi, safi); otable = XCALLOC(MTYPE_OTHER_TABLE, sizeof(*otable)); @@ -376,6 +394,7 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, otable->table = table; otable_add(&zvrf->other_tables, otable); +done: return table; } diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 6c80f9bcb4..5448e17073 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -233,9 +233,13 @@ zvrf_other_table_compare_func(const struct other_route_table *a, DECLARE_RBTREE_UNIQ(otable, struct other_route_table, next, zvrf_other_table_compare_func) -struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi, - vrf_id_t vrf_id, - uint32_t table_id); +extern struct route_table * +zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi, vrf_id_t vrf_id, + uint32_t table_id); +extern struct route_table *zebra_vrf_get_table_with_table_id(afi_t afi, + safi_t safi, + vrf_id_t vrf_id, + uint32_t table_id); extern void zebra_vrf_update_all(struct zserv *client); extern struct zebra_vrf *zebra_vrf_lookup_by_id(vrf_id_t vrf_id); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 9d17454730..12517f3135 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1708,10 +1708,9 @@ DEFPY (show_route_summary, if ((zvrf = vrf->info) == NULL) continue; - table = zebra_vrf_table_with_table_id(afi, - SAFI_UNICAST, - zvrf->vrf->vrf_id, - table_id); + table = zebra_vrf_lookup_table_with_table_id( + afi, SAFI_UNICAST, zvrf->vrf->vrf_id, table_id); + if (!table) continue; @@ -1726,9 +1725,8 @@ DEFPY (show_route_summary, if (vrf_name) VRF_GET_ID(vrf_id, vrf_name, false); - table = zebra_vrf_table_with_table_id(afi, - SAFI_UNICAST, - vrf_id, table_id); + table = zebra_vrf_lookup_table_with_table_id(afi, SAFI_UNICAST, + vrf_id, table_id); if (!table) return CMD_SUCCESS; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 2417b505ad..3efb407fae 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -4615,18 +4615,21 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, { char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; + char buf2[PREFIX_STRLEN]; zebra_mac_t *zrmac = NULL; zrmac = zl3vni_rmac_lookup(zl3vni, rmac); if (!zrmac) { + /* Create the RMAC entry, or update its vtep, if necessary. */ zrmac = zl3vni_rmac_add(zl3vni, rmac); if (!zrmac) { zlog_debug( - "Failed to add RMAC %s L3VNI %u Remote VTEP %s", + "Failed to add RMAC %s L3VNI %u Remote VTEP %s, prefix %s", prefix_mac2str(rmac, buf, sizeof(buf)), zl3vni->vni, - ipaddr2str(vtep_ip, buf1, sizeof(buf1))); + ipaddr2str(vtep_ip, buf1, sizeof(buf1)), + prefix2str(host_prefix, buf2, sizeof(buf2))); return -1; } memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); @@ -4638,6 +4641,21 @@ static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac, /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); + } else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, + &vtep_ip->ipaddr_v4)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "L3VNI %u Remote VTEP change(%s -> %s) for RMAC %s, prefix %s", + zl3vni->vni, + inet_ntoa(zrmac->fwd_info.r_vtep_ip), + ipaddr2str(vtep_ip, buf1, sizeof(buf1)), + prefix_mac2str(rmac, buf, sizeof(buf)), + prefix2str(host_prefix, buf2, sizeof(buf2))); + + zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + + /* install rmac in kernel */ + zl3vni_rmac_install(zl3vni, zrmac); } rb_find_or_add_host(&zrmac->host_rb, host_prefix); @@ -4786,24 +4804,39 @@ static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip, struct prefix *host_prefix) { char buf[ETHER_ADDR_STRLEN]; - char buf1[INET6_ADDRSTRLEN]; + char buf1[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + char buf3[PREFIX_STRLEN]; zebra_neigh_t *nh = NULL; + /* Create the next hop entry, or update its mac, if necessary. */ nh = zl3vni_nh_lookup(zl3vni, vtep_ip); if (!nh) { nh = zl3vni_nh_add(zl3vni, vtep_ip, rmac); if (!nh) { - zlog_debug( - "Failed to add NH as Neigh (IP %s MAC %s L3-VNI %u)", - ipaddr2str(vtep_ip, buf1, sizeof(buf1)), + "Failed to add NH %s as Neigh (RMAC %s L3-VNI %u prefix %s)", + ipaddr2str(vtep_ip, buf1, sizeof(buf2)), prefix_mac2str(rmac, buf, sizeof(buf)), - zl3vni->vni); + zl3vni->vni, + prefix2str(host_prefix, buf2, sizeof(buf2))); return -1; } /* install the nh neigh in kernel */ zl3vni_nh_install(zl3vni, nh); + } else if (memcmp(&nh->emac, rmac, ETH_ALEN) != 0) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("L3VNI %u RMAC change(%s --> %s) for nexthop %s, prefix %s", + zl3vni->vni, + prefix_mac2str(&nh->emac, buf, sizeof(buf)), + prefix_mac2str(rmac, buf1, sizeof(buf1)), + ipaddr2str(vtep_ip, buf2, sizeof(buf2)), + prefix2str(host_prefix, buf3, sizeof(buf3))); + + memcpy(&nh->emac, rmac, ETH_ALEN); + /* install (update) the nh neigh in kernel */ + zl3vni_nh_install(zl3vni, nh); } rb_find_or_add_host(&nh->host_rb, host_prefix); @@ -5775,12 +5808,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 |
