diff options
605 files changed, 29727 insertions, 8215 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 103ac3a478..837ec75b8d 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -12,3 +12,10 @@ ac4d0be5874fafd14212d6007fff7495edc9b152 d62a17aedeb0eebdba98238874bb13d62c48dbf9 c14777c6bfd0a446c85243d3a9835054a259c276 996c93142d3abfab0f6d6c800474e22a8cfbdbc5 +# require semicolon after macro XYZ +67b0f40c98aeb9bbc95370fe2be29e56a00a8748 +80413c2073a20774b264ab04f7a4ea4515699790 +960b9a53837d1aefa16bd531c7087f800dbe147b +96244aca23adec551c29b78f26605f8af8eea53e +8451921b70044a2c1075e7ba391f095fabee2550 +bf8d3d6aca3f20255a621ed1c148fd05b3a8ae5c diff --git a/.gitignore b/.gitignore index 05ca0b1140..4e120dae85 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,5 @@ refix .vscode .kitchen .emacs.desktop* + +/test-suite.log diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 85d79bdc3b..41391c51ac 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -42,7 +42,7 @@ THE SOFTWARE. #include "xroute.h" #include "babel_errors.h" -DEFINE_MTYPE_STATIC(BABELD, BABEL_IF, "Babel Interface") +DEFINE_MTYPE_STATIC(BABELD, BABEL_IF, "Babel Interface"); #define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0) diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 14e583a35c..71ac356585 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -153,7 +153,7 @@ FRR_DAEMON_INFO(babeld, BABELD, .yang_modules = babeld_yang_modules, .n_yang_modules = array_size(babeld_yang_modules), - ) +); int main(int argc, char **argv) diff --git a/babeld/babeld.c b/babeld/babeld.c index a907daf6c2..72080bd7eb 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -46,8 +46,8 @@ THE SOFTWARE. #include "babel_zebra.h" #include "babel_errors.h" -DEFINE_MGROUP(BABELD, "babeld") -DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure") +DEFINE_MGROUP(BABELD, "babeld"); +DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure"); static int babel_init_routing_process(struct thread *thread); static void babel_get_myid(void); diff --git a/babeld/babeld.h b/babeld/babeld.h index 752cc8620a..4487aae99f 100644 --- a/babeld/babeld.h +++ b/babeld/babeld.h @@ -41,20 +41,6 @@ THE SOFTWARE. #define MAX(x,y) ((x)<=(y)?(y):(x)) #define MIN(x,y) ((x)<=(y)?(x):(y)) -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -/* nothing */ -#elif defined(__GNUC__) -#define inline __inline -#if (__GNUC__ >= 3) -#define restrict __restrict -#else -#define restrict /**/ -#endif -#else -#define inline /**/ -#define restrict /**/ -#endif - #if defined(__GNUC__) && (__GNUC__ >= 3) #define ATTRIBUTE(x) __attribute__ (x) #define LIKELY(_x) __builtin_expect(!!(_x), 1) diff --git a/babeld/util.h b/babeld/util.h index 9310040571..037ebe3666 100644 --- a/babeld/util.h +++ b/babeld/util.h @@ -29,7 +29,7 @@ THE SOFTWARE. #include "log.h" #include "memory.h" -DECLARE_MGROUP(BABELD) +DECLARE_MGROUP(BABELD); #if defined(i386) || defined(__mc68020__) || defined(__x86_64__) #define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0) @@ -129,13 +129,7 @@ extern const unsigned char v4prefix[16]; vararg macros are not portable. */ #if defined NO_DEBUG -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define debugf(...) do {} while(0) -#elif defined __GNUC__ -#define debugf(_args...) do {} while(0) -#else -static inline void debugf(int level, const char *format, ...) { return; } -#endif #else /* NO_DEBUG */ @@ -148,19 +142,10 @@ static inline void debugf(int level, const char *format, ...) { return; } #define BABEL_DEBUG_ROUTE (1 << 5) #define BABEL_DEBUG_ALL (0xFFFF) -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define debugf(level, ...) \ do { \ if(UNLIKELY(debug & level)) zlog_debug(__VA_ARGS__); \ } while(0) -#elif defined __GNUC__ -#define debugf(level, _args...) \ -do { \ -if(UNLIKELY(debug & level)) zlog_debug(_args); \ -} while(0) -#else -static inline void debugf(int level, const char *format, ...) { return; } -#endif #endif /* NO_DEBUG */ diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 9e5bc20a49..18f331e201 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -32,10 +32,10 @@ #include "bfd.h" -DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory") -DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory") -DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer") -DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF") +DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory"); +DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory"); +DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer"); +DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF"); /* * Prototypes @@ -1941,6 +1941,14 @@ void bfd_sessions_remove_manual(void) hash_iterate(bfd_key_hash, _bfd_session_remove_manual, NULL); } +void bfd_profiles_remove(void) +{ + struct bfd_profile *bp; + + while ((bp = TAILQ_FIRST(&bplist)) != NULL) + bfd_profile_free(bp); +} + /* * Profile related hash functions. */ diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 503b5ca7d6..d9d5d8cb5e 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -41,9 +41,9 @@ #define BFDD_JSON_CONV_OPTIONS (0) #endif -DECLARE_MGROUP(BFDD) -DECLARE_MTYPE(BFDD_CONTROL) -DECLARE_MTYPE(BFDD_NOTIFICATION) +DECLARE_MGROUP(BFDD); +DECLARE_MTYPE(BFDD_CONTROL); +DECLARE_MTYPE(BFDD_NOTIFICATION); struct bfd_timers { uint32_t desired_min_tx; @@ -619,6 +619,7 @@ void bfd_session_free(struct bfd_session *bs); const struct bfd_session *bfd_session_next(const struct bfd_session *bs, bool mhop); void bfd_sessions_remove_manual(void); +void bfd_profiles_remove(void); /** * Set the BFD session echo state. diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 0cac990108..7a2c3cc3aa 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -41,9 +41,9 @@ /* * FRR related code. */ -DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon") -DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory") -DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data") +DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon"); +DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory"); +DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data"); /* Master of threads. */ struct thread_master *master; @@ -134,7 +134,8 @@ FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617, .signals = bfd_signals, .n_signals = array_size(bfd_signals), .privs = &bglobal.bfdd_privs, .yang_modules = bfdd_yang_modules, - .n_yang_modules = array_size(bfdd_yang_modules)) + .n_yang_modules = array_size(bfdd_yang_modules), +); #define OPTION_CTLSOCK 1001 #define OPTION_DPLANEADDR 2000 diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index ba80b2363f..42ed587f20 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -557,7 +557,7 @@ void bfd_cli_show_required_echo_receive_interval(struct vty *vty, * Profile commands. */ DEFPY_YANG_NOSH(bfd_profile, bfd_profile_cmd, - "profile WORD$name", + "profile BFDPROF$name", BFD_PROFILE_STR BFD_PROFILE_NAME_STR) { diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c index 26bce4f357..b221b6d539 100644 --- a/bfdd/bfdd_nb_config.c +++ b/bfdd/bfdd_nb_config.c @@ -229,7 +229,15 @@ static int bfd_session_destroy(enum nb_event event, */ int bfdd_bfd_create(struct nb_cb_create_args *args) { - /* NOTHING */ + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* + * Set any non-NULL value to be able to call + * nb_running_unset_entry in bfdd_bfd_destroy. + */ + nb_running_set_entry(args->dnode, (void *)0x1); + return NB_OK; } @@ -245,7 +253,14 @@ int bfdd_bfd_destroy(struct nb_cb_destroy_args *args) return NB_OK; case NB_EV_APPLY: + /* + * We need to call this to unset pointers from + * the child nodes - sessions and profiles. + */ + nb_running_unset_entry(args->dnode); + bfd_sessions_remove_manual(); + bfd_profiles_remove(); break; case NB_EV_ABORT: diff --git a/bfdd/config.c b/bfdd/config.c index a97caf137e..22ec912359 100644 --- a/bfdd/config.c +++ b/bfdd/config.c @@ -30,7 +30,7 @@ #include "bfd.h" -DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory") +DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory"); /* * Definitions diff --git a/bfdd/dplane.c b/bfdd/dplane.c index 9cb0b0ea85..6fb301d46a 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -46,7 +46,8 @@ #include "lib/openbsd-queue.h" -DEFINE_MTYPE_STATIC(BFDD, BFDD_DPLANE_CTX, "Data plane client allocated memory") +DEFINE_MTYPE_STATIC(BFDD, BFDD_DPLANE_CTX, + "Data plane client allocated memory"); /** Data plane client socket buffer size. */ #define BFD_DPLANE_CLIENT_BUF_SIZE 8192 diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 745a0dffce..ef4f626111 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -23,7 +23,7 @@ #include "lib/typesafe.h" -PREDECL_DLIST(bgp_adv_fifo) +PREDECL_DLIST(bgp_adv_fifo); struct update_subgroup; @@ -60,7 +60,7 @@ struct bgp_advertise { struct bgp_path_info *pathi; }; -DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo) +DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo); /* BGP adjacency out. */ struct bgp_adj_out { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1b176f8716..a583581030 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -243,6 +243,15 @@ struct attr { */ #define ATTR_ES_PEER_ROUTER (1 << 4) + /* These two flags are only set on L3 routes installed in a + * VRF as a result of EVPN MAC-IP route + * XXX - while splitting up per-family attrs these need to be + * classified as non-EVPN + */ +#define ATTR_ES_L3_NHG_USE (1 << 5) +#define ATTR_ES_L3_NHG_ACTIVE (1 << 6) +#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) + /* route tag */ route_tag_t tag; diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 11e9344d1c..f1bdcc8bb4 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -29,6 +29,7 @@ #include "thread.h" #include "buffer.h" #include "stream.h" +#include "vrf.h" #include "zclient.h" #include "bfd.h" #include "lib/json.h" @@ -40,667 +41,391 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_vty.h" +DEFINE_MTYPE_STATIC(BGPD, BFD_CONFIG, "BFD configuration data"); + extern struct zclient *zclient; -/* - * bgp_bfd_peer_group2peer_copy - Copy the BFD information from peer group - * template - * to peer. - */ -void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer) +static void bfd_session_status_update(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, + void *arg) { - struct bfd_info *bfd_info; - struct bfd_info *conf_bfd_info; - - if (!conf->bfd_info) - return; - - conf_bfd_info = (struct bfd_info *)conf->bfd_info; - if (!peer->bfd_info) - peer->bfd_info = bfd_info_create(); - - bfd_info = (struct bfd_info *)peer->bfd_info; + struct peer *peer = arg; + + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug("%s: neighbor %s vrf %s(%u) bfd state %s -> %s", + __func__, peer->conf_if ? peer->conf_if : peer->host, + bfd_sess_vrf(bsp), bfd_sess_vrf_id(bsp), + bfd_get_status_str(bss->previous_state), + bfd_get_status_str(bss->state)); + + if (bss->state == BSS_DOWN && bss->previous_state == BSS_UP) { + if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) + && bfd_sess_cbit(bsp) && !bss->remote_cbit) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_info( + "%s BFD DOWN message ignored in the process of graceful restart when C bit is cleared", + peer->host); + return; + } + peer->last_reset = PEER_DOWN_BFD_DOWN; + BGP_EVENT_ADD(peer, BGP_Stop); + } - /* Copy BFD parameter values */ - bfd_info->required_min_rx = conf_bfd_info->required_min_rx; - bfd_info->desired_min_tx = conf_bfd_info->desired_min_tx; - bfd_info->detect_mult = conf_bfd_info->detect_mult; - bfd_info->type = conf_bfd_info->type; + if (bss->state == BSS_UP && bss->previous_state != BSS_UP + && peer->status != Established) { + if (!BGP_PEER_START_SUPPRESSED(peer)) { + bgp_fsm_nht_update(peer, true); + BGP_EVENT_ADD(peer, BGP_Start); + } + } } -/* - * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single - * hop. - */ -bool bgp_bfd_is_peer_multihop(struct peer *peer) +void bgp_peer_config_apply(struct peer *p, struct peer_group *pg) { - struct bfd_info *bfd_info; + struct listnode *n; + struct peer *pn; + struct peer *gconfig; + + /* When called on a group, apply to all peers. */ + if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) { + for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) + bgp_peer_config_apply(pn, pg); + return; + } - bfd_info = (struct bfd_info *)peer->bfd_info; + /* No group, just use current configuration. */ + if (pg == NULL || pg->conf->bfd_config == NULL) { + bfd_sess_set_timers(p->bfd_config->session, + p->bfd_config->detection_multiplier, + p->bfd_config->min_rx, + p->bfd_config->min_tx); + bfd_sess_set_cbit(p->bfd_config->session, p->bfd_config->cbit); + bfd_sess_set_profile(p->bfd_config->session, + p->bfd_config->profile); + bfd_sess_install(p->bfd_config->session); + return; + } - if (!bfd_info) - return false; + /* + * Check if the group configuration was overwritten or apply group + * configuration. + */ + gconfig = pg->conf; + + /* + * If using default control plane independent configuration, + * then prefer group's (e.g. it means it wasn't manually configured). + */ + if (!p->bfd_config->cbit) + bfd_sess_set_cbit(p->bfd_config->session, + gconfig->bfd_config->cbit); + else + bfd_sess_set_cbit(p->bfd_config->session, p->bfd_config->cbit); - if ((bfd_info->type == BFD_TYPE_MULTIHOP) - || ((peer->sort == BGP_PEER_IBGP) && !peer->shared_network) - || is_ebgp_multihop_configured(peer)) - return true; + /* If no profile was specified in peer, then use the group profile. */ + if (p->bfd_config->profile[0] == 0) + bfd_sess_set_profile(p->bfd_config->session, + gconfig->bfd_config->profile); else - return false; + bfd_sess_set_profile(p->bfd_config->session, + p->bfd_config->profile); + + /* If no specific timers were configured, then use the group timers. */ + if (p->bfd_config->detection_multiplier == BFD_DEF_DETECT_MULT + || p->bfd_config->min_rx == BFD_DEF_MIN_RX + || p->bfd_config->min_tx == BFD_DEF_MIN_TX) + bfd_sess_set_timers(p->bfd_config->session, + gconfig->bfd_config->detection_multiplier, + gconfig->bfd_config->min_rx, + gconfig->bfd_config->min_tx); + else + bfd_sess_set_timers(p->bfd_config->session, + p->bfd_config->detection_multiplier, + p->bfd_config->min_rx, + p->bfd_config->min_tx); + + bfd_sess_install(p->bfd_config->session); } -/* - * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister - * command to Zebra to be forwarded to BFD - */ -static void bgp_bfd_peer_sendmsg(struct peer *peer, int command) +void bgp_peer_bfd_update_source(struct peer *p) { - struct bfd_session_arg arg = {}; - struct bfd_info *bfd_info; - int multihop; - vrf_id_t vrf_id; - size_t addrlen; - - /* - * XXX: some pointers are dangling during shutdown, so instead of - * trying to send a message during signal handlers lets just wait BGP - * to terminate zebra's connection and BFD will automatically find - * out that we are no longer expecting notifications. - * - * The pointer that is causing a crash here is `peer->nexthop.ifp`. - * That happens because at this point of the shutdown all interfaces are - * already `free()`d. - */ - if (bm->terminating) + struct bfd_session_params *session = p->bfd_config->session; + bool changed = false; + int family; + union { + struct in_addr v4; + struct in6_addr v6; + } src, dst; + + /* Nothing to do for groups. */ + if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) return; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Update peer's source/destination addresses. */ + bfd_sess_addresses(session, &family, &src.v6, &dst.v6); + if (family == AF_INET) { + if ((p->su_local + && p->su_local->sin.sin_addr.s_addr != src.v4.s_addr) + || p->su.sin.sin_addr.s_addr != dst.v4.s_addr) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug( + "%s: address [%pI4->%pI4] to [%pI4->%pI4]", + __func__, &src.v4, &dst.v4, + p->su_local ? &p->su_local->sin.sin_addr + : &src.v4, + &p->su.sin.sin_addr); + + bfd_sess_set_ipv4_addrs( + session, + p->su_local ? &p->su_local->sin.sin_addr : NULL, + &p->su.sin.sin_addr); + changed = true; + } + } else { + if ((p->su_local + && memcmp(&p->su_local->sin6, &src.v6, sizeof(src.v6))) + || memcmp(&p->su.sin6, &dst.v6, sizeof(dst.v6))) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug( + "%s: address [%pI6->%pI6] to [%pI6->%pI6]", + __func__, &src.v6, &dst.v6, + p->su_local + ? &p->su_local->sin6.sin6_addr + : &src.v6, + &p->su.sin6.sin6_addr); + + bfd_sess_set_ipv6_addrs( + session, + p->su_local ? &p->su_local->sin6.sin6_addr + : NULL, + &p->su.sin6.sin6_addr); + changed = true; + } + } - vrf_id = peer->bgp->vrf_id; + /* Update interface. */ + if (p->nexthop.ifp && bfd_sess_interface(session) == NULL) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug("%s: interface none to %s", __func__, + p->nexthop.ifp->name); - if (command == ZEBRA_BFD_DEST_DEREGISTER) { - multihop = - CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP); - UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP); - } else { - multihop = bgp_bfd_is_peer_multihop(peer); - if ((command == ZEBRA_BFD_DEST_REGISTER) && multihop) - SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP); + bfd_sess_set_interface(session, p->nexthop.ifp->name); + changed = true; } - /* while graceful restart with fwd path preserved - * and bfd controlplane check not configured is not kept - * keep bfd independent controlplane bit set to 1 + + /* + * Update TTL. + * + * Two cases: + * - We detected that the peer is a hop away from us (remove multi hop). + * (this happens when `p->shared_network` is set to `true`) + * - eBGP multi hop / TTL security changed. */ - if (!CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_RESTART) - && !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD) - && !CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) - SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); - - /* Set all message arguments. */ - arg.family = peer->su.sa.sa_family; - addrlen = arg.family == AF_INET ? sizeof(struct in_addr) - : sizeof(struct in6_addr); - - if (arg.family == AF_INET) - memcpy(&arg.dst, &peer->su.sin.sin_addr, addrlen); - else - memcpy(&arg.dst, &peer->su.sin6.sin6_addr, addrlen); + if (!PEER_IS_MULTIHOP(p) && bfd_sess_hop_count(session) > 1) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug("%s: TTL %d to 1", __func__, + bfd_sess_hop_count(session)); - if (peer->su_local) { - if (arg.family == AF_INET) - memcpy(&arg.src, &peer->su_local->sin.sin_addr, - addrlen); - else - memcpy(&arg.src, &peer->su_local->sin6.sin6_addr, - addrlen); + bfd_sess_set_hop_count(session, 1); + changed = true; } + if (PEER_IS_MULTIHOP(p) && p->ttl != bfd_sess_hop_count(session)) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug("%s: TTL %d to %d", __func__, + bfd_sess_hop_count(session), p->ttl); - if (peer->nexthop.ifp) { - arg.ifnamelen = strlen(peer->nexthop.ifp->name); - strlcpy(arg.ifname, peer->nexthop.ifp->name, - sizeof(arg.ifname)); + bfd_sess_set_hop_count(session, p->ttl); + changed = true; } - if (bfd_info->profile[0]) { - arg.profilelen = strlen(bfd_info->profile); - strlcpy(arg.profile, bfd_info->profile, sizeof(arg.profile)); + /* Update VRF. */ + if (bfd_sess_vrf_id(session) != p->bgp->vrf_id) { + if (BGP_DEBUG(bfd, BFD_LIB)) + zlog_debug( + "%s: VRF %s(%d) to %s(%d)", __func__, + bfd_sess_vrf(session), bfd_sess_vrf_id(session), + vrf_id_to_name(p->bgp->vrf_id), p->bgp->vrf_id); + + bfd_sess_set_vrf(session, p->bgp->vrf_id); + changed = true; } - arg.set_flag = 1; - arg.mhop = multihop; - arg.ttl = peer->ttl; - arg.vrf_id = vrf_id; - arg.command = command; - arg.bfd_info = bfd_info; - arg.min_tx = bfd_info->desired_min_tx; - arg.min_rx = bfd_info->required_min_rx; - arg.detection_multiplier = bfd_info->detect_mult; - arg.cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); - - /* Send message. */ - zclient_bfd_command(zclient, &arg); + if (changed) + bfd_sess_install(session); } -/* - * bgp_bfd_register_peer - register a peer with BFD through zebra - * for monitoring the peer rechahability. +/** + * Reset BFD configuration data structure to its defaults settings. */ -void bgp_bfd_register_peer(struct peer *peer) +static void bgp_peer_bfd_reset(struct peer *p) { - struct bfd_info *bfd_info; - - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* Check if BFD is enabled and peer has already been registered with BFD - */ - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) - return; - - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); + /* Set defaults. */ + p->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT; + p->bfd_config->min_rx = BFD_DEF_MIN_RX; + p->bfd_config->min_tx = BFD_DEF_MIN_TX; + p->bfd_config->cbit = false; + p->bfd_config->profile[0] = 0; } -/** - * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra - * for stopping the monitoring of the peer - * rechahability. - */ -void bgp_bfd_deregister_peer(struct peer *peer) +void bgp_peer_configure_bfd(struct peer *p, bool manual) { - struct bfd_info *bfd_info; + /* Groups should not call this. */ + assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Already configured, skip it. */ + if (p->bfd_config) { + /* If manually active update flag. */ + if (!p->bfd_config->manual) + p->bfd_config->manual = manual; - /* Check if BFD is eanbled and peer has not been registered */ - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) return; + } - bfd_info->status = BFD_STATUS_DOWN; - bfd_info->last_update = bgp_clock(); - - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER); -} - -/* - * bgp_bfd_update_peer - update peer with BFD with new BFD paramters - * through zebra. - */ -static void bgp_bfd_update_peer(struct peer *peer) -{ - struct bfd_info *bfd_info; + /* Allocate memory for configuration overrides. */ + p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config)); + p->bfd_config->manual = manual; - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Create new session and assign callback. */ + p->bfd_config->session = bfd_sess_new(bfd_session_status_update, p); + bgp_peer_bfd_reset(p); - /* Check if the peer has been registered with BFD*/ - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) - return; + /* Configure session with basic BGP peer data. */ + if (p->su.sa.sa_family == AF_INET) + bfd_sess_set_ipv4_addrs(p->bfd_config->session, + p->su_local ? &p->su_local->sin.sin_addr + : NULL, + &p->su.sin.sin_addr); + else + bfd_sess_set_ipv6_addrs( + p->bfd_config->session, + p->su_local ? &p->su_local->sin6.sin6_addr : NULL, + &p->su.sin6.sin6_addr); - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_UPDATE); -} + bfd_sess_set_vrf(p->bfd_config->session, p->bgp->vrf_id); + bfd_sess_set_hop_count(p->bfd_config->session, + PEER_IS_MULTIHOP(p) ? p->ttl : 1); -/** - * bgp_bfd_reset_peer - reinitialise bfd - * ensures that bfd state machine is restarted - * to be synced with remote bfd - */ -void bgp_bfd_reset_peer(struct peer *peer) -{ - if (!peer->bfd_info) - return; + if (p->nexthop.ifp) + bfd_sess_set_interface(p->bfd_config->session, + p->nexthop.ifp->name); - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); + bfd_sess_enable(p->bfd_config->session, true); } -/* - * bgp_bfd_update_type - update session type with BFD through zebra. - */ -static void bgp_bfd_update_type(struct peer *peer) +static void bgp_peer_remove_bfd(struct peer *p) { - struct bfd_info *bfd_info; - int multihop; - - if (!peer->bfd_info) - return; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Groups should not call this. */ + assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - /* Check if the peer has been registered with BFD*/ - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG)) + /* + * Peer configuration was removed, however we must check if there + * is still a group configuration to keep this running. + */ + if (p->group && p->group->conf->bfd_config) { + p->bfd_config->manual = false; + bgp_peer_bfd_reset(p); + bgp_peer_config_apply(p, p->group); return; - - if (bfd_info->type == BFD_TYPE_NOT_CONFIGURED) { - multihop = bgp_bfd_is_peer_multihop(peer); - if ((multihop - && !CHECK_FLAG(bfd_info->flags, - BFD_FLAG_BFD_TYPE_MULTIHOP)) - || (!multihop && CHECK_FLAG(bfd_info->flags, - BFD_FLAG_BFD_TYPE_MULTIHOP))) { - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER); - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); - } - } else { - if ((bfd_info->type == BFD_TYPE_MULTIHOP - && !CHECK_FLAG(bfd_info->flags, - BFD_FLAG_BFD_TYPE_MULTIHOP)) - || (bfd_info->type == BFD_TYPE_SINGLEHOP - && CHECK_FLAG(bfd_info->flags, - BFD_FLAG_BFD_TYPE_MULTIHOP))) { - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER); - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); - } } -} - -/* - * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled - * to zebra - */ -static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS) -{ - struct listnode *mnode, *node, *nnode; - struct bgp *bgp; - struct peer *peer; - - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Zebra: BFD Dest replay request"); - - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); - - /* Replay the peer, if BFD is enabled in BGP */ - for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp)) - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - bgp_bfd_update_peer(peer); - } - - return 0; + bfd_sess_free(&p->bfd_config->session); + XFREE(MTYPE_BFD_CONFIG, p->bfd_config); } -/* - * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring - * down the peer if the BFD session went down from - * * up. - */ -static void bgp_bfd_peer_status_update(struct peer *peer, int status, - int remote_cbit) +static void bgp_group_configure_bfd(struct peer *p) { - struct bfd_info *bfd_info; - int old_status; + struct listnode *n; + struct peer *pn; - bfd_info = (struct bfd_info *)peer->bfd_info; + /* Peers should not call this. */ + assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - if (bfd_info->status == status) + /* Already allocated: do nothing. */ + if (p->bfd_config) return; - old_status = bfd_info->status; - BFD_SET_CLIENT_STATUS(bfd_info->status, status); + p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config)); - bfd_info->last_update = bgp_clock(); + /* Set defaults. */ + p->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT; + p->bfd_config->min_rx = BFD_DEF_MIN_RX; + p->bfd_config->min_tx = BFD_DEF_MIN_TX; - if (status != old_status) { - if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) - zlog_debug("[%s]: BFD %s", peer->host, - bfd_get_status_str(status)); - } - if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP)) { - if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) && - CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE) && - !remote_cbit) { - zlog_info("%s BFD DOWN message ignored in the process of graceful restart when C bit is cleared", - peer->host); - return; - } - peer->last_reset = PEER_DOWN_BFD_DOWN; - BGP_EVENT_ADD(peer, BGP_Stop); - } - if ((status == BFD_STATUS_UP) && (old_status == BFD_STATUS_DOWN) - && peer->status != Established) { - if (!BGP_PEER_START_SUPPRESSED(peer)) { - bgp_fsm_nht_update(peer, true); - BGP_EVENT_ADD(peer, BGP_Start); - } - } + for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) + bgp_peer_configure_bfd(pn, false); } -/* - * bgp_bfd_dest_update - Find the peer for which the BFD status - * has changed and bring down the peer - * connectivity if the BFD session went down. - */ -static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS) +static void bgp_group_remove_bfd(struct peer *p) { - struct interface *ifp; - struct prefix dp; - struct prefix sp; - int status; - int remote_cbit; + struct listnode *n; + struct peer *pn; - ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status, - &remote_cbit, vrf_id); + /* Peers should not call this. */ + assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)); - if (BGP_DEBUG(zebra, ZEBRA)) { - struct vrf *vrf; + /* Already freed: do nothing. */ + if (p->bfd_config == NULL) + return; - vrf = vrf_lookup_by_id(vrf_id); + /* Free configuration and point to `NULL`. */ + XFREE(MTYPE_BFD_CONFIG, p->bfd_config); - if (ifp) - zlog_debug( - "Zebra: vrf %s(%u) interface %s bfd destination %pFX %s %s", - VRF_LOGNAME(vrf), vrf_id, ifp->name, &dp, - bfd_get_status_str(status), - remote_cbit ? "(cbit on)" : ""); + /* Now that it is `NULL` recalculate configuration for all peers. */ + for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) { + if (pn->bfd_config->manual) + bgp_peer_config_apply(pn, NULL); else - zlog_debug( - "Zebra: vrf %s(%u) source %pFX bfd destination %pFX %s %s", - VRF_LOGNAME(vrf), vrf_id, &sp, &dp, - bfd_get_status_str(status), - remote_cbit ? "(cbit on)" : ""); - } - - /* Bring the peer down if BFD is enabled in BGP */ - { - struct listnode *mnode, *node, *nnode; - struct bgp *bgp; - struct peer *peer; - - for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp)) - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (!peer->bfd_info) - continue; - - if ((dp.family == AF_INET) - && (peer->su.sa.sa_family == AF_INET)) { - if (dp.u.prefix4.s_addr - != peer->su.sin.sin_addr.s_addr) - continue; - } else if ((dp.family == AF_INET6) - && (peer->su.sa.sa_family - == AF_INET6)) { - if (memcmp(&dp.u.prefix6, - &peer->su.sin6.sin6_addr, - sizeof(struct in6_addr))) - continue; - } else - continue; - - if (ifp && (ifp == peer->nexthop.ifp)) { - bgp_bfd_peer_status_update(peer, - status, - remote_cbit); - } else { - if (!peer->su_local) - continue; - - if ((sp.family == AF_INET) - && (peer->su_local->sa.sa_family - == AF_INET)) { - if (sp.u.prefix4.s_addr - != peer->su_local->sin - .sin_addr.s_addr) - continue; - } else if ((sp.family == AF_INET6) - && (peer->su_local->sa - .sa_family - == AF_INET6)) { - if (memcmp(&sp.u.prefix6, - &peer->su_local->sin6 - .sin6_addr, - sizeof(struct - in6_addr))) - continue; - } else - continue; - - if ((vrf_id != VRF_DEFAULT) - && (peer->bgp->vrf_id != vrf_id)) - continue; - - bgp_bfd_peer_status_update(peer, - status, - remote_cbit); - } - } - } - - return 0; -} - -/* - * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer. - */ -static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx, - uint32_t min_tx, uint8_t detect_mult, - int defaults) -{ - struct bfd_info *bi; - struct peer_group *group; - struct listnode *node, *nnode; - int command = 0; - - bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx, - detect_mult, NULL, defaults, &command); - - /* This command overrides profile if it was previously applied. */ - bi = peer->bfd_info; - bi->profile[0] = 0; - - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - command = 0; - bfd_set_param((struct bfd_info **)&(peer->bfd_info), - min_rx, min_tx, detect_mult, NULL, - defaults, &command); - - /* - * This command overrides profile if it was previously - * applied. - */ - bi = peer->bfd_info; - bi->profile[0] = 0; - - if ((peer->status == Established) - && (command == ZEBRA_BFD_DEST_REGISTER)) - bgp_bfd_register_peer(peer); - else if (command == ZEBRA_BFD_DEST_UPDATE) - bgp_bfd_update_peer(peer); - } - } else { - if ((peer->status == Established) - && (command == ZEBRA_BFD_DEST_REGISTER)) - bgp_bfd_register_peer(peer); - else if (command == ZEBRA_BFD_DEST_UPDATE) - bgp_bfd_update_peer(peer); - } - return 0; -} - -/* - * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for - * peer. - */ -static int bgp_bfd_peer_param_unset(struct peer *peer) -{ - struct peer_group *group; - struct listnode *node, *nnode; - - if (!peer->bfd_info) - return 0; - - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - bfd_info_free(&(peer->bfd_info)); - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - bgp_bfd_deregister_peer(peer); - bfd_info_free(&(peer->bfd_info)); - } - } else { - bgp_bfd_deregister_peer(peer); - bfd_info_free(&(peer->bfd_info)); + bgp_peer_remove_bfd(pn); } - return 0; } -/* - * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or - * singlehop) - */ -static int bgp_bfd_peer_param_type_set(struct peer *peer, - enum bfd_sess_type type) +void bgp_peer_remove_bfd_config(struct peer *p) { - struct peer_group *group; - struct listnode *node, *nnode; - int command = 0; - struct bfd_info *bfd_info; - - if (!peer->bfd_info) - bfd_set_param((struct bfd_info **)&(peer->bfd_info), - BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, NULL, 1, &command); - - bfd_info = (struct bfd_info *)peer->bfd_info; - bfd_info->type = type; - - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - command = 0; - if (!peer->bfd_info) - bfd_set_param( - (struct bfd_info **)&(peer->bfd_info), - BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, NULL, 1, &command); - - bfd_info = (struct bfd_info *)peer->bfd_info; - bfd_info->type = type; - - if (peer->status == Established) { - if (command == ZEBRA_BFD_DEST_REGISTER) - bgp_bfd_register_peer(peer); - else - bgp_bfd_update_type(peer); - } - } - } else { - if (peer->status == Established) { - if (command == ZEBRA_BFD_DEST_REGISTER) - bgp_bfd_register_peer(peer); - else - bgp_bfd_update_type(peer); - } - } - - return 0; -} - -#if HAVE_BFDD > 0 -/** - * Set peer BFD profile configuration. - */ -static int bgp_bfd_peer_set_profile(struct peer *peer, const char *profile) -{ - struct peer_group *group; - struct listnode *node, *nnode; - int command = 0; - struct bfd_info *bfd_info; - - bfd_set_param((struct bfd_info **)&(peer->bfd_info), BFD_DEF_MIN_RX, - BFD_DEF_MIN_TX, BFD_DEF_DETECT_MULT, NULL, 1, &command); - - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* If profile was specified, then copy string. */ - if (profile) - strlcpy(bfd_info->profile, profile, sizeof(bfd_info->profile)); - else /* Otherwise just initialize it empty. */ - bfd_info->profile[0] = 0; - - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - command = 0; - bfd_set_param((struct bfd_info **)&(peer->bfd_info), - BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, NULL, 1, &command); - - bfd_info = (struct bfd_info *)peer->bfd_info; - - /* If profile was specified, then copy string. */ - if (profile) - strlcpy(bfd_info->profile, profile, - sizeof(bfd_info->profile)); - else /* Otherwise just initialize it empty. */ - bfd_info->profile[0] = 0; - - if (peer->status == Established - && command == ZEBRA_BFD_DEST_REGISTER) - bgp_bfd_register_peer(peer); - else if (command == ZEBRA_BFD_DEST_UPDATE) - bgp_bfd_update_peer(peer); - } - } else { - if (peer->status == Established - && command == ZEBRA_BFD_DEST_REGISTER) - bgp_bfd_register_peer(peer); - else if (command == ZEBRA_BFD_DEST_UPDATE) - bgp_bfd_update_peer(peer); - } - - return 0; + if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) + bgp_group_remove_bfd(p); + else + bgp_peer_remove_bfd(p); } -#endif /* * bgp_bfd_peer_config_write - Write the peer BFD configuration. */ -void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr) +void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer, + const char *addr) { - struct bfd_info *bfd_info; - - if (!peer->bfd_info) - return; - - bfd_info = (struct bfd_info *)peer->bfd_info; - - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) + /* + * Always show group BFD configuration, but peer only when explicitly + * configured. + */ + if ((!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) + && peer->bfd_config->manual) + || CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { #if HAVE_BFDD > 0 vty_out(vty, " neighbor %s bfd\n", addr); #else vty_out(vty, " neighbor %s bfd %d %d %d\n", addr, - bfd_info->detect_mult, bfd_info->required_min_rx, - bfd_info->desired_min_tx); + peer->bfd_config->detection_multiplier, + peer->bfd_config->min_rx, peer->bfd_config->min_tx); #endif /* HAVE_BFDD */ - - if (bfd_info->type != BFD_TYPE_NOT_CONFIGURED) - vty_out(vty, " neighbor %s bfd %s\n", addr, - (bfd_info->type == BFD_TYPE_MULTIHOP) ? "multihop" - : "singlehop"); - - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG) - && (bfd_info->type == BFD_TYPE_NOT_CONFIGURED)) { - vty_out(vty, " neighbor %s bfd", addr); - if (bfd_info->profile[0]) - vty_out(vty, " profile %s", bfd_info->profile); - vty_out(vty, "\n"); } - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) - vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", addr); + if (peer->bfd_config->profile[0]) + vty_out(vty, " neighbor %s bfd profile %s\n", addr, + peer->bfd_config->profile); + + if (peer->bfd_config->cbit) + vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", + addr); } /* * bgp_bfd_show_info - Show the peer BFD information. */ -void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json, +void bgp_bfd_show_info(struct vty *vty, const struct peer *peer, json_object *json_neigh) { - bfd_show_info(vty, (struct bfd_info *)peer->bfd_info, - bgp_bfd_is_peer_multihop(peer), 0, use_json, json_neigh); + if (peer->bfd_config->session) + bfd_sess_show(vty, json_neigh, peer->bfd_config->session); } DEFUN (neighbor_bfd, @@ -712,16 +437,17 @@ DEFUN (neighbor_bfd, { int idx_peer = 1; struct peer *peer; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - ret = bgp_bfd_peer_param_set(peer, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, 1); - if (ret != 0) - return bgp_vty_return(vty, ret); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); + else + bgp_peer_configure_bfd(peer, true); + + bgp_peer_config_apply(peer, peer->group); return CMD_SUCCESS; } @@ -745,89 +471,30 @@ DEFUN( int idx_number_1 = 3; int idx_number_2 = 4; int idx_number_3 = 5; + long detection_multiplier, min_rx, min_tx; struct peer *peer; - uint32_t rx_val; - uint32_t tx_val; - uint8_t dm_val; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if ((ret = bfd_validate_param( - vty, argv[idx_number_1]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val)) - != CMD_SUCCESS) - return ret; - - ret = bgp_bfd_peer_param_set(peer, rx_val, tx_val, dm_val, 0); - if (ret != 0) - return bgp_vty_return(vty, ret); - - return CMD_SUCCESS; -} - -DEFUN_HIDDEN (neighbor_bfd_type, - neighbor_bfd_type_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>", - NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 - "Enables BFD support\n" - "Multihop session\n" - "Single hop session\n") -{ - int idx_peer = 1; - int idx_hop = 3; - struct peer *peer; - enum bfd_sess_type type; - int ret; - - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; + detection_multiplier = strtol(argv[idx_number_1]->arg, NULL, 10); + min_rx = strtol(argv[idx_number_2]->arg, NULL, 10); + min_tx = strtol(argv[idx_number_3]->arg, NULL, 10); - if (strmatch(argv[idx_hop]->text, "singlehop")) - type = BFD_TYPE_SINGLEHOP; - else if (strmatch(argv[idx_hop]->text, "multihop")) - type = BFD_TYPE_MULTIHOP; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); else - return CMD_WARNING_CONFIG_FAILED; - - ret = bgp_bfd_peer_param_type_set(peer, type); - if (ret != 0) - return bgp_vty_return(vty, ret); + bgp_peer_configure_bfd(peer, true); - return CMD_SUCCESS; -} - -static int bgp_bfd_set_check_controlplane_failure_peer(struct vty *vty, struct peer *peer, - const char *no) -{ - struct bfd_info *bfd_info; + peer->bfd_config->detection_multiplier = detection_multiplier; + peer->bfd_config->min_rx = min_rx; + peer->bfd_config->min_tx = min_tx; + bgp_peer_config_apply(peer, peer->group); - if (!peer->bfd_info) { - if (no) - return CMD_SUCCESS; - vty_out(vty, "%% Specify bfd command first\n"); - return CMD_WARNING_CONFIG_FAILED; - } - bfd_info = (struct bfd_info *)peer->bfd_info; - if (!no) { - if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) { - SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE); - bgp_bfd_update_peer(peer); - } - } else { - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) { - UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE); - bgp_bfd_update_peer(peer); - } - } return CMD_SUCCESS; } - DEFUN (neighbor_bfd_check_controlplane_failure, neighbor_bfd_check_controlplane_failure_cmd, "[no] neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure", @@ -840,9 +507,6 @@ DEFUN (neighbor_bfd_check_controlplane_failure, const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL; int idx_peer = 0; struct peer *peer; - struct peer_group *group; - struct listnode *node, *nnode; - int ret = CMD_SUCCESS; if (no) idx_peer = 2; @@ -853,19 +517,16 @@ DEFUN (neighbor_bfd_check_controlplane_failure, vty_out(vty, "%% Specify remote-as or peer-group commands first\n"); return CMD_WARNING_CONFIG_FAILED; } - if (!peer->bfd_info) { - if (no) - return CMD_SUCCESS; - vty_out(vty, "%% Specify bfd command first\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - group = peer->group; - for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) - ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no); - } else - ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no); - return ret; + + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); + else + bgp_peer_configure_bfd(peer, true); + + peer->bfd_config->cbit = no == NULL; + bgp_peer_config_apply(peer, peer->group); + + return CMD_SUCCESS; } DEFUN (no_neighbor_bfd, @@ -888,44 +549,15 @@ DEFUN (no_neighbor_bfd, { int idx_peer = 2; struct peer *peer; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - ret = bgp_bfd_peer_param_unset(peer); - if (ret != 0) - return bgp_vty_return(vty, ret); - - return CMD_SUCCESS; -} - - -DEFUN_HIDDEN (no_neighbor_bfd_type, - no_neighbor_bfd_type_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>", - NO_STR - NEIGHBOR_STR - NEIGHBOR_ADDR_STR2 - "Disables BFD support\n" - "Multihop session\n" - "Singlehop session\n") -{ - int idx_peer = 2; - struct peer *peer; - int ret; - - peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - - if (!peer->bfd_info) - return 0; - - ret = bgp_bfd_peer_param_type_set(peer, BFD_TYPE_NOT_CONFIGURED); - if (ret != 0) - return bgp_vty_return(vty, ret); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_remove_bfd(peer); + else + bgp_peer_remove_bfd(peer); return CMD_SUCCESS; } @@ -941,15 +573,19 @@ DEFUN(neighbor_bfd_profile, neighbor_bfd_profile_cmd, { int idx_peer = 1, idx_prof = 4; struct peer *peer; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - ret = bgp_bfd_peer_set_profile(peer, argv[idx_prof]->arg); - if (ret != 0) - return bgp_vty_return(vty, ret); + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); + else + bgp_peer_configure_bfd(peer, true); + + strlcpy(peer->bfd_config->profile, argv[idx_prof]->arg, + sizeof(peer->bfd_config->profile)); + bgp_peer_config_apply(peer, peer->group); return CMD_SUCCESS; } @@ -965,38 +601,33 @@ DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd, { int idx_peer = 2; struct peer *peer; - int ret; peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (!peer->bfd_info) - return 0; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) + bgp_group_configure_bfd(peer); + else + bgp_peer_configure_bfd(peer, true); - ret = bgp_bfd_peer_set_profile(peer, NULL); - if (ret != 0) - return bgp_vty_return(vty, ret); + peer->bfd_config->profile[0] = 0; + bgp_peer_config_apply(peer, peer->group); return CMD_SUCCESS; } #endif /* HAVE_BFDD */ -void bgp_bfd_init(void) +void bgp_bfd_init(struct thread_master *tm) { - bfd_gbl_init(); - /* Initialize BFD client functions */ - zclient->interface_bfd_dest_update = bgp_bfd_dest_update; - zclient->bfd_dest_replay = bgp_bfd_dest_replay; + bfd_protocol_integration_init(zclient, tm); /* "neighbor bfd" commands. */ install_element(BGP_NODE, &neighbor_bfd_cmd); install_element(BGP_NODE, &neighbor_bfd_param_cmd); - install_element(BGP_NODE, &neighbor_bfd_type_cmd); install_element(BGP_NODE, &neighbor_bfd_check_controlplane_failure_cmd); install_element(BGP_NODE, &no_neighbor_bfd_cmd); - install_element(BGP_NODE, &no_neighbor_bfd_type_cmd); #if HAVE_BFDD > 0 install_element(BGP_NODE, &neighbor_bfd_profile_cmd); diff --git a/bgpd/bgp_bfd.h b/bgpd/bgp_bfd.h index f2fa959b45..9dca48a437 100644 --- a/bgpd/bgp_bfd.h +++ b/bgpd/bgp_bfd.h @@ -23,22 +23,58 @@ #ifndef _QUAGGA_BGP_BFD_H #define _QUAGGA_BGP_BFD_H -extern void bgp_bfd_init(void); +#define PEER_IS_MULTIHOP(peer) \ + ((((peer)->sort == BGP_PEER_IBGP) && !(peer)->shared_network) \ + || is_ebgp_multihop_configured((peer))) -extern void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer); +extern void bgp_bfd_init(struct thread_master *tm); -extern void bgp_bfd_register_peer(struct peer *peer); +extern void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer, + const char *addr); -extern void bgp_bfd_deregister_peer(struct peer *peer); +/** + * Show BFD information helper. + * + * \param vty the VTY pointer. + * \param peer the BGP configuration pointer. + * \param use_json unused. + * \param json_neigh JSON object when called as JSON command. + */ +extern void bgp_bfd_show_info(struct vty *vty, const struct peer *peer, + json_object *json_neigh); -extern void bgp_bfd_reset_peer(struct peer *peer); +/** + * When called on a group it applies configuration to all peers in that group, + * otherwise just applies the configuration to a single peer. + * + * This function should be called when configuration changes either on group + * or peer. + * + * \param p the BGP peer pointer. + * \param pg the BGP group to copy configuration from (it is usually + * `p->group` exception when copying new group configuration + * see `peer_group2peer_config_copy` function case). + */ +extern void bgp_peer_config_apply(struct peer *p, struct peer_group *pg); -extern void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, - char *addr); +/** + * Allocates and configure BFD session for peer. If it is already configured, + * then it does nothing. + * + * Always call `bgp_peer_config_apply` afterwards if you need the changes + * immediately applied. + */ +extern void bgp_peer_configure_bfd(struct peer *p, bool manual); -extern void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json, - json_object *json_neigh); +/** + * Removes BFD configuration from either peer or peer group. + */ +extern void bgp_peer_remove_bfd_config(struct peer *p); -extern bool bgp_bfd_is_peer_multihop(struct peer *peer); +/** + * Special function to handle the case of changing source address. This + * happens when the peer/group is configured with `neigbor X update-source Y`. + */ +extern void bgp_peer_bfd_update_source(struct peer *p); #endif /* _QUAGGA_BGP_BFD_H */ diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 4102d102e6..0e5f506b3a 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -59,21 +59,21 @@ static struct bmp_bgp_peer *bmp_bgp_peer_get(struct peer *peer); static void bmp_active_disconnected(struct bmp_active *ba); static void bmp_active_put(struct bmp_active *ba); -DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)") - -DEFINE_MTYPE_STATIC(BMP, BMP_CONN, "BMP connection state") -DEFINE_MTYPE_STATIC(BMP, BMP_TARGETS, "BMP targets") -DEFINE_MTYPE_STATIC(BMP, BMP_TARGETSNAME, "BMP targets name") -DEFINE_MTYPE_STATIC(BMP, BMP_LISTENER, "BMP listener") -DEFINE_MTYPE_STATIC(BMP, BMP_ACTIVE, "BMP active connection config") -DEFINE_MTYPE_STATIC(BMP, BMP_ACLNAME, "BMP access-list name") -DEFINE_MTYPE_STATIC(BMP, BMP_QUEUE, "BMP update queue item") -DEFINE_MTYPE_STATIC(BMP, BMP, "BMP instance state") -DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ, "BMP route mirroring buffer") -DEFINE_MTYPE_STATIC(BMP, BMP_PEER, "BMP per BGP peer data") -DEFINE_MTYPE_STATIC(BMP, BMP_OPEN, "BMP stored BGP OPEN message") - -DEFINE_QOBJ_TYPE(bmp_targets) +DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)"); + +DEFINE_MTYPE_STATIC(BMP, BMP_CONN, "BMP connection state"); +DEFINE_MTYPE_STATIC(BMP, BMP_TARGETS, "BMP targets"); +DEFINE_MTYPE_STATIC(BMP, BMP_TARGETSNAME, "BMP targets name"); +DEFINE_MTYPE_STATIC(BMP, BMP_LISTENER, "BMP listener"); +DEFINE_MTYPE_STATIC(BMP, BMP_ACTIVE, "BMP active connection config"); +DEFINE_MTYPE_STATIC(BMP, BMP_ACLNAME, "BMP access-list name"); +DEFINE_MTYPE_STATIC(BMP, BMP_QUEUE, "BMP update queue item"); +DEFINE_MTYPE_STATIC(BMP, BMP, "BMP instance state"); +DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ, "BMP route mirroring buffer"); +DEFINE_MTYPE_STATIC(BMP, BMP_PEER, "BMP per BGP peer data"); +DEFINE_MTYPE_STATIC(BMP, BMP_OPEN, "BMP stored BGP OPEN message"); + +DEFINE_QOBJ_TYPE(bmp_targets); static int bmp_bgp_cmp(const struct bmp_bgp *a, const struct bmp_bgp *b) { @@ -89,7 +89,7 @@ static uint32_t bmp_bgp_hash(const struct bmp_bgp *e) return jhash(&e->bgp, sizeof(e->bgp), 0x55aa5a5a); } -DECLARE_HASH(bmp_bgph, struct bmp_bgp, bbi, bmp_bgp_cmp, bmp_bgp_hash) +DECLARE_HASH(bmp_bgph, struct bmp_bgp, bbi, bmp_bgp_cmp, bmp_bgp_hash); struct bmp_bgph_head bmp_bgph; @@ -109,11 +109,11 @@ static uint32_t bmp_bgp_peer_hash(const struct bmp_bgp_peer *e) } DECLARE_HASH(bmp_peerh, struct bmp_bgp_peer, bpi, - bmp_bgp_peer_cmp, bmp_bgp_peer_hash) + bmp_bgp_peer_cmp, bmp_bgp_peer_hash); struct bmp_peerh_head bmp_peerh; -DECLARE_LIST(bmp_mirrorq, struct bmp_mirrorq, bmi) +DECLARE_LIST(bmp_mirrorq, struct bmp_mirrorq, bmi); /* listener management */ @@ -132,7 +132,8 @@ static int bmp_listener_cmp(const struct bmp_listener *a, return 0; } -DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli, bmp_listener_cmp) +DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli, + bmp_listener_cmp); static int bmp_targets_cmp(const struct bmp_targets *a, const struct bmp_targets *b) @@ -140,11 +141,11 @@ static int bmp_targets_cmp(const struct bmp_targets *a, return strcmp(a->name, b->name); } -DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp) +DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp); -DECLARE_LIST(bmp_session, struct bmp, bsi) +DECLARE_LIST(bmp_session, struct bmp, bsi); -DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli) +DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli); static int bmp_qhash_cmp(const struct bmp_queue_entry *a, const struct bmp_queue_entry *b) @@ -189,7 +190,7 @@ static uint32_t bmp_qhash_hkey(const struct bmp_queue_entry *e) } DECLARE_HASH(bmp_qhash, struct bmp_queue_entry, bhi, - bmp_qhash_cmp, bmp_qhash_hkey) + bmp_qhash_cmp, bmp_qhash_hkey); static int bmp_active_cmp(const struct bmp_active *a, const struct bmp_active *b) @@ -206,7 +207,7 @@ static int bmp_active_cmp(const struct bmp_active *a, return 0; } -DECLARE_SORTLIST_UNIQ(bmp_actives, struct bmp_active, bai, bmp_active_cmp) +DECLARE_SORTLIST_UNIQ(bmp_actives, struct bmp_active, bai, bmp_active_cmp); static struct bmp *bmp_new(struct bmp_targets *bt, int bmp_sock) { @@ -2443,4 +2444,5 @@ static int bgp_bmp_module_init(void) FRR_MODULE_SETUP(.name = "bgpd_bmp", .version = FRR_VERSION, .description = "bgpd BMP module", - .init = bgp_bmp_module_init) + .init = bgp_bmp_module_init, +); diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index 2c3ba570ee..899840e582 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -66,8 +66,8 @@ * always happens from the front of the queue.) */ -PREDECL_DLIST(bmp_qlist) -PREDECL_HASH(bmp_qhash) +PREDECL_DLIST(bmp_qlist); +PREDECL_HASH(bmp_qhash); struct bmp_queue_entry { struct bmp_qlist_item bli; @@ -92,7 +92,7 @@ struct bmp_queue_entry { * with a size limit. Refcount works the same as for monitoring above. */ -PREDECL_LIST(bmp_mirrorq) +PREDECL_LIST(bmp_mirrorq); struct bmp_mirrorq { struct bmp_mirrorq_item bmi; @@ -112,7 +112,7 @@ enum { BMP_AFI_LIVE, }; -PREDECL_LIST(bmp_session) +PREDECL_LIST(bmp_session); struct bmp_active; struct bmp_targets; @@ -166,7 +166,7 @@ struct bmp { * succeeds, "bmp" is set up. */ -PREDECL_SORTLIST_UNIQ(bmp_actives) +PREDECL_SORTLIST_UNIQ(bmp_actives); #define BMP_DFLT_MINRETRY 30000 #define BMP_DFLT_MAXRETRY 720000 @@ -191,7 +191,7 @@ struct bmp_active { }; /* config & state for passive / listening sockets */ -PREDECL_SORTLIST_UNIQ(bmp_listeners) +PREDECL_SORTLIST_UNIQ(bmp_listeners); struct bmp_listener { struct bmp_listeners_item bli; @@ -209,7 +209,7 @@ struct bmp_listener { * bmp_active items. If they have the same config, BMP session should be * put in the same targets since that's a bit more effective. */ -PREDECL_SORTLIST_UNIQ(bmp_targets) +PREDECL_SORTLIST_UNIQ(bmp_targets); struct bmp_targets { struct bmp_targets_item bti; @@ -245,13 +245,13 @@ struct bmp_targets { uint64_t cnt_accept, cnt_aclrefused; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(bmp_targets) +DECLARE_QOBJ_TYPE(bmp_targets); /* per struct peer * data. Lookup by peer->qobj_node.nid, created on demand, * deleted in peer_backward hook. */ -PREDECL_HASH(bmp_peerh) +PREDECL_HASH(bmp_peerh); struct bmp_bgp_peer { struct bmp_peerh_item bpi; @@ -267,7 +267,7 @@ struct bmp_bgp_peer { }; /* per struct bgp * data */ -PREDECL_HASH(bmp_bgph) +PREDECL_HASH(bmp_bgph); #define BMP_PEER_DOWN_NO_RELEVANT_EVENT_CODE 0x00 @@ -309,6 +309,6 @@ enum { BMP_STATS_FRR_NH_INVALID = 65531, }; -DECLARE_MGROUP(BMP) +DECLARE_MGROUP(BMP); #endif /*_BGP_BMP_H_*/ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 3afa6eaf09..ce1b7b552b 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -21,6 +21,7 @@ #include <zebra.h> #include <lib/version.h> +#include "lib/bfd.h" #include "lib/printfrr.h" #include "prefix.h" #include "linklist.h" @@ -67,6 +68,7 @@ unsigned long conf_bgp_debug_labelpool; unsigned long conf_bgp_debug_pbr; unsigned long conf_bgp_debug_graceful_restart; unsigned long conf_bgp_debug_evpn_mh; +unsigned long conf_bgp_debug_bfd; unsigned long term_bgp_debug_as4; unsigned long term_bgp_debug_neighbor_events; @@ -86,6 +88,7 @@ unsigned long term_bgp_debug_labelpool; unsigned long term_bgp_debug_pbr; unsigned long term_bgp_debug_graceful_restart; unsigned long term_bgp_debug_evpn_mh; +unsigned long term_bgp_debug_bfd; struct list *bgp_debug_neighbor_events_peers = NULL; struct list *bgp_debug_keepalive_peers = NULL; @@ -2093,6 +2096,31 @@ DEFUN (no_debug_bgp_labelpool, return CMD_SUCCESS; } +DEFPY(debug_bgp_bfd, debug_bgp_bfd_cmd, + "[no] debug bgp bfd", + NO_STR + DEBUG_STR + BGP_STR + "Bidirection Forwarding Detection\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) { + DEBUG_OFF(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(false); + } else { + DEBUG_ON(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(true); + } + } else { + if (no) + TERM_DEBUG_OFF(bfd, BFD_LIB); + else + TERM_DEBUG_ON(bfd, BFD_LIB); + } + + return CMD_SUCCESS; +} + DEFUN (no_debug_bgp, no_debug_bgp_cmd, "no debug bgp", @@ -2136,6 +2164,7 @@ DEFUN (no_debug_bgp, TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART); TERM_DEBUG_OFF(evpn_mh, EVPN_MH_ES); TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT); + TERM_DEBUG_OFF(bfd, BFD_LIB); vty_out(vty, "All possible debugging has been turned off\n"); @@ -2225,6 +2254,9 @@ DEFUN_NOSH (show_debugging_bgp, if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) vty_out(vty, " BGP EVPN-MH route debugging is on\n"); + if (BGP_DEBUG(bfd, BFD_LIB)) + vty_out(vty, " BGP BFD library debugging is on\n"); + vty_out(vty, "\n"); return CMD_SUCCESS; } @@ -2350,6 +2382,11 @@ static int bgp_config_write_debug(struct vty *vty) write++; } + if (CONF_BGP_DEBUG(bfd, BFD_LIB)) { + vty_out(vty, "debug bgp bfd\n"); + write++; + } + return write; } @@ -2478,6 +2515,10 @@ void bgp_debug_init(void) install_element(ENABLE_NODE, &debug_bgp_evpn_mh_cmd); install_element(CONFIG_NODE, &debug_bgp_evpn_mh_cmd); + + /* debug bgp bfd */ + install_element(ENABLE_NODE, &debug_bgp_bfd_cmd); + install_element(CONFIG_NODE, &debug_bgp_bfd_cmd); } /* Return true if this prefix is on the per_prefix_list of prefixes to debug diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index f16cfee4f2..fa8da1c345 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -78,6 +78,7 @@ extern unsigned long conf_bgp_debug_labelpool; extern unsigned long conf_bgp_debug_pbr; extern unsigned long conf_bgp_debug_graceful_restart; extern unsigned long conf_bgp_debug_evpn_mh; +extern unsigned long conf_bgp_debug_bfd; extern unsigned long term_bgp_debug_as4; extern unsigned long term_bgp_debug_neighbor_events; @@ -95,6 +96,7 @@ extern unsigned long term_bgp_debug_labelpool; extern unsigned long term_bgp_debug_pbr; extern unsigned long term_bgp_debug_graceful_restart; extern unsigned long term_bgp_debug_evpn_mh; +extern unsigned long term_bgp_debug_bfd; extern struct list *bgp_debug_neighbor_events_peers; extern struct list *bgp_debug_keepalive_peers; @@ -139,6 +141,8 @@ struct bgp_debug_filter { #define BGP_DEBUG_GRACEFUL_RESTART 0x01 +#define BGP_DEBUG_BFD_LIB 0x01 + #define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) #define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 7b29f1e4c9..2d4fea413a 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -57,19 +57,14 @@ /* * Definitions and external declarations. */ -DEFINE_QOBJ_TYPE(bgpevpn) -DEFINE_QOBJ_TYPE(bgp_evpn_es) +DEFINE_QOBJ_TYPE(bgpevpn); +DEFINE_QOBJ_TYPE(bgp_evpn_es); /* * Static function declarations */ static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn); -static void bgp_evpn_update_type2_route_entry(struct bgp *bgp, - struct bgpevpn *vpn, - struct bgp_dest *dest, - struct bgp_path_info *local_pi, - const char *caller); static struct in_addr zero_vtep_ip; /* @@ -1602,8 +1597,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, } } - /* MAC-IP routes in the VNI route table are linked to the - * destination ES + /* local MAC-IP routes in the VNI table are linked to + * the destination ES */ if (route_change && vpn_rt && (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)) @@ -1669,6 +1664,18 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp, evpn_zebra_reinstall_best_route(bgp, vpn, dest); } +static inline bool bgp_evpn_route_add_l3_ecomm_ok(struct bgpevpn *vpn, + const struct prefix_evpn *p, + esi_t *esi) +{ + return p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE + && (is_evpn_prefix_ipaddr_v4(p) + || !IN6_IS_ADDR_LINKLOCAL( + &p->prefix.macip_addr.ip.ipaddr_v6)) + && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS) + && bgpevpn_get_l3vni(vpn) && bgp_evpn_es_add_l3_ecomm_ok(esi); +} + /* * Create or update EVPN route (of type based on prefix) for specified VNI * and schedule for processing. @@ -1738,12 +1745,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * IPv4 or IPv6 global addresses and we're advertising L3VNI with * these routes. */ - if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && - (is_evpn_prefix_ipaddr_v4(p) || - !IN6_IS_ADDR_LINKLOCAL(&p->prefix.macip_addr.ip.ipaddr_v6)) && - CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS) && - bgpevpn_get_l3vni(vpn)) - add_l3_ecomm = 1; + add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok( + vpn, p, (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL); /* Set up extended community. */ build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm); @@ -1930,11 +1933,10 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, return 0; } -static void bgp_evpn_update_type2_route_entry(struct bgp *bgp, - struct bgpevpn *vpn, - struct bgp_dest *dest, - struct bgp_path_info *local_pi, - const char *caller) +void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, + struct bgp_dest *dest, + struct bgp_path_info *local_pi, + const char *caller) { afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; @@ -1977,12 +1979,9 @@ static void bgp_evpn_update_type2_route_entry(struct bgp *bgp, /* Add L3 VNI RTs and RMAC for non IPv6 link-local if * using L3 VNI for type-2 routes also. */ - if ((is_evpn_prefix_ipaddr_v4(evp) || - !IN6_IS_ADDR_LINKLOCAL( - &evp->prefix.macip_addr.ip.ipaddr_v6)) && - CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS) && - bgpevpn_get_l3vni(vpn)) - add_l3_ecomm = 1; + add_l3_ecomm = bgp_evpn_route_add_l3_ecomm_ok( + vpn, evp, + (attr.es_flags & ATTR_ES_IS_LOCAL) ? &attr.esi : NULL); /* Set up extended community. */ build_evpn_route_extcomm(vpn, &attr, add_l3_ecomm); @@ -2235,6 +2234,8 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) int ret; struct prefix_evpn p; + update_type1_routes_for_evi(bgp, vpn); + /* Update and advertise the type-3 route (only one) followed by the * locally learnt type-2 routes (MACIP) - for this VNI. * @@ -2377,6 +2378,8 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, afi_t afi = 0; safi_t safi = 0; bool new_pi = false; + bool use_l3nhg = false; + bool is_l3nhg_active = false; memset(pp, 0, sizeof(struct prefix)); ip_prefix_from_evpn_prefix(evp, pp); @@ -2412,6 +2415,13 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, else attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); + bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg, + &is_l3nhg_active, NULL); + if (use_l3nhg) + attr.es_flags |= ATTR_ES_L3_NHG_USE; + if (is_l3nhg_active) + attr.es_flags |= ATTR_ES_L3_NHG_ACTIVE; + /* Check if route entry is already present. */ for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (pi->extra @@ -2452,6 +2462,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* as it is an importation, change nexthop */ bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF); + /* Link path to evpn nexthop */ + bgp_evpn_path_nh_add(bgp_vrf, pi); + bgp_aggregate_increment(bgp_vrf, bgp_dest_get_prefix(dest), pi, afi, safi); @@ -2485,6 +2498,8 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct attr *attr_new; int ret; struct prefix_evpn ad_evp; + bool old_local_es = false; + bool new_local_es; /* EAD prefix in the global table doesn't include the VTEP-IP so * we need to create a different copy for the VNI @@ -2507,6 +2522,7 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, /* Create an info */ pi = bgp_create_evpn_bgp_path_info(parent_pi, dest, parent_pi->attr); + new_local_es = bgp_evpn_attr_is_local_es(pi->attr); } else { if (attrhash_cmp(pi->attr, parent_pi->attr) && !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { @@ -2525,17 +2541,29 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, if (!IPV4_ADDR_SAME(&pi->attr->nexthop, &attr_new->nexthop)) SET_FLAG(pi->flags, BGP_PATH_IGP_CHANGED); + old_local_es = bgp_evpn_attr_is_local_es(pi->attr); + new_local_es = bgp_evpn_attr_is_local_es(attr_new); + /* If ESI is different or if its type has changed we + * need to reinstall the path in zebra + */ + if ((old_local_es != new_local_es) + || memcmp(&pi->attr->esi, &attr_new->esi, + sizeof(attr_new->esi))) { + + if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) + zlog_debug("VNI %d path %pFX chg to %s es", + vpn->vni, &pi->net->p, + new_local_es ? "local" + : "non-local"); + bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED); + } + /* Unintern existing, set to new. */ bgp_attr_unintern(&pi->attr); pi->attr = attr_new; pi->uptime = bgp_clock(); } - /* MAC-IP routes in the VNI table are linked to the destination ES */ - if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) - bgp_evpn_path_es_link(pi, vpn->vni, - bgp_evpn_attr_get_esi(pi->attr)); - /* Perform route selection and update zebra, if required. */ ret = evpn_route_select_install(bgp, vpn, dest); @@ -2545,10 +2573,9 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * from sync-path to remote-path) */ local_pi = bgp_evpn_route_get_local_path(bgp, dest); - if (local_pi && bgp_evpn_attr_is_local_es(local_pi->attr)) + if (local_pi && (old_local_es || new_local_es)) bgp_evpn_update_type2_route_entry(bgp, vpn, dest, local_pi, - __func__); - + __func__); bgp_dest_unlock_node(dest); return ret; @@ -2617,6 +2644,9 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Mark entry for deletion */ bgp_path_info_delete(dest, pi); + /* Unlink path to evpn nexthop */ + bgp_evpn_path_nh_del(bgp_vrf, pi); + /* Perform route selection and update zebra, if required. */ bgp_process(bgp_vrf, dest, afi, safi); @@ -2851,11 +2881,11 @@ static int bgp_evpn_route_rmac_self_check(struct bgp *bgp_vrf, /* don't import hosts that are locally attached */ static inline bool -bgp_evpn_skip_vrf_import_of_local_es(const struct prefix_evpn *evp, +bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf, + const struct prefix_evpn *evp, struct bgp_path_info *pi, int install) { esi_t *esi; - struct in_addr nh; if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { esi = bgp_evpn_attr_get_esi(pi->attr); @@ -2873,29 +2903,51 @@ bgp_evpn_skip_vrf_import_of_local_es(const struct prefix_evpn *evp, } return true; } + } + return false; +} - /* Don't import routes with ES as destination if the nexthop - * has not been advertised via the EAD-ES - */ - if (pi->attr) - nh = pi->attr->nexthop; +/* + * Install or uninstall a mac-ip route in the provided vrf if + * there is a rt match + */ +int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf, + struct bgp_path_info *pi, + int install) +{ + int ret = 0; + const struct prefix_evpn *evp = + (const struct prefix_evpn *)bgp_dest_get_prefix(pi->net); + + /* Consider "valid" remote routes applicable for + * this VRF. + */ + if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID) + && pi->type == ZEBRA_ROUTE_BGP + && pi->sub_type == BGP_ROUTE_NORMAL)) + return 0; + + if (is_route_matching_for_vrf(bgp_vrf, pi)) { + if (bgp_evpn_route_rmac_self_check(bgp_vrf, evp, pi)) + return 0; + + /* don't import hosts that are locally attached */ + if (install + && !bgp_evpn_skip_vrf_import_of_local_es(bgp_vrf, evp, pi, + install)) + ret = install_evpn_route_entry_in_vrf(bgp_vrf, evp, pi); else - nh.s_addr = INADDR_ANY; - if (install && !bgp_evpn_es_is_vtep_active(esi, nh)) { - if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) { - char esi_buf[ESI_STR_LEN]; + ret = uninstall_evpn_route_entry_in_vrf(bgp_vrf, evp, + pi); - zlog_debug( - "vrf %s of evpn prefix %pFX skipped, nh %pI4 inactive in es %s", - install ? "import" : "unimport", evp, - &nh, - esi_to_str(esi, esi_buf, - sizeof(esi_buf))); - } - return true; - } + if (ret) + flog_err(EC_BGP_EVPN_FAIL, + "Failed to %s EVPN %pFX route in VRF %s", + install ? "install" : "uninstall", evp, + vrf_id_to_name(bgp_vrf->vrf_id)); } - return false; + + return ret; } /* @@ -2947,46 +2999,10 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { - /* Consider "valid" remote routes applicable for - * this VRF. - */ - if (!(CHECK_FLAG(pi->flags, BGP_PATH_VALID) - && pi->type == ZEBRA_ROUTE_BGP - && pi->sub_type == BGP_ROUTE_NORMAL)) - continue; - - /* don't import hosts that are locally attached - */ - if (bgp_evpn_skip_vrf_import_of_local_es( - evp, pi, install)) - continue; - - if (is_route_matching_for_vrf(bgp_vrf, pi)) { - if (bgp_evpn_route_rmac_self_check( - bgp_vrf, evp, pi)) - continue; - - if (install) - ret = install_evpn_route_entry_in_vrf( - bgp_vrf, evp, pi); - else - ret = uninstall_evpn_route_entry_in_vrf( - bgp_vrf, evp, pi); - - if (ret) { - flog_err( - EC_BGP_EVPN_FAIL, - "Failed to %s EVPN %pFX route in VRF %s", - install ? "install" - : "uninstall", - evp, - vrf_id_to_name( - bgp_vrf->vrf_id)); - bgp_dest_unlock_node(rd_dest); - bgp_dest_unlock_node(dest); - return ret; - } - } + ret = bgp_evpn_route_entry_install_if_vrf_match( + bgp_vrf, pi, install); + if (ret) + return ret; } } } @@ -3136,7 +3152,7 @@ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) return ret; ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE, - 1); + 0); if (ret) return ret; @@ -3167,14 +3183,13 @@ static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi, || is_evpn_prefix_ipaddr_v6(evp))) return 0; - /* don't import hosts that are locally attached */ - if (bgp_evpn_skip_vrf_import_of_local_es(evp, pi, install)) - return 0; - for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) { int ret; - if (install) + /* don't import hosts that are locally attached */ + if (install + && !bgp_evpn_skip_vrf_import_of_local_es(bgp_vrf, evp, pi, + install)) ret = install_evpn_route_entry_in_vrf(bgp_vrf, evp, pi); else ret = uninstall_evpn_route_entry_in_vrf(bgp_vrf, evp, @@ -3289,6 +3304,13 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi, if (sub_type != ECOMMUNITY_ROUTE_TARGET) continue; + /* non-local MAC-IP routes in the global route table are linked + * to the destination ES + */ + if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) + bgp_evpn_path_es_link(pi, 0, + bgp_evpn_attr_get_esi(pi->attr)); + /* * macip routes (type-2) are imported into VNI and VRF tables. * IMET route is imported into VNI table. @@ -3368,6 +3390,18 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi, true, true); } +void bgp_evpn_import_type2_route(struct bgp_path_info *pi, int import) +{ + struct bgp *bgp_evpn; + + bgp_evpn = bgp_get_evpn(); + if (!bgp_evpn) + return; + + install_uninstall_evpn_route(bgp_evpn, AFI_L2VPN, SAFI_EVPN, + &pi->net->p, pi, import); +} + /* Import the pi into vrf routing tables */ void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import) { @@ -3721,7 +3755,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, if (attr) { STREAM_GET(&attr->esi, pkt, sizeof(esi_t)); - if (bgp_evpn_is_esi_local(&attr->esi)) + if (bgp_evpn_is_esi_local_and_non_bypass(&attr->esi)) attr->es_flags |= ATTR_ES_IS_LOCAL; else attr->es_flags &= ~ATTR_ES_IS_LOCAL; @@ -5774,11 +5808,14 @@ void bgp_evpn_init(struct bgp *bgp) /* Default BUM handling is to do head-end replication. */ bgp->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL; + + bgp_evpn_nh_init(bgp); } void bgp_evpn_vrf_delete(struct bgp *bgp_vrf) { bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf); + bgp_evpn_nh_finish(bgp_vrf); } /* diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 29d3d2c62f..83a6dd84c8 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -206,5 +206,4 @@ extern void bgp_evpn_init(struct bgp *bgp); extern int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx); extern bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx); extern void update_advertise_vrf_routes(struct bgp *bgp_vrf); - #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 123c46f12f..868238ebdd 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -64,17 +64,20 @@ static void bgp_evpn_es_vtep_del(struct bgp *bgp, struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr); static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es); static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es); -static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi); +static struct bgp_evpn_es_evi * +bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi); static uint32_t bgp_evpn_es_get_active_vtep_cnt(struct bgp_evpn_es *es); static void bgp_evpn_l3nhg_update_on_vtep_chg(struct bgp_evpn_es *es); static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi); static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller); -static void -bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep, - bool active); +static void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info); +static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es, + bool is_local); esi_t zero_esi_buf, *zero_esi = &zero_esi_buf; static int bgp_evpn_run_consistency_checks(struct thread *t); +static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info *nh_info); +static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info); /****************************************************************************** * per-ES (Ethernet Segment) routing table @@ -970,6 +973,48 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, return 0; } +/* + * This function is called when the export RT for a VNI changes. + * Update all type-1 local routes for this VNI from VNI/ES tables and the global + * table and advertise these routes to peers. + */ + +void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn) +{ + struct prefix_evpn p; + struct bgp_evpn_es *es; + struct bgp_evpn_es_evi *es_evi; + struct bgp_evpn_es_evi *es_evi_next; + + RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head, + &vpn->es_evi_rb_tree, es_evi_next) { + es = es_evi->es; + + /* Update EAD-ES */ + if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) { + build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG, + &es->esi, es->originator_ip); + if (bgp_evpn_type1_route_update(bgp, es, NULL, &p)) + flog_err(EC_BGP_EVPN_ROUTE_CREATE, + "%u: EAD-ES route update failure for ESI %s VNI %u", + bgp->vrf_id, es->esi_str, + es_evi->vpn->vni); + } + + /* Update EAD-EVI */ + if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) { + build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG, + &es->esi, es->originator_ip); + if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn, + &p)) + flog_err(EC_BGP_EVPN_ROUTE_DELETE, + "%u: EAD-EVI route update failure for ESI %s VNI %u", + bgp->vrf_id, es->esi_str, + es_evi->vpn->vni); + } + } +} + /* Delete local Type-1 route */ static int bgp_evpn_type1_es_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, struct prefix_evpn *p) @@ -1249,8 +1294,6 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, * removed. */ bgp_evpn_l3nhg_update_on_vtep_chg(es_vtep->es); - bgp_evpn_es_path_update_on_vtep_chg(es_vtep, new_active); - /* queue up the es for background consistency checks */ bgp_evpn_es_cons_checks_pend_add(es_vtep->es); } @@ -1326,59 +1369,60 @@ static void bgp_evpn_es_vtep_del(struct bgp *bgp, bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr); } -bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh) -{ - struct bgp_evpn_es *es; - struct bgp_evpn_es_vtep *es_vtep; - struct listnode *node = NULL; - bool rc = false; - - if (!memcmp(esi, zero_esi, sizeof(*esi)) || !nh.s_addr) - return true; - - es = bgp_evpn_es_find(esi); - if (!es) - return false; - - for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { - if (es_vtep->vtep_ip.s_addr == nh.s_addr) { - if (CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE)) - rc = true; - break; - } - } - return rc; -} - /********************** ES MAC-IP paths ************************************* - * MAC-IP routes in the VNI routing table are linked to the destination - * ES for efficient updates on ES changes (such as VTEP add/del). + * 1. Local MAC-IP routes in the VNI routing table are linked to the + * destination ES (macip_evi_path_list) for efficient updates on ES oper + * state changes. + * 2. Non-local MAC-IP routes in the global routing table are linked to + * the detination for efficient updates on - + * a. VTEP add/del - this results in a L3NHG update. + * b. ES-VRF add/del - this may result in the host route being migrated to + * L3NHG or vice versa (flat multipath list). ****************************************************************************/ -void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info) +static void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info) { bgp_evpn_path_es_unlink(es_info); XFREE(MTYPE_BGP_EVPN_PATH_ES_INFO, es_info); } +void bgp_evpn_path_mh_info_free(struct bgp_path_mh_info *mh_info) +{ + if (mh_info->es_info) + bgp_evpn_path_es_info_free(mh_info->es_info); + if (mh_info->nh_info) + bgp_evpn_path_nh_info_free(mh_info->nh_info); + XFREE(MTYPE_BGP_EVPN_PATH_MH_INFO, mh_info); +} + static struct bgp_path_es_info * bgp_evpn_path_es_info_new(struct bgp_path_info *pi, vni_t vni) { struct bgp_path_info_extra *e; + struct bgp_path_mh_info *mh_info; + struct bgp_path_es_info *es_info; e = bgp_path_info_extra_get(pi); + /* If mh_info doesn't exist allocate it */ + mh_info = e->mh_info; + if (!mh_info) + e->mh_info = mh_info = XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO, + sizeof(struct bgp_path_mh_info)); + /* If es_info doesn't exist allocate it */ - if (!e->es_info) { - e->es_info = XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO, - sizeof(struct bgp_path_es_info)); - e->es_info->pi = pi; - e->es_info->vni = vni; + es_info = mh_info->es_info; + if (!es_info) { + mh_info->es_info = es_info = + XCALLOC(MTYPE_BGP_EVPN_PATH_ES_INFO, + sizeof(struct bgp_path_es_info)); + es_info->vni = vni; + es_info->pi = pi; } - return e->es_info; + return es_info; } -void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info) +static void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info) { struct bgp_evpn_es *es = es_info->es; struct bgp_path_info *pi; @@ -1391,7 +1435,13 @@ void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info) zlog_debug("vni %u path %pFX unlinked from es %s", es_info->vni, &pi->net->p, es->esi_str); - list_delete_node(es->macip_path_list, &es_info->es_listnode); + if (es_info->vni) + list_delete_node(es->macip_evi_path_list, + &es_info->es_listnode); + else + list_delete_node(es->macip_global_path_list, + &es_info->es_listnode); + es_info->es = NULL; /* if there are no other references against the ES it @@ -1408,9 +1458,11 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi) { struct bgp_path_es_info *es_info; struct bgp_evpn_es *es; - struct bgp *bgp_evpn = bgp_get_evpn(); + struct bgp *bgp_evpn; - es_info = pi->extra ? pi->extra->es_info : NULL; + es_info = (pi->extra && pi->extra->mh_info) + ? pi->extra->mh_info->es_info + : NULL; /* if the esi is zero just unlink the path from the old es */ if (!esi || !memcmp(esi, zero_esi, sizeof(*esi))) { if (es_info) @@ -1418,6 +1470,7 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi) return; } + bgp_evpn = bgp_get_evpn(); if (!bgp_evpn) return; @@ -1444,43 +1497,59 @@ void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi) /* link mac-ip path to the new destination ES */ es_info->es = es; listnode_init(&es_info->es_listnode, es_info); - listnode_add(es->macip_path_list, &es_info->es_listnode); + if (es_info->vni) + listnode_add(es->macip_evi_path_list, &es_info->es_listnode); + else + listnode_add(es->macip_global_path_list, &es_info->es_listnode); +} + +static bool bgp_evpn_is_macip_path(struct bgp_path_info *pi) +{ + struct prefix_evpn *evp; + + /* Only MAC-IP routes need to be linked (MAC-only routes can be + * skipped) as these lists are maintained for managing + * host routes in the tenant VRF + */ + evp = (struct prefix_evpn *)&pi->net->p; + return is_evpn_prefix_ipaddr_v4(evp) || is_evpn_prefix_ipaddr_v6(evp); } +/* When a remote ES is added to a VRF, routes using that as + * a destination need to be migrated to a L3NHG or viceversa. + * This is done indirectly by re-attempting an install of the + * route in the associated VRFs. As a part of the VRF install use + * of l3 NHG is evaluated and this results in the + * attr.es_flag ATTR_ES_USE_L3_NHG being set or cleared. + */ static void -bgp_evpn_es_path_update_on_vtep_chg(struct bgp_evpn_es_vtep *es_vtep, - bool active) +bgp_evpn_es_path_update_on_es_vrf_chg(struct bgp_evpn_es_vrf *es_vrf, + const char *reason) { struct listnode *node; struct bgp_path_es_info *es_info; struct bgp_path_info *pi; - struct bgp_path_info *parent_pi; - struct bgp_evpn_es *es = es_vtep->es; + struct bgp_evpn_es *es = es_vrf->es; + + if (!bgp_mh_info->host_routes_use_l3nhg) + return; if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("update paths linked to es %s on vtep chg", - es->esi_str); + zlog_debug("update paths linked to es %s on es-vrf %s %s", + es->esi_str, es_vrf->bgp_vrf->name, reason); - for (ALL_LIST_ELEMENTS_RO(es->macip_path_list, node, es_info)) { + for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) { pi = es_info->pi; - if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID)) - continue; - - if (pi->sub_type != BGP_ROUTE_IMPORTED) - continue; - - parent_pi = pi->extra ? pi->extra->parent : NULL; - if (!parent_pi || !parent_pi->attr) - continue; - if (es_vtep->vtep_ip.s_addr != parent_pi->attr->nexthop.s_addr) + if (!bgp_evpn_is_macip_path(pi)) continue; if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) zlog_debug( - "update path %pFX linked to es %s on vtep chg", - &parent_pi->net->p, es->esi_str); - bgp_evpn_import_route_in_vrfs(parent_pi, active ? 1 : 0); + "update path %pFX linked to es %s on vrf chg", + &pi->net->p, es->esi_str); + bgp_evpn_route_entry_install_if_vrf_match(es_vrf->bgp_vrf, pi, + 1); } } @@ -1537,8 +1606,10 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi) listset_app_node_mem(es->es_vrf_list); /* Initialise the route list used for efficient event handling */ - es->macip_path_list = list_new(); - listset_app_node_mem(es->macip_path_list); + es->macip_evi_path_list = list_new(); + listset_app_node_mem(es->macip_evi_path_list); + es->macip_global_path_list = list_new(); + listset_app_node_mem(es->macip_global_path_list); QOBJ_REG(es, bgp_evpn_es); @@ -1552,7 +1623,8 @@ static struct bgp_evpn_es *bgp_evpn_es_new(struct bgp *bgp, const esi_t *esi) static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller) { if ((es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) - || listcount(es->macip_path_list)) + || listcount(es->macip_evi_path_list) + || listcount(es->macip_global_path_list)) return; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) @@ -1562,7 +1634,8 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller) list_delete(&es->es_evi_list); list_delete(&es->es_vrf_list); list_delete(&es->es_vtep_list); - list_delete(&es->macip_path_list); + list_delete(&es->macip_evi_path_list); + list_delete(&es->macip_global_path_list); bgp_table_unlock(es->route_table); /* remove the entry from various databases */ @@ -1573,15 +1646,25 @@ static void bgp_evpn_es_free(struct bgp_evpn_es *es, const char *caller) XFREE(MTYPE_BGP_EVPN_ES, es); } +static inline bool bgp_evpn_is_es_local_and_non_bypass(struct bgp_evpn_es *es) +{ + return (es->flags & BGP_EVPNES_LOCAL) + && !(es->flags & BGP_EVPNES_BYPASS); +} + /* init local info associated with the ES */ static void bgp_evpn_es_local_info_set(struct bgp *bgp, struct bgp_evpn_es *es) { char buf[BGP_EVPN_PREFIX_RD_LEN]; + bool old_is_local; + bool is_local; if (CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL)) return; + old_is_local = bgp_evpn_is_es_local_and_non_bypass(es); SET_FLAG(es->flags, BGP_EVPNES_LOCAL); + listnode_init(&es->es_listnode, es); listnode_add(bgp_mh_info->local_es_list, &es->es_listnode); @@ -1591,16 +1674,28 @@ static void bgp_evpn_es_local_info_set(struct bgp *bgp, struct bgp_evpn_es *es) es->prd.prefixlen = 64; snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, es->rd_id); (void)str2prefix_rd(buf, &es->prd); + + is_local = bgp_evpn_is_es_local_and_non_bypass(es); + if (old_is_local != is_local) + bgp_evpn_mac_update_on_es_local_chg(es, is_local); } /* clear any local info associated with the ES */ -static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es *es) +static void bgp_evpn_es_local_info_clear(struct bgp_evpn_es *es, bool finish) { + bool old_is_local; + bool is_local; + if (!CHECK_FLAG(es->flags, BGP_EVPNES_LOCAL)) return; + old_is_local = bgp_evpn_is_es_local_and_non_bypass(es); UNSET_FLAG(es->flags, BGP_EVPNES_LOCAL); + is_local = bgp_evpn_is_es_local_and_non_bypass(es); + if (!finish && (old_is_local != is_local)) + bgp_evpn_mac_update_on_es_local_chg(es, is_local); + /* remove from the ES local list */ list_delete_node(bgp_mh_info->local_es_list, &es->es_listnode); @@ -1622,10 +1717,127 @@ static void bgp_evpn_es_remote_info_re_eval(struct bgp_evpn_es *es) } } -static inline bool bgp_evpn_local_es_is_active(struct bgp_evpn_es *es) +/* If ES is present and local it needs to be active/oper-up for + * including L3 EC + */ +bool bgp_evpn_es_add_l3_ecomm_ok(esi_t *esi) { - return (es->flags & BGP_EVPNES_OPER_UP) - && !(es->flags & BGP_EVPNES_BYPASS); + struct bgp_evpn_es *es; + + if (!esi || !bgp_mh_info->suppress_l3_ecomm_on_inactive_es) + return true; + + es = bgp_evpn_es_find(esi); + + return (!es || !(es->flags & BGP_EVPNES_LOCAL) + || bgp_evpn_local_es_is_active(es)); +} + +static bool bgp_evpn_is_valid_local_path(struct bgp_path_info *pi) +{ + return (CHECK_FLAG(pi->flags, BGP_PATH_VALID) + && pi->type == ZEBRA_ROUTE_BGP + && pi->sub_type == BGP_ROUTE_STATIC); +} + +/* Update all local MAC-IP routes in the VNI routing table associated + * with the ES. When the ES is down the routes are advertised without + * the L3 extcomm + */ +static void bgp_evpn_mac_update_on_es_oper_chg(struct bgp_evpn_es *es) +{ + struct listnode *node; + struct bgp_path_es_info *es_info; + struct bgp_path_info *pi; + struct bgp *bgp; + struct bgpevpn *vpn; + + if (!bgp_mh_info->suppress_l3_ecomm_on_inactive_es) + return; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("update paths linked to es %s on oper chg", + es->esi_str); + + bgp = bgp_get_evpn(); + for (ALL_LIST_ELEMENTS_RO(es->macip_evi_path_list, node, es_info)) { + pi = es_info->pi; + + if (!bgp_evpn_is_valid_local_path(pi)) + continue; + + if (!bgp_evpn_is_macip_path(pi)) + continue; + + vpn = bgp_evpn_lookup_vni(bgp, es_info->vni); + if (!vpn) + continue; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) + zlog_debug( + "update path %d %pFX linked to es %s on oper chg", + es_info->vni, &pi->net->p, es->esi_str); + + bgp_evpn_update_type2_route_entry(bgp, vpn, pi->net, pi, + __func__); + } +} + +static bool bgp_evpn_is_valid_bgp_path(struct bgp_path_info *pi) +{ + return (CHECK_FLAG(pi->flags, BGP_PATH_VALID) + && pi->type == ZEBRA_ROUTE_BGP + && pi->sub_type == BGP_ROUTE_NORMAL); +} + +/* If an ES is no longer local (or becomes local) we need to re-install + * paths using that ES as destination. This is needed as the criteria + * for best path selection has changed. + */ +static void bgp_evpn_mac_update_on_es_local_chg(struct bgp_evpn_es *es, + bool is_local) +{ + struct listnode *node; + struct bgp_path_es_info *es_info; + struct bgp_path_info *pi; + bool tmp_local; + struct attr *attr_new; + struct attr attr_tmp; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("update paths linked to es %s on chg to %s", + es->esi_str, is_local ? "local" : "non-local"); + + for (ALL_LIST_ELEMENTS_RO(es->macip_global_path_list, node, es_info)) { + pi = es_info->pi; + + /* Consider "valid" remote routes */ + if (!bgp_evpn_is_valid_bgp_path(pi)) + continue; + + if (!pi->attr) + continue; + + tmp_local = !!(pi->attr->es_flags & ATTR_ES_IS_LOCAL); + if (tmp_local == is_local) + continue; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) + zlog_debug( + "update path %pFX linked to es %s on chg to %s", + &pi->net->p, es->esi_str, + is_local ? "local" : "non-local"); + + attr_tmp = *pi->attr; + if (is_local) + attr_tmp.es_flags |= ATTR_ES_IS_LOCAL; + else + attr_tmp.es_flags &= ~ATTR_ES_IS_LOCAL; + attr_new = bgp_attr_intern(&attr_tmp); + bgp_attr_unintern(&pi->attr); + pi->attr = attr_new; + bgp_evpn_import_type2_route(pi, 1); + } } static void bgp_evpn_local_es_deactivate(struct bgp *bgp, @@ -1657,6 +1869,8 @@ static void bgp_evpn_local_es_deactivate(struct bgp *bgp, "%u failed to delete type-1 route for ESI %s", bgp->vrf_id, es->esi_str); } + + bgp_evpn_mac_update_on_es_oper_chg(es); } /* Process ES link oper-down by withdrawing ES-EAD and ESR */ @@ -1704,6 +1918,8 @@ static void bgp_evpn_local_es_activate(struct bgp *bgp, struct bgp_evpn_es *es, es->originator_ip); (void)bgp_evpn_type1_route_update(bgp, es, NULL, &p); } + + bgp_evpn_mac_update_on_es_oper_chg(es); } /* Process ES link oper-up by generating ES-EAD and ESR */ @@ -1738,11 +1954,14 @@ static void bgp_evpn_local_es_bypass_update(struct bgp *bgp, bool old_bypass = !!(es->flags & BGP_EVPNES_BYPASS); bool old_active; bool new_active; + bool old_is_local; + bool is_local; if (bypass == old_bypass) return; old_active = bgp_evpn_local_es_is_active(es); + old_is_local = bgp_evpn_is_es_local_and_non_bypass(es); if (bypass) SET_FLAG(es->flags, BGP_EVPNES_BYPASS); else @@ -1759,6 +1978,10 @@ static void bgp_evpn_local_es_bypass_update(struct bgp *bgp, else bgp_evpn_local_es_deactivate(bgp, es); } + + is_local = bgp_evpn_is_es_local_and_non_bypass(es); + if (old_is_local != is_local) + bgp_evpn_mac_update_on_es_local_chg(es, is_local); } static void bgp_evpn_local_es_do_del(struct bgp *bgp, struct bgp_evpn_es *es) @@ -1783,16 +2006,17 @@ static void bgp_evpn_local_es_do_del(struct bgp *bgp, struct bgp_evpn_es *es) /* Clear local info associated with the ES and free it up if there is * no remote reference */ - bgp_evpn_es_local_info_clear(es); + bgp_evpn_es_local_info_clear(es, false); } -bool bgp_evpn_is_esi_local(esi_t *esi) +bool bgp_evpn_is_esi_local_and_non_bypass(esi_t *esi) { struct bgp_evpn_es *es = NULL; /* Lookup ESI hash - should exist. */ es = bgp_evpn_es_find(esi); - return es ? !!(es->flags & BGP_EVPNES_LOCAL) : false; + + return es && bgp_evpn_is_es_local_and_non_bypass(es); } int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi) @@ -2072,7 +2296,9 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, json_object_int_add(json, "vrfCount", listcount(es->es_vrf_list)); json_object_int_add(json, "macipPathCount", - listcount(es->macip_path_list)); + listcount(es->macip_evi_path_list)); + json_object_int_add(json, "macipGlobalPathCount", + listcount(es->macip_global_path_list)); json_object_int_add(json, "inconsistentVniVtepCount", es->incons_evi_vtep_cnt); if (listcount(es->es_vtep_list)) { @@ -2120,8 +2346,10 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, vty_out(vty, " Remote VNI Count: %d\n", es->remote_es_evi_cnt); vty_out(vty, " VRF Count: %d\n", listcount(es->es_vrf_list)); - vty_out(vty, " MACIP Path Count: %d\n", - listcount(es->macip_path_list)); + vty_out(vty, " MACIP EVI Path Count: %d\n", + listcount(es->macip_evi_path_list)); + vty_out(vty, " MACIP Global Path Count: %d\n", + listcount(es->macip_global_path_list)); vty_out(vty, " Inconsistent VNI VTEP Count: %d\n", es->incons_evi_vtep_cnt); if (es->inconsistencies) { @@ -2352,6 +2580,8 @@ static void bgp_evpn_l3nhg_deactivate(struct bgp_evpn_es_vrf *es_vrf) es_vrf->nhg_id); bgp_evpn_l3nhg_zebra_del(es_vrf); es_vrf->flags &= ~BGP_EVPNES_VRF_NHG_ACTIVE; + /* MAC-IPs can now be installed via the L3NHG */ + bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg-deactivate"); } static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update) @@ -2370,6 +2600,8 @@ static void bgp_evpn_l3nhg_activate(struct bgp_evpn_es_vrf *es_vrf, bool update) es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id, es_vrf->nhg_id); es_vrf->flags |= BGP_EVPNES_VRF_NHG_ACTIVE; + /* MAC-IPs can now be installed via the L3NHG */ + bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "l3nhg_activate"); } bgp_evpn_l3nhg_zebra_add(es_vrf); @@ -2446,6 +2678,11 @@ static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es, bgp_vrf->vrf_id, es_vrf->nhg_id, es_vrf->v6_nhg_id); bgp_evpn_l3nhg_activate(es_vrf, false /* update */); + /* update paths in the VRF that may already be associated with + * this destination ES + */ + bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "es-vrf-create"); + return es_vrf; } @@ -2474,6 +2711,11 @@ static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf) /* remove from the VRF-ESI rb tree */ RB_REMOVE(bgp_es_vrf_rb_head, &bgp_vrf->es_vrf_rb_tree, es_vrf); + /* update paths in the VRF that may already be associated with + * this destination ES + */ + bgp_evpn_es_path_update_on_es_vrf_chg(es_vrf, "es-vrf-delete"); + XFREE(MTYPE_BGP_EVPN_ES_VRF, es_vrf); } @@ -2556,22 +2798,56 @@ void bgp_evpn_es_evi_vrf_ref(struct bgpevpn *vpn) bgp_evpn_es_vrf_ref(es_evi, vpn->bgp_vrf); } +/* 1. If ES-VRF is not present install the host route with the exploded/flat + * multi-path list. + * 2. If ES-VRF is present - + * - if L3NHG has not been activated for the ES-VRF (this could be because + * all the PEs attached to the VRF are down) do not install the route + * in zebra. + * - if L3NHG has been activated install the route via that L3NHG + */ +void bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi, bool *use_l3nhg, + bool *is_l3nhg_active, + struct bgp_evpn_es_vrf **es_vrf_p) +{ + struct bgp_evpn_es *es; + struct bgp_evpn_es_vrf *es_vrf; + + if (!bgp_mh_info->host_routes_use_l3nhg) + return; + + es = bgp_evpn_es_find(esi); + if (!es) + return; + + es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf); + if (!es_vrf) + return; + + *use_l3nhg = true; + if (es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE) + *is_l3nhg_active = true; + if (es_vrf_p) + *es_vrf_p = es_vrf; +} + /* returns false if legacy-exploded mp needs to be used for route install */ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi, uint32_t *nhg_p) { esi_t *esi; - struct bgp_evpn_es *es; - struct bgp_evpn_es_vrf *es_vrf; + struct bgp_evpn_es_vrf *es_vrf = NULL; struct bgp_path_info *parent_pi; struct bgp_node *rn; struct prefix_evpn *evp; struct bgp_path_info *mpinfo; + bool use_l3nhg = false; + bool is_l3nhg_active = false; *nhg_p = 0; - /* L3NHG support is disabled, use legacy-exploded multipath */ - if (!bgp_mh_info->host_routes_use_l3nhg) + /* we don't support NHG for routes leaked from another VRF yet */ + if (pi->extra && pi->extra->bgp_orig) return false; parent_pi = get_route_parent_evpn(pi); @@ -2591,15 +2867,17 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi, if (!memcmp(esi, zero_esi, sizeof(*esi))) return false; - /* if the ES-VRF is not setup or if the NHG has not been installed - * we cannot install the route yet, return a 0-NHG to indicate - * that + bgp_evpn_es_vrf_use_nhg(bgp_vrf, esi, &use_l3nhg, &is_l3nhg_active, + &es_vrf); + + /* L3NHG support is disabled, use legacy-exploded multipath */ + if (!use_l3nhg) + return false; + + /* if the NHG has not been installed we cannot install the route yet, + * return a 0-NHG to indicate that */ - es = bgp_evpn_es_find(esi); - if (!es) - return true; - es_vrf = bgp_evpn_es_vrf_find(es, bgp_vrf); - if (!es_vrf || !(es_vrf->flags & BGP_EVPNES_VRF_NHG_ACTIVE)) + if (!is_l3nhg_active) return true; /* this needs to be set the v6NHG if v6route */ @@ -2610,7 +2888,7 @@ bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi, for (mpinfo = bgp_path_info_mpath_next(pi); mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) { - /* if any of the paths of have a different ESI we can't use + /* if any of the paths have a different ESI we can't use * the NHG associated with the ES. fallback to legacy-exploded * multipath */ @@ -2946,7 +3224,8 @@ static struct bgp_evpn_es_evi *bgp_evpn_es_evi_new(struct bgp_evpn_es *es, /* remove the ES-EVI from the per-L2-VNI and per-ES tables and free * up the memory. */ -static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi) +static struct bgp_evpn_es_evi * +bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi) { struct bgp_evpn_es *es = es_evi->es; struct bgpevpn *vpn = es_evi->vpn; @@ -2955,7 +3234,7 @@ static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi) * reference */ if (es_evi->flags & (BGP_EVPNES_EVI_LOCAL | BGP_EVPNES_EVI_REMOTE)) - return; + return es_evi; bgp_evpn_es_vrf_deref(es_evi); @@ -2970,6 +3249,8 @@ static void bgp_evpn_es_evi_free(struct bgp_evpn_es_evi *es_evi) /* remove from the VNI-ESI rb tree */ XFREE(MTYPE_BGP_EVPN_ES_EVI, es_evi); + + return NULL; } /* init local info associated with the ES-EVI */ @@ -2986,17 +3267,18 @@ static void bgp_evpn_es_evi_local_info_set(struct bgp_evpn_es_evi *es_evi) } /* clear any local info associated with the ES-EVI */ -static void bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi *es_evi) +static struct bgp_evpn_es_evi * +bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi *es_evi) { struct bgpevpn *vpn = es_evi->vpn; if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL)) - return; + return es_evi; UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL); list_delete_node(vpn->local_es_evi_list, &es_evi->l2vni_listnode); - bgp_evpn_es_evi_free(es_evi); + return bgp_evpn_es_evi_free(es_evi); } /* eval remote info associated with the ES */ @@ -3026,14 +3308,15 @@ static void bgp_evpn_es_evi_remote_info_re_eval(struct bgp_evpn_es_evi *es_evi) } } -static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi) +static struct bgp_evpn_es_evi * +bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi) { struct prefix_evpn p; struct bgp_evpn_es *es = es_evi->es; struct bgp *bgp; if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL)) - return; + return es_evi; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("del local es %s evi %u", @@ -3067,8 +3350,7 @@ static void bgp_evpn_local_es_evi_do_del(struct bgp_evpn_es_evi *es_evi) } } - bgp_evpn_es_evi_local_info_clear(es_evi); - + return bgp_evpn_es_evi_local_info_clear(es_evi); } int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni) @@ -3284,6 +3566,30 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, return 0; } +/* If a VNI is being deleted we need to force del all remote VTEPs */ +static void bgp_evpn_remote_es_evi_flush(struct bgp_evpn_es_evi *es_evi) +{ + struct listnode *node = NULL; + struct listnode *nnode = NULL; + struct bgp_evpn_es_evi_vtep *evi_vtep; + struct bgp *bgp; + + bgp = bgp_get_evpn(); + if (!bgp) + return; + + /* delete all VTEPs */ + for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list, node, nnode, + evi_vtep)) { + evi_vtep->flags &= ~(BGP_EVPN_EVI_VTEP_EAD_PER_ES + | BGP_EVPN_EVI_VTEP_EAD_PER_EVI); + bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); + bgp_evpn_es_evi_vtep_free(evi_vtep); + } + /* delete the EVI */ + bgp_evpn_es_evi_remote_info_re_eval(es_evi); +} + /* Initialize the ES tables maintained per-L2_VNI */ void bgp_evpn_vni_es_init(struct bgpevpn *vpn) { @@ -3303,7 +3609,9 @@ void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn) RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head, &vpn->es_evi_rb_tree, es_evi_next) { - bgp_evpn_local_es_evi_do_del(es_evi); + es_evi = bgp_evpn_local_es_evi_do_del(es_evi); + if (es_evi) + bgp_evpn_remote_es_evi_flush(es_evi); } list_delete(&vpn->local_es_evi_list); @@ -3802,6 +4110,507 @@ static int bgp_evpn_run_consistency_checks(struct thread *t) return 0; } +/***************************************************************************** + * EVPN-Nexthop and RMAC management: nexthops associated with Type-2 routes + * that have an ES as destination are consolidated by BGP into a per-VRF + * nh->rmac mapping which is sent to zebra. Zebra installs the nexthop + * as a remote neigh/fdb entry with a dummy (type-1) prefix referencing it. + * + * This handling is needed because Type-2 routes with ES as dest use NHG + * that is setup using EAD routes (i.e. such NHGs do not include the + * RMAC info). + ****************************************************************************/ +static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add) +{ + struct stream *s; + struct bgp *bgp_vrf = nh->bgp_vrf; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp_vrf)) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("No zebra instance, not %s remote nh %s", + add ? "adding" : "deleting", nh->nh_str); + return; + } + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header( + s, add ? ZEBRA_EVPN_REMOTE_NH_ADD : ZEBRA_EVPN_REMOTE_NH_DEL, + bgp_vrf->vrf_id); + stream_putl(s, bgp_vrf->vrf_id); + stream_put(s, &nh->ip, sizeof(nh->ip)); + if (add) + stream_put(s, &nh->rmac, sizeof(nh->rmac)); + + stream_putw_at(s, 0, stream_get_endp(s)); + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) { + if (add) + zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra", + nh->bgp_vrf->name, nh->nh_str, &nh->rmac); + else if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("evpn vrf %s nh %s del to zebra", + nh->bgp_vrf->name, nh->nh_str); + } + + zclient_send_message(zclient); +} + +static void bgp_evpn_nh_zebra_update(struct bgp_evpn_nh *nh, bool add) +{ + if (add && !is_zero_mac(&nh->rmac)) { + nh->flags |= BGP_EVPN_NH_READY_FOR_ZEBRA; + bgp_evpn_nh_zebra_update_send(nh, true); + } else { + if (!(nh->flags & BGP_EVPN_NH_READY_FOR_ZEBRA)) + return; + nh->flags &= ~BGP_EVPN_NH_READY_FOR_ZEBRA; + bgp_evpn_nh_zebra_update_send(nh, false); + } +} + +static void *bgp_evpn_nh_alloc(void *p) +{ + struct bgp_evpn_nh *tmp_n = p; + struct bgp_evpn_nh *n; + + n = XCALLOC(MTYPE_BGP_EVPN_NH, sizeof(struct bgp_evpn_nh)); + *n = *tmp_n; + + return ((void *)n); +} + +static struct bgp_evpn_nh *bgp_evpn_nh_find(struct bgp *bgp_vrf, + struct ipaddr *ip) +{ + struct bgp_evpn_nh tmp; + struct bgp_evpn_nh *n; + + memset(&tmp, 0, sizeof(tmp)); + memcpy(&tmp.ip, ip, sizeof(struct ipaddr)); + n = hash_lookup(bgp_vrf->evpn_nh_table, &tmp); + + return n; +} + +/* Add nexthop entry - implicitly created on first path reference */ +static struct bgp_evpn_nh *bgp_evpn_nh_add(struct bgp *bgp_vrf, + struct ipaddr *ip, + struct bgp_path_info *pi) +{ + struct bgp_evpn_nh tmp_n; + struct bgp_evpn_nh *n = NULL; + + memset(&tmp_n, 0, sizeof(struct bgp_evpn_nh)); + memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr)); + n = hash_get(bgp_vrf->evpn_nh_table, &tmp_n, bgp_evpn_nh_alloc); + ipaddr2str(ip, n->nh_str, sizeof(n->nh_str)); + n->bgp_vrf = bgp_vrf; + + n->pi_list = list_new(); + listset_app_node_mem(n->pi_list); + + /* Setup ref_pi when the nh is created */ + if (CHECK_FLAG(pi->flags, BGP_PATH_VALID) && pi->attr) { + n->ref_pi = pi; + memcpy(&n->rmac, &pi->attr->rmac, ETH_ALEN); + } + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("evpn vrf %s nh %s rmac %pEA add", n->bgp_vrf->name, + n->nh_str, &n->rmac); + bgp_evpn_nh_zebra_update(n, true); + return n; +} + +/* Delete nexthop entry if there are no paths referencing it */ +static void bgp_evpn_nh_del(struct bgp_evpn_nh *n) +{ + struct bgp_evpn_nh *tmp_n; + struct bgp *bgp_vrf = n->bgp_vrf; + + if (listcount(n->pi_list)) + return; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("evpn vrf %s nh %s del to zebra", bgp_vrf->name, + n->nh_str); + + bgp_evpn_nh_zebra_update(n, false); + list_delete(&n->pi_list); + tmp_n = hash_release(bgp_vrf->evpn_nh_table, n); + XFREE(MTYPE_BGP_EVPN_NH, tmp_n); +} + +static unsigned int bgp_evpn_nh_hash_keymake(const void *p) +{ + const struct bgp_evpn_nh *n = p; + const struct ipaddr *ip = &n->ip; + + if (IS_IPADDR_V4(ip)) + return jhash_1word(ip->ipaddr_v4.s_addr, 0); + + return jhash2(ip->ipaddr_v6.s6_addr32, + array_size(ip->ipaddr_v6.s6_addr32), 0); +} + +static bool bgp_evpn_nh_cmp(const void *p1, const void *p2) +{ + const struct bgp_evpn_nh *n1 = p1; + const struct bgp_evpn_nh *n2 = p2; + + if (n1 == NULL && n2 == NULL) + return true; + + if (n1 == NULL || n2 == NULL) + return false; + + return (memcmp(&n1->ip, &n2->ip, sizeof(struct ipaddr)) == 0); +} + +void bgp_evpn_nh_init(struct bgp *bgp_vrf) +{ + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("evpn vrf %s nh init", bgp_vrf->name); + bgp_vrf->evpn_nh_table = hash_create( + bgp_evpn_nh_hash_keymake, bgp_evpn_nh_cmp, "BGP EVPN NH table"); +} + +static void bgp_evpn_nh_flush_entry(struct bgp_evpn_nh *nh) +{ + struct listnode *node; + struct listnode *nnode; + struct bgp_path_evpn_nh_info *nh_info; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("evpn vrf %s nh %s flush", nh->bgp_vrf->name, + nh->nh_str); + + /* force flush paths */ + for (ALL_LIST_ELEMENTS(nh->pi_list, node, nnode, nh_info)) + bgp_evpn_path_nh_del(nh->bgp_vrf, nh_info->pi); +} + +static void bgp_evpn_nh_flush_cb(struct hash_bucket *bucket, void *ctxt) +{ + struct bgp_evpn_nh *nh = (struct bgp_evpn_nh *)bucket->data; + + bgp_evpn_nh_flush_entry(nh); +} + +void bgp_evpn_nh_finish(struct bgp *bgp_vrf) +{ + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("evpn vrf %s nh finish", bgp_vrf->name); + hash_iterate( + bgp_vrf->evpn_nh_table, + (void (*)(struct hash_bucket *, void *))bgp_evpn_nh_flush_cb, + NULL); + hash_free(bgp_vrf->evpn_nh_table); + bgp_vrf->evpn_nh_table = NULL; +} + +static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh *nh) +{ + struct listnode *node; + struct bgp_path_info *pi; + struct bgp_path_evpn_nh_info *nh_info; + + if (nh->ref_pi) + return; + + for (ALL_LIST_ELEMENTS_RO(nh->pi_list, node, nh_info)) { + pi = nh_info->pi; + if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID) || !pi->attr) + continue; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("evpn vrf %s nh %s ref_pi update", + nh->bgp_vrf->name, nh->nh_str); + nh->ref_pi = pi; + /* If we have a new pi copy rmac from it and update + * zebra if the new rmac is different + */ + if (memcmp(&nh->rmac, &nh->ref_pi->attr->rmac, ETH_ALEN)) { + memcpy(&nh->rmac, &nh->ref_pi->attr->rmac, ETH_ALEN); + bgp_evpn_nh_zebra_update(nh, true); + } + break; + } +} + +static void bgp_evpn_nh_clear_ref_pi(struct bgp_evpn_nh *nh, + struct bgp_path_info *pi) +{ + if (nh->ref_pi != pi) + return; + + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("evpn vrf %s nh %s ref_pi clear", nh->bgp_vrf->name, + nh->nh_str); + nh->ref_pi = NULL; + /* try to find another ref_pi */ + bgp_evpn_nh_update_ref_pi(nh); + /* couldn't find one - clear the old rmac and notify zebra */ + if (!nh->ref_pi) { + memset(&nh->rmac, 0, ETH_ALEN); + bgp_evpn_nh_zebra_update(nh, true); + } +} + +static void bgp_evpn_path_nh_info_free(struct bgp_path_evpn_nh_info *nh_info) +{ + bgp_evpn_path_nh_unlink(nh_info); + XFREE(MTYPE_BGP_EVPN_PATH_NH_INFO, nh_info); +} + +static struct bgp_path_evpn_nh_info * +bgp_evpn_path_nh_info_new(struct bgp_path_info *pi) +{ + struct bgp_path_info_extra *e; + struct bgp_path_mh_info *mh_info; + struct bgp_path_evpn_nh_info *nh_info; + + e = bgp_path_info_extra_get(pi); + + /* If mh_info doesn't exist allocate it */ + mh_info = e->mh_info; + if (!mh_info) + e->mh_info = mh_info = XCALLOC(MTYPE_BGP_EVPN_PATH_MH_INFO, + sizeof(struct bgp_path_mh_info)); + + /* If nh_info doesn't exist allocate it */ + nh_info = mh_info->nh_info; + if (!nh_info) { + mh_info->nh_info = nh_info = + XCALLOC(MTYPE_BGP_EVPN_PATH_NH_INFO, + sizeof(struct bgp_path_evpn_nh_info)); + nh_info->pi = pi; + } + + return nh_info; +} + +static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info) +{ + struct bgp_evpn_nh *nh = nh_info->nh; + struct bgp_path_info *pi; + char prefix_buf[PREFIX_STRLEN]; + + if (!nh) + return; + + pi = nh_info->pi; + if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) + zlog_debug("path %s unlinked from nh %s %s", + pi->net ? prefix2str(&pi->net->p, prefix_buf, + sizeof(prefix_buf)) + : "", + nh->bgp_vrf->name, nh->nh_str); + + list_delete_node(nh->pi_list, &nh_info->nh_listnode); + + nh_info->nh = NULL; + + /* check if the ref_pi need to be updated */ + bgp_evpn_nh_clear_ref_pi(nh, pi); + + /* if there are no other references against the nh it + * needs to be freed + */ + bgp_evpn_nh_del(nh); + + /* Note we don't free the path nh_info on unlink; it will be freed up + * along with the path. + */ +} + +static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) +{ + struct bgp_path_evpn_nh_info *nh_info; + struct bgp_evpn_nh *nh; + struct ipaddr ip; + + /* EVPN nexthop setup in bgp has been turned off */ + if (!bgp_mh_info->bgp_evpn_nh_setup) + return; + + if (!bgp_vrf->evpn_nh_table) { + if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) + zlog_debug("path %pFX linked to vrf %s failed", + &pi->net->p, bgp_vrf->name); + return; + } + + nh_info = (pi->extra && pi->extra->mh_info) + ? pi->extra->mh_info->nh_info + : NULL; + + /* if NHG is not being used for this path we don't need to manage the + * nexthops in bgp (they are managed by zebra instead) + */ + if (!(pi->attr->es_flags & ATTR_ES_L3_NHG_USE)) { + if (nh_info) + bgp_evpn_path_nh_unlink(nh_info); + return; + } + + /* setup nh_info against the path if it doesn't aleady exist */ + if (!nh_info) + nh_info = bgp_evpn_path_nh_info_new(pi); + + /* find-create nh */ + memset(&ip, 0, sizeof(ip)); + if (pi->net->p.family == AF_INET6) { + SET_IPADDR_V6(&ip); + memcpy(&ip.ipaddr_v6, &pi->attr->mp_nexthop_global, + sizeof(ip.ipaddr_v6)); + } else { + SET_IPADDR_V4(&ip); + memcpy(&ip.ipaddr_v4, &pi->attr->nexthop, sizeof(ip.ipaddr_v4)); + } + + nh = bgp_evpn_nh_find(bgp_vrf, &ip); + if (!nh) + nh = bgp_evpn_nh_add(bgp_vrf, &ip, pi); + + /* dup check */ + if (nh_info->nh == nh) { + /* Check if any of the paths are now valid */ + bgp_evpn_nh_update_ref_pi(nh); + return; + } + + /* unlink old nh if any */ + bgp_evpn_path_nh_unlink(nh_info); + + if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) + zlog_debug("path %pFX linked to nh %s %s", &pi->net->p, + nh->bgp_vrf->name, nh->nh_str); + + /* link mac-ip path to the new nh */ + nh_info->nh = nh; + listnode_init(&nh_info->nh_listnode, nh_info); + listnode_add(nh->pi_list, &nh_info->nh_listnode); + /* If a new valid path got linked to the nh see if can get the rmac + * from it + */ + bgp_evpn_nh_update_ref_pi(nh); + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) { + if (!nh->ref_pi) + zlog_debug( + "path %pFX linked to nh %s %s with no valid pi", + &pi->net->p, nh->bgp_vrf->name, nh->nh_str); + } +} + +void bgp_evpn_path_nh_del(struct bgp *bgp_vrf, struct bgp_path_info *pi) +{ + struct bgp_path_evpn_nh_info *nh_info; + + nh_info = (pi->extra && pi->extra->mh_info) + ? pi->extra->mh_info->nh_info + : NULL; + + if (!nh_info) + return; + + bgp_evpn_path_nh_unlink(nh_info); +} + +void bgp_evpn_path_nh_add(struct bgp *bgp_vrf, struct bgp_path_info *pi) +{ + bgp_evpn_path_nh_link(bgp_vrf, pi); +} + +static void bgp_evpn_nh_show_entry(struct bgp_evpn_nh *nh, struct vty *vty, + json_object *json_array) +{ + json_object *json = NULL; + char mac_buf[ETHER_ADDR_STRLEN]; + char prefix_buf[PREFIX_STRLEN]; + + if (json_array) + /* create a separate json object for each ES */ + json = json_object_new_object(); + + prefix_mac2str(&nh->rmac, mac_buf, sizeof(mac_buf)); + if (nh->ref_pi && nh->ref_pi->net) + prefix2str(&nh->ref_pi->net->p, prefix_buf, sizeof(prefix_buf)); + else + prefix_buf[0] = '\0'; + if (json) { + json_object_string_add(json, "vrf", nh->bgp_vrf->name); + json_object_string_add(json, "ip", nh->nh_str); + json_object_string_add(json, "rmac", mac_buf); + json_object_string_add(json, "basePath", prefix_buf); + json_object_int_add(json, "pathCount", listcount(nh->pi_list)); + } else { + vty_out(vty, "%-15s %-15s %-17s %-10d %s\n", nh->bgp_vrf->name, + nh->nh_str, mac_buf, listcount(nh->pi_list), + prefix_buf); + } + + /* add ES to the json array */ + if (json_array) + json_object_array_add(json_array, json); +} + +struct nh_show_ctx { + struct vty *vty; + json_object *json; +}; + +static void bgp_evpn_nh_show_hash_cb(struct hash_bucket *bucket, void *ctxt) +{ + struct bgp_evpn_nh *nh = (struct bgp_evpn_nh *)bucket->data; + struct nh_show_ctx *wctx = (struct nh_show_ctx *)ctxt; + + bgp_evpn_nh_show_entry(nh, wctx->vty, wctx->json); +} + +/* Display all evpn nexthops */ +void bgp_evpn_nh_show(struct vty *vty, bool uj) +{ + json_object *json_array = NULL; + struct bgp *bgp_vrf; + struct listnode *node; + struct nh_show_ctx wctx; + + if (uj) { + /* create an array of nexthops */ + json_array = json_object_new_array(); + } else { + vty_out(vty, "%-15s %-15s %-17s %-10s %s\n", "VRF", "IP", + "RMAC", "#Paths", "Base Path"); + } + + wctx.vty = vty; + wctx.json = json_array; + + /* walk through all vrfs */ + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) { + hash_iterate(bgp_vrf->evpn_nh_table, + (void (*)(struct hash_bucket *, + void *))bgp_evpn_nh_show_hash_cb, + &wctx); + } + + /* print the array of json-ESs */ + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json_array, JSON_C_TO_STRING_PRETTY)); + json_object_free(json_array); + } +} + /*****************************************************************************/ void bgp_evpn_mh_init(void) { @@ -3824,6 +4633,8 @@ void bgp_evpn_mh_init(void) bgp_mh_info->consistency_checking = true; bgp_mh_info->install_l3nhg = false; bgp_mh_info->host_routes_use_l3nhg = BGP_EVPN_MH_USE_ES_L3NHG_DEF; + bgp_mh_info->suppress_l3_ecomm_on_inactive_es = true; + bgp_mh_info->bgp_evpn_nh_setup = true; memset(&zero_esi_buf, 0, sizeof(esi_t)); } @@ -3838,7 +4649,7 @@ void bgp_evpn_mh_finish(void) RB_FOREACH_SAFE (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree, es_next) { - bgp_evpn_es_local_info_clear(es); + bgp_evpn_es_local_info_clear(es, true); } if (bgp_mh_info->t_cons_check) thread_cancel(&bgp_mh_info->t_cons_check); diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index e5186619ff..c96de86871 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -105,8 +105,17 @@ struct bgp_evpn_es { /* List of MAC-IP VNI paths using this ES as destination - * element is bgp_path_info_extra->es_info + * Note: Only local/zebra-added MACIP paths in the VNI + * routing table are linked to this list */ - struct list *macip_path_list; + struct list *macip_evi_path_list; + + /* List of MAC-IP paths in the global routing table using this + * ES as destination - data is bgp_path_info_extra->es_info + * Note: Only non-local/imported MACIP paths in the global + * routing table are linked to this list + */ + struct list *macip_global_path_list; /* Number of remote VNIs referencing this ES */ uint32_t remote_es_evi_cnt; @@ -125,9 +134,9 @@ struct bgp_evpn_es { /* preference config for BUM-DF election. advertised via the ESR. */ uint16_t df_pref; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(bgp_evpn_es) +DECLARE_QOBJ_TYPE(bgp_evpn_es); RB_HEAD(bgp_es_rb_head, bgp_evpn_es); RB_PROTOTYPE(bgp_es_rb_head, bgp_evpn_es, rb_node, bgp_es_rb_cmp); @@ -241,6 +250,26 @@ struct bgp_evpn_es_evi_vtep { struct bgp_evpn_es_vtep *es_vtep; }; +/* A nexthop is created when a path (imported from an EVPN type-2 route) + * is added to the VRF route table using that nexthop. + * It is added on first pi reference and removed on last pi deref. + */ +struct bgp_evpn_nh { + /* backpointer to the VRF */ + struct bgp *bgp_vrf; + /* nexthop/VTEP IP */ + struct ipaddr ip; + /* description for easy logging */ + char nh_str[INET6_ADDRSTRLEN]; + struct ethaddr rmac; + /* pi from which we are pulling the nh RMAC */ + struct bgp_path_info *ref_pi; + /* List of VRF paths using this nexthop */ + struct list *pi_list; + uint8_t flags; +#define BGP_EVPN_NH_READY_FOR_ZEBRA (1 << 0) +}; + /* multihoming information stored in bgp_master */ #define bgp_mh_info (bm->mh_info) struct bgp_evpn_mh_info { @@ -273,6 +302,12 @@ struct bgp_evpn_mh_info { /* Skip EAD-EVI advertisements by turning off this knob */ bool ead_evi_tx; #define BGP_EVPN_MH_EAD_EVI_TX_DEF true + /* If the Local ES is inactive we advertise the MAC-IP without the + * L3 ecomm + */ + bool suppress_l3_ecomm_on_inactive_es; + /* Setup EVPN PE nexthops and their RMAC in bgpd */ + bool bgp_evpn_nh_setup; }; /****************************************************************************/ @@ -330,11 +365,18 @@ static inline uint32_t bgp_evpn_attr_get_df_pref(struct attr *attr) return (attr) ? attr->df_pref : 0; } +static inline bool bgp_evpn_local_es_is_active(struct bgp_evpn_es *es) +{ + return (es->flags & BGP_EVPNES_OPER_UP) + && !(es->flags & BGP_EVPNES_BYPASS); +} + /****************************************************************************/ extern int bgp_evpn_es_route_install_uninstall(struct bgp *bgp, struct bgp_evpn_es *es, afi_t afi, safi_t safi, struct prefix_evpn *evp, struct bgp_path_info *pi, int install); +extern void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn); int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi, struct attr *attr, uint8_t *pfx, int psize, uint32_t addpath_id); @@ -361,21 +403,28 @@ void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni, bool uj, bool detail); void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail); struct bgp_evpn_es *bgp_evpn_es_find(const esi_t *esi); -extern bool bgp_evpn_is_esi_local(esi_t *esi); extern void bgp_evpn_vrf_es_init(struct bgp *bgp_vrf); +extern bool bgp_evpn_is_esi_local_and_non_bypass(esi_t *esi); extern void bgp_evpn_es_vrf_deref(struct bgp_evpn_es_evi *es_evi); extern void bgp_evpn_es_vrf_ref(struct bgp_evpn_es_evi *es_evi, struct bgp *bgp_vrf); -extern void bgp_evpn_path_es_info_free(struct bgp_path_es_info *es_info); -extern void bgp_evpn_path_es_unlink(struct bgp_path_es_info *es_info); +extern void bgp_evpn_path_mh_info_free(struct bgp_path_mh_info *mh_info); extern void bgp_evpn_path_es_link(struct bgp_path_info *pi, vni_t vni, esi_t *esi); -extern bool bgp_evpn_es_is_vtep_active(esi_t *esi, struct in_addr nh); extern bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf, struct bgp_path_info *pi, uint32_t *nhg_p); extern void bgp_evpn_es_vrf_show(struct vty *vty, bool uj, struct bgp_evpn_es *es); extern void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj); extern void bgp_evpn_switch_ead_evi_rx(void); +extern bool bgp_evpn_es_add_l3_ecomm_ok(esi_t *esi); +extern void bgp_evpn_es_vrf_use_nhg(struct bgp *bgp_vrf, esi_t *esi, + bool *use_l3nhg, bool *is_l3nhg_active, + struct bgp_evpn_es_vrf **es_vrf_p); +extern void bgp_evpn_nh_init(struct bgp *bgp_vrf); +extern void bgp_evpn_nh_finish(struct bgp *bgp_vrf); +extern void bgp_evpn_nh_show(struct vty *vty, bool uj); +extern void bgp_evpn_path_nh_add(struct bgp *bgp_vrf, struct bgp_path_info *pi); +extern void bgp_evpn_path_nh_del(struct bgp *bgp_vrf, struct bgp_path_info *pi); #endif /* _FRR_BGP_EVPN_MH_H */ diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 77b3746344..debed9f68b 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -112,10 +112,10 @@ struct bgpevpn { /* List of local ESs */ struct list *local_es_evi_list; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(bgpevpn) +DECLARE_QOBJ_TYPE(bgpevpn); /* Mapping of Import RT to VNIs. * The Import RTs of all VNIs are maintained in a hash table with each @@ -631,4 +631,13 @@ bgp_global_evpn_node_lookup(struct bgp_table *table, afi_t afi, safi_t safi, const struct prefix_evpn *evp, struct prefix_rd *prd); extern void bgp_evpn_import_route_in_vrfs(struct bgp_path_info *pi, int import); +extern void bgp_evpn_update_type2_route_entry(struct bgp *bgp, + struct bgpevpn *vpn, + struct bgp_node *rn, + struct bgp_path_info *local_pi, + const char *caller); +extern int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf, + struct bgp_path_info *pi, + int install); +extern void bgp_evpn_import_type2_route(struct bgp_path_info *pi, int import); #endif /* _BGP_EVPN_PRIVATE_H */ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index b101589a79..381e6f082b 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -688,7 +688,8 @@ static void show_esi_routes(struct bgp *bgp, /* Display all MAC-IP VNI routes linked to an ES */ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, - json_object *json, int detail) + json_object *json, int detail, + bool global_table) { struct bgp_node *rn; struct bgp_path_info *pi; @@ -709,11 +710,17 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, json_paths = json_object_new_array(); RB_FOREACH (es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) { + struct list *es_list; if (esi && memcmp(esi, &es->esi, sizeof(*esi))) continue; - for (ALL_LIST_ELEMENTS_RO(es->macip_path_list, node, es_info)) { + if (global_table) + es_list = es->macip_global_path_list; + else + es_list = es->macip_evi_path_list; + + for (ALL_LIST_ELEMENTS_RO(es_list, node, es_info)) { json_object *json_path = NULL; pi = es_info->pi; @@ -734,9 +741,9 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, json_path = json_object_new_array(); if (detail) - route_vty_out_detail(vty, bgp, rn, pi, - AFI_L2VPN, SAFI_EVPN, - json_path); + route_vty_out_detail( + vty, bgp, rn, pi, AFI_L2VPN, SAFI_EVPN, + RPKI_NOT_BEING_USED, json_path); else route_vty_out(vty, &rn->p, pi, 0, SAFI_EVPN, json_path, false); @@ -758,6 +765,18 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, } } +static void bgp_evpn_show_routes_mac_ip_evi_es(struct vty *vty, esi_t *esi, + json_object *json, int detail) +{ + return bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, false); +} + +static void bgp_evpn_show_routes_mac_ip_global_es(struct vty *vty, esi_t *esi, + json_object *json, int detail) +{ + return bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true); +} + static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, struct vty *vty, struct in_addr vtep_ip, json_object *json, int detail) @@ -823,6 +842,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type, if (detail) route_vty_out_detail(vty, bgp, dest, pi, AFI_L2VPN, SAFI_EVPN, + RPKI_NOT_BEING_USED, json_path); else route_vty_out(vty, p, pi, 0, SAFI_EVPN, @@ -1377,33 +1397,43 @@ DEFUN(show_ip_bgp_l2vpn_evpn, "show [ip] bgp l2vpn evpn [json]", SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR JSON_STR) { - return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 0, + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, + SHOW_DISPLAY_STANDARD, use_json(argc, argv)); } DEFUN(show_ip_bgp_l2vpn_evpn_rd, show_ip_bgp_l2vpn_evpn_rd_cmd, - "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN [json]", + "show [ip] bgp l2vpn evpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> [json]", SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" JSON_STR) + "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" + JSON_STR) { int idx_ext_community = 0; int ret; struct prefix_rd prd; + int rd_all = 0; - argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); + argv_find(argv, argc, "all", &rd_all); + if (rd_all) + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, + NULL, SHOW_DISPLAY_STANDARD, + use_json(argc, argv)); + argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; } - return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 0, + return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, + SHOW_DISPLAY_STANDARD, use_json(argc, argv)); } @@ -1418,34 +1448,41 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_tags, "Display information about all EVPN NLRIs\n" "Display BGP tags for prefixes\n") { - return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, 1, - 0); + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, NULL, + SHOW_DISPLAY_TAGS, 0); } DEFUN(show_ip_bgp_l2vpn_evpn_rd_tags, show_ip_bgp_l2vpn_evpn_rd_tags_cmd, - "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN tags", + "show [ip] bgp l2vpn evpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> tags", SHOW_STR IP_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n") + "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" + "Display BGP tags for prefixes\n") { int idx_ext_community = 0; int ret; struct prefix_rd prd; + int rd_all = 0; - argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); + argv_find(argv, argc, "all", &rd_all); + if (rd_all) + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, + NULL, SHOW_DISPLAY_TAGS, 0); + argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; } - return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, 1, - 0); + return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_normal, NULL, + SHOW_DISPLAY_TAGS, 0); } DEFUN(show_ip_bgp_l2vpn_evpn_neighbor_routes, @@ -1511,13 +1548,13 @@ DEFUN(show_ip_bgp_l2vpn_evpn_neighbor_routes, return CMD_WARNING; } - return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, peer, 0, - uj); + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, peer, + SHOW_DISPLAY_STANDARD, uj); } DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, show_ip_bgp_l2vpn_evpn_rd_neighbor_routes_cmd, - "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> routes [json]", + "show [ip] bgp l2vpn evpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors <A.B.C.D|X:X::X:X|WORD> routes [json]", SHOW_STR IP_STR BGP_STR @@ -1525,6 +1562,7 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, EVPN_HELP_STR "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" "Detailed information on TCP and BGP neighbor connections\n" "IPv4 Neighbor to display information about\n" "IPv6 Neighbor to display information about\n" @@ -1541,6 +1579,7 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; struct bgp *bgp = NULL; + int rd_all = 0; bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, &bgp, uj); @@ -1549,20 +1588,26 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, return CMD_WARNING; } - argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); - ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); - if (!ret) { - if (uj) { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", - "Malformed Route Distinguisher"); - vty_out(vty, "%s\n", - json_object_to_json_string(json_no)); - json_object_free(json_no); - } else - vty_out(vty, "%% Malformed Route Distinguisher\n"); - return CMD_WARNING; + argv_find(argv, argc, "all", &rd_all); + if (!rd_all) { + argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", + &idx_ext_community); + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); + if (!ret) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add( + json_no, "warning", + "Malformed Route Distinguisher"); + vty_out(vty, "%s\n", + json_object_to_json_string(json_no)); + json_object_free(json_no); + } else + vty_out(vty, + "%% Malformed Route Distinguisher\n"); + return CMD_WARNING; + } } /* neighbors <A.B.C.D|X:X::X:X|WORD> */ @@ -1599,8 +1644,13 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_routes, return CMD_WARNING; } - return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, peer, 0, - uj); + + if (rd_all) + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_neighbor, + peer, SHOW_DISPLAY_STANDARD, uj); + else + return bgp_show_ethernet_vpn(vty, &prd, bgp_show_type_neighbor, + peer, SHOW_DISPLAY_STANDARD, uj); } DEFUN(show_ip_bgp_l2vpn_evpn_neighbor_advertised_routes, @@ -1674,7 +1724,7 @@ DEFUN(show_ip_bgp_l2vpn_evpn_neighbor_advertised_routes, DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes_cmd, - "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json]", + "show [ip] bgp l2vpn evpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors <A.B.C.D|X:X::X:X|WORD> advertised-routes [json]", SHOW_STR IP_STR BGP_STR @@ -1682,6 +1732,7 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, EVPN_HELP_STR "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" "Detailed information on TCP and BGP neighbor connections\n" "IPv4 Neighbor to display information about\n" "IPv6 Neighbor to display information about\n" @@ -1698,6 +1749,7 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, char *peerstr = NULL; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; + int rd_all = 0; if (uj) argc--; @@ -1712,8 +1764,6 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, return CMD_WARNING; } - argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); - /* neighbors <A.B.C.D|X:X::X:X|WORD> */ argv_find(argv, argc, "neighbors", &idx); peerstr = argv[++idx]->arg; @@ -1748,19 +1798,29 @@ DEFUN(show_ip_bgp_l2vpn_evpn_rd_neighbor_advertised_routes, return CMD_WARNING; } - ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); - if (!ret) { - if (uj) { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add(json_no, "warning", - "Malformed Route Distinguisher"); - vty_out(vty, "%s\n", - json_object_to_json_string(json_no)); - json_object_free(json_no); - } else - vty_out(vty, "%% Malformed Route Distinguisher\n"); - return CMD_WARNING; + argv_find(argv, argc, "all", &rd_all); + if (rd_all) + return show_adj_route_vpn(vty, peer, NULL, AFI_L2VPN, SAFI_EVPN, + uj); + else { + argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", + &idx_ext_community); + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); + if (!ret) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add( + json_no, "warning", + "Malformed Route Distinguisher"); + vty_out(vty, "%s\n", + json_object_to_json_string(json_no)); + json_object_free(json_no); + } else + vty_out(vty, + "%% Malformed Route Distinguisher\n"); + return CMD_WARNING; + } } return show_adj_route_vpn(vty, peer, &prd, AFI_L2VPN, SAFI_EVPN, uj); @@ -1785,7 +1845,7 @@ DEFUN(show_ip_bgp_l2vpn_evpn_all_overlay, DEFUN(show_ip_bgp_evpn_rd_overlay, show_ip_bgp_evpn_rd_overlay_cmd, - "show [ip] bgp l2vpn evpn rd ASN:NN_OR_IP-ADDRESS:NN overlay", + "show [ip] bgp l2vpn evpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> overlay", SHOW_STR IP_STR BGP_STR @@ -1793,14 +1853,21 @@ DEFUN(show_ip_bgp_evpn_rd_overlay, EVPN_HELP_STR "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" "Display BGP Overlay Information for prefixes\n") { int idx_ext_community = 0; int ret; struct prefix_rd prd; + int rd_all = 0; - argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); + argv_find(argv, argc, "all", &rd_all); + if (rd_all) + return bgp_show_ethernet_vpn(vty, NULL, bgp_show_type_normal, + NULL, SHOW_DISPLAY_OVERLAY, + use_json(argc, argv)); + argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", &idx_ext_community); ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); @@ -2367,7 +2434,8 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, pi, afi, safi, json_path); + route_vty_out_detail(vty, bgp, dest, pi, afi, safi, + RPKI_NOT_BEING_USED, json_path); if (json) json_object_array_add(json_paths, json_path); @@ -2436,7 +2504,8 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, pi, afi, safi, json_path); + route_vty_out_detail(vty, bgp, dest, pi, afi, safi, + RPKI_NOT_BEING_USED, json_path); if (json) json_object_array_add(json_paths, json_path); @@ -2541,7 +2610,8 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, if (json) json_path = json_object_new_array(); - route_vty_out_detail(vty, bgp, dest, pi, afi, safi, json_path); + route_vty_out_detail(vty, bgp, dest, pi, afi, safi, + RPKI_NOT_BEING_USED, json_path); if (json) json_object_array_add(json_paths, json_path); @@ -2651,7 +2721,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, pi, afi, safi, - json_path); + RPKI_NOT_BEING_USED, json_path); if (json) json_object_array_add(json_paths, json_path); @@ -2699,6 +2769,131 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, } /* + * Display BGP EVPN routing table -- all RDs and MAC and/or IP + * (vty handler). Only matching type-2 routes will be displayed. + */ +static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp, + struct ethaddr *mac, struct ipaddr *ip, + json_object *json) +{ + struct bgp_dest *rd_dest; + struct bgp_table *table; + struct bgp_dest *dest; + struct bgp_path_info *pi; + afi_t afi = AFI_L2VPN; + safi_t safi = SAFI_EVPN; + uint32_t prefix_cnt, path_cnt; + prefix_cnt = path_cnt = 0; + + /* EVPN routing table is a 2-level table with the first level being + * the RD. We need to look in every RD we know about. + */ + for (rd_dest = bgp_table_top(bgp->rib[afi][safi]); rd_dest; + rd_dest = bgp_route_next(rd_dest)) { + json_object *json_paths = NULL; /* paths array for prefix */ + json_object *json_prefix = NULL; /* prefix within an RD */ + json_object *json_rd = NULL; /* holds all prefixes for RD */ + char rd_str[RD_ADDRSTRLEN]; + char prefix_str[BUFSIZ]; + int add_rd_to_json = 0; + struct prefix_evpn ep; + const struct prefix *rd_destp = bgp_dest_get_prefix(rd_dest); + + table = bgp_dest_get_bgp_table_info(rd_dest); + if (table == NULL) + continue; + + prefix_rd2str((struct prefix_rd *)rd_destp, rd_str, + sizeof(rd_str)); + + /* Construct an RT-2 from the user-supplied mac(ip), + * then search the l2vpn evpn table for it. + */ + build_evpn_type2_prefix(&ep, mac, ip); + dest = bgp_afi_node_lookup(bgp->rib[afi][safi], afi, safi, + (struct prefix *)&ep, + (struct prefix_rd *)rd_destp); + if (!dest) + continue; + + if (json) + json_rd = json_object_new_object(); + + const struct prefix *p = bgp_dest_get_prefix(dest); + + prefix2str(p, prefix_str, sizeof(prefix_str)); + + pi = bgp_dest_get_bgp_path_info(dest); + if (pi) { + /* RD header - per RD. */ + bgp_evpn_show_route_rd_header(vty, rd_dest, json_rd, + rd_str, RD_ADDRSTRLEN); + prefix_cnt++; + } + + if (json) { + json_prefix = json_object_new_object(); + json_paths = json_object_new_array(); + json_object_string_add(json_prefix, "prefix", + prefix_str); + json_object_int_add(json_prefix, "prefixLen", + p->prefixlen); + } else + /* Prefix and num paths displayed once per prefix. */ + route_vty_out_detail_header( + vty, bgp, dest, (struct prefix_rd *)rd_destp, + AFI_L2VPN, SAFI_EVPN, json_prefix); + + /* For EVPN, the prefix is displayed for each path (to + * fit in with code that already exists). + */ + for (; pi; pi = pi->next) { + json_object *json_path = NULL; + + add_rd_to_json = 1; + path_cnt++; + + if (json) + json_path = json_object_new_array(); + + route_vty_out_detail(vty, bgp, dest, pi, AFI_L2VPN, + SAFI_EVPN, RPKI_NOT_BEING_USED, + json_path); + + if (json) + json_object_array_add(json_paths, json_path); + else + vty_out(vty, "\n"); + } + + if (json) { + json_object_object_add(json_prefix, "paths", + json_paths); + json_object_object_add(json_rd, prefix_str, + json_prefix); + if (add_rd_to_json) + json_object_object_add(json, rd_str, json_rd); + else { + json_object_free(json_rd); + json_rd = NULL; + } + } + } + + if (json) { + json_object_int_add(json, "numPrefix", prefix_cnt); + json_object_int_add(json, "numPaths", path_cnt); + } else { + if (prefix_cnt == 0) { + vty_out(vty, "No Matching EVPN prefixes exist\n"); + } else { + vty_out(vty, "Displayed %u prefixes (%u paths)\n", + prefix_cnt, path_cnt); + } + } +} + +/* * Display BGP EVPN routing table - all routes (vty handler). * If 'type' is non-zero, only routes matching that type are shown. */ @@ -2810,6 +3005,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, */ for (; pi; pi = pi->next) { json_object *json_path = NULL; + path_cnt++; add_prefix_to_json = 1; add_rd_to_json = 1; @@ -2820,7 +3016,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, if (detail) { route_vty_out_detail( vty, bgp, dest, pi, AFI_L2VPN, - SAFI_EVPN, json_path); + SAFI_EVPN, RPKI_NOT_BEING_USED, + json_path); } else route_vty_out(vty, p, pi, 0, SAFI_EVPN, json_path, false); @@ -4100,6 +4297,21 @@ DEFPY(show_bgp_l2vpn_evpn_es_vrf, show_bgp_l2vpn_evpn_es_vrf_cmd, return CMD_SUCCESS; } +DEFPY(show_bgp_l2vpn_evpn_nh, + show_bgp_l2vpn_evpn_nh_cmd, + "show bgp l2vpn evpn next-hops [json$uj]", + SHOW_STR + BGP_STR + L2VPN_HELP_STR + EVPN_HELP_STR + "Nexthops\n" + JSON_STR) +{ + bgp_evpn_nh_show(vty, uj); + + return CMD_SUCCESS; +} + /* * Display EVPN neighbor summary. */ @@ -4221,7 +4433,7 @@ DEFUN(show_bgp_l2vpn_evpn_route, */ DEFUN(show_bgp_l2vpn_evpn_route_rd, show_bgp_l2vpn_evpn_route_rd_cmd, - "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN [type "EVPN_TYPE_ALL_LIST"] [json]", + "show bgp l2vpn evpn route rd <ASN:NN_OR_IP-ADDRESS:NN|all> [type "EVPN_TYPE_ALL_LIST"] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -4229,6 +4441,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, EVPN_RT_HELP_STR EVPN_RT_DIST_HELP_STR EVPN_ASN_IP_HELP_STR + "All VPN Route Distinguishers\n" EVPN_TYPE_HELP_STR EVPN_TYPE_ALL_LIST_HELP_STR JSON_STR) @@ -4237,9 +4450,10 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, int ret; struct prefix_rd prd; int type = 0; - int rd_idx = 0; bool uj = false; json_object *json = NULL; + int idx_ext_community = 0; + int rd_all = 0; bgp = bgp_get_evpn(); if (!bgp) @@ -4250,10 +4464,12 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, if (uj) json = json_object_new_object(); - /* get the RD */ - if (argv_find(argv, argc, "rd", &rd_idx)) { - ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd); - + argv_find(argv, argc, "all", &rd_all); + if (!rd_all) { + /* get the RD */ + argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", + &idx_ext_community); + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; @@ -4263,7 +4479,10 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0) return CMD_WARNING; - evpn_show_route_rd(vty, bgp, &prd, type, json); + if (rd_all) + evpn_show_all_routes(vty, bgp, type, json, 1); + else + evpn_show_route_rd(vty, bgp, &prd, type, json); if (uj) { vty_out(vty, "%s\n", json_object_to_json_string_ext( @@ -4279,7 +4498,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, */ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, show_bgp_l2vpn_evpn_route_rd_macip_cmd, - "show bgp l2vpn evpn route rd ASN:NN_OR_IP-ADDRESS:NN mac WORD [ip WORD] [json]", + "show bgp l2vpn evpn route rd <ASN:NN_OR_IP-ADDRESS:NN|all> mac WORD [ip WORD] [json]", SHOW_STR BGP_STR L2VPN_HELP_STR @@ -4287,6 +4506,7 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, EVPN_RT_HELP_STR EVPN_RT_DIST_HELP_STR EVPN_ASN_IP_HELP_STR + "All VPN Route Distinguishers\n" "MAC\n" "MAC address (e.g., 00:e0:ec:20:12:62)\n" "IP\n" @@ -4298,11 +4518,12 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, struct prefix_rd prd; struct ethaddr mac; struct ipaddr ip; - int rd_idx = 0; + int idx_ext_community = 0; int mac_idx = 0; int ip_idx = 0; bool uj = false; json_object *json = NULL; + int rd_all = 0; memset(&mac, 0, sizeof(struct ethaddr)); memset(&ip, 0, sizeof(struct ipaddr)); @@ -4317,8 +4538,11 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, json = json_object_new_object(); /* get the prd */ - if (argv_find(argv, argc, "rd", &rd_idx)) { - ret = str2prefix_rd(argv[rd_idx + 1]->arg, &prd); + argv_find(argv, argc, "all", &rd_all); + if (!rd_all) { + argv_find(argv, argc, "ASN:NN_OR_IP-ADDRESS:NN", + &idx_ext_community); + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; @@ -4341,7 +4565,10 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, } } - evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json); + if (rd_all) + evpn_show_route_rd_all_macip(vty, bgp, &mac, &ip, json); + else + evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json); if (uj) { vty_out(vty, "%s\n", json_object_to_json_string_ext( @@ -4658,12 +4885,49 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all, } DEFPY_HIDDEN( - show_bgp_l2vpn_evpn_route_mac_ip_es, - show_bgp_l2vpn_evpn_route_mac_ip_es_cmd, - "show bgp l2vpn evpn route mac-ip-es [NAME$esi_str|detail$detail] [json$uj]", + show_bgp_l2vpn_evpn_route_mac_ip_evi_es, + show_bgp_l2vpn_evpn_route_mac_ip_evi_es_cmd, + "show bgp l2vpn evpn route mac-ip-evi-es [NAME$esi_str|detail$detail] [json$uj]", + SHOW_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR + "EVPN route information\n" + "MAC IP routes in the EVI tables linked to the ES\n" + "ES ID\n" + "Detailed information\n" JSON_STR) +{ + esi_t esi; + esi_t *esi_p; + json_object *json = NULL; + + if (esi_str) { + if (!str_to_esi(esi_str, &esi)) { + vty_out(vty, "%%Malformed ESI\n"); + return CMD_WARNING; + } + esi_p = &esi; + } else { + esi_p = NULL; + } + + if (uj) + json = json_object_new_object(); + bgp_evpn_show_routes_mac_ip_evi_es(vty, esi_p, json, !!detail); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; +} + +DEFPY_HIDDEN( + show_bgp_l2vpn_evpn_route_mac_ip_global_es, + show_bgp_l2vpn_evpn_route_mac_ip_global_es_cmd, + "show bgp l2vpn evpn route mac-ip-global-es [NAME$esi_str|detail$detail] [json$uj]", SHOW_STR BGP_STR L2VPN_HELP_STR EVPN_HELP_STR "EVPN route information\n" - "MAC IP routes linked to the ES\n" + "MAC IP routes in the global table linked to the ES\n" "ES ID\n" "Detailed information\n" JSON_STR) { @@ -4683,7 +4947,7 @@ DEFPY_HIDDEN( if (uj) json = json_object_new_object(); - bgp_evpn_show_routes_mac_ip_es(vty, esi_p, json, !!detail); + bgp_evpn_show_routes_mac_ip_global_es(vty, esi_p, json, !!detail); if (uj) { vty_out(vty, "%s\n", json_object_to_json_string_ext( @@ -5957,6 +6221,7 @@ void bgp_ethernetvpn_init(void) install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_evi_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_vrf_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_nh_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd); @@ -5968,7 +6233,10 @@ void bgp_ethernetvpn_init(void) &show_bgp_l2vpn_evpn_route_vni_multicast_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd); - install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_mac_ip_es_cmd); + install_element(VIEW_NODE, + &show_bgp_l2vpn_evpn_route_mac_ip_evi_es_cmd); + install_element(VIEW_NODE, + &show_bgp_l2vpn_evpn_route_mac_ip_global_es_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vrf_import_rt_cmd); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 6abba18418..45a856a459 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -57,8 +57,8 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_vty.h" -DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer)) -DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer)) +DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer)); +DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer)); /* Definition of display strings corresponding to FSM events. This should be * kept consistent with the events defined in bgpd.h @@ -1215,8 +1215,9 @@ int bgp_stop(struct peer *peer) peer->nsf_af_count = 0; /* deregister peer */ - if (peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE) - bgp_bfd_deregister_peer(peer); + if (peer->bfd_config + && peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE) + bfd_sess_uninstall(peer->bfd_config->session); if (peer_dynamic_neighbor(peer) && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { @@ -2122,7 +2123,10 @@ static int bgp_establish(struct peer *peer) hash_release(peer->bgp->peerhash, peer); hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); - bgp_bfd_reset_peer(peer); + /* Start BFD peer if not already running. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); + return ret; } diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index bf4966c839..bcf697e153 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -155,8 +155,8 @@ extern void bgp_start_routeadv(struct bgp *); extern void bgp_adjust_routeadv(struct peer *); #include "hook.h" -DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer)) -DECLARE_HOOK(peer_established, (struct peer *peer), (peer)) +DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer)); +DECLARE_HOOK(peer_established, (struct peer *peer), (peer)); int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd); int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd); diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index 001340be35..fcb2df9d6f 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -50,10 +50,10 @@ static struct labelpool *lp; /* request this many labels at a time from zebra */ #define LP_CHUNK_SIZE 50 -DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk") -DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item") -DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment") -DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback") +DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk"); +DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item"); +DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment"); +DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback"); struct lp_chunk { uint32_t first; @@ -80,7 +80,7 @@ struct lp_fifo { struct lp_lcb lcb; }; -DECLARE_LIST(lp_fifo, struct lp_fifo, fifo) +DECLARE_LIST(lp_fifo, struct lp_fifo, fifo); struct lp_cbq_item { int (*cbfunc)(mpls_label_t label, void *lblid, bool alloc); diff --git a/bgpd/bgp_labelpool.h b/bgpd/bgp_labelpool.h index d9f64acfe4..d6a8eec84d 100644 --- a/bgpd/bgp_labelpool.h +++ b/bgpd/bgp_labelpool.h @@ -31,7 +31,7 @@ #define LP_TYPE_VRF 0x00000001 #define LP_TYPE_BGP_LU 0x00000002 -PREDECL_LIST(lp_fifo) +PREDECL_LIST(lp_fifo); struct labelpool { struct skiplist *ledger; /* all requests */ diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 3cb3d06217..ea74a82cec 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -65,6 +65,7 @@ #include "bgpd/bgp_nb.h" #include "bgpd/bgp_evpn_mh.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_routemap_nb.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -162,6 +163,9 @@ __attribute__((__noreturn__)) void sigint(void) assert(bm->terminating == false); bm->terminating = true; /* global flag that shutting down */ + /* Disable BFD events to avoid wasting processing. */ + bfd_protocol_integration_set_shutdown(true); + bgp_terminate(); bgp_exit(0); @@ -385,6 +389,7 @@ static const struct frr_yang_module_info *const bgpd_yang_modules[] = { &frr_route_map_info, &frr_routing_info, &frr_vrf_info, + &frr_bgp_route_map_info, }; FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT, @@ -394,7 +399,8 @@ FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT, .signals = bgp_signals, .n_signals = array_size(bgp_signals), .privs = &bgpd_privs, .yang_modules = bgpd_yang_modules, - .n_yang_modules = array_size(bgpd_yang_modules), ) + .n_yang_modules = array_size(bgpd_yang_modules), +); #define DEPRECATED_OPTIONS "" diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 0013eb2df2..36bdc05eb7 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -28,112 +28,115 @@ /* this file is temporary in nature; definitions should be moved to the * files they're used in */ -DEFINE_MGROUP(BGPD, "bgpd") -DEFINE_MTYPE(BGPD, BGP, "BGP instance") -DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details") -DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer") -DEFINE_MTYPE(BGPD, BGP_PEER_HOST, "BGP peer hostname") -DEFINE_MTYPE(BGPD, BGP_PEER_IFNAME, "BGP peer ifname") -DEFINE_MTYPE(BGPD, PEER_GROUP, "Peer group") -DEFINE_MTYPE(BGPD, PEER_GROUP_HOST, "BGP Peer group hostname") -DEFINE_MTYPE(BGPD, PEER_DESC, "Peer description") -DEFINE_MTYPE(BGPD, PEER_PASSWORD, "Peer password string") -DEFINE_MTYPE(BGPD, BGP_PEER_AF, "BGP peer af") -DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group") -DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup") -DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet") -DEFINE_MTYPE(BGPD, ATTR, "BGP attribute") -DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath") -DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg") -DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data") -DEFINE_MTYPE(BGPD, AS_STR, "BGP aspath str") - -DEFINE_MTYPE(BGPD, BGP_TABLE, "BGP table") -DEFINE_MTYPE(BGPD, BGP_NODE, "BGP node") -DEFINE_MTYPE(BGPD, BGP_ROUTE, "BGP route") -DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info") -DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected") -DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static") -DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr") -DEFINE_MTYPE(BGPD, BGP_ADVERTISE, "BGP adv") -DEFINE_MTYPE(BGPD, BGP_SYNCHRONISE, "BGP synchronise") -DEFINE_MTYPE(BGPD, BGP_ADJ_IN, "BGP adj in") -DEFINE_MTYPE(BGPD, BGP_ADJ_OUT, "BGP adj out") -DEFINE_MTYPE(BGPD, BGP_MPATH_INFO, "BGP multipath info") - -DEFINE_MTYPE(BGPD, AS_LIST, "BGP AS list") -DEFINE_MTYPE(BGPD, AS_FILTER, "BGP AS filter") -DEFINE_MTYPE(BGPD, AS_FILTER_STR, "BGP AS filter str") - -DEFINE_MTYPE(BGPD, COMMUNITY, "community") -DEFINE_MTYPE(BGPD, COMMUNITY_VAL, "community val") -DEFINE_MTYPE(BGPD, COMMUNITY_STR, "community str") - -DEFINE_MTYPE(BGPD, ECOMMUNITY, "extcommunity") -DEFINE_MTYPE(BGPD, ECOMMUNITY_VAL, "extcommunity val") -DEFINE_MTYPE(BGPD, ECOMMUNITY_STR, "extcommunity str") - -DEFINE_MTYPE(BGPD, COMMUNITY_LIST, "community-list") -DEFINE_MTYPE(BGPD, COMMUNITY_LIST_NAME, "community-list name") -DEFINE_MTYPE(BGPD, COMMUNITY_LIST_ENTRY, "community-list entry") -DEFINE_MTYPE(BGPD, COMMUNITY_LIST_CONFIG, "community-list config") -DEFINE_MTYPE(BGPD, COMMUNITY_LIST_HANDLER, "community-list handler") - -DEFINE_MTYPE(BGPD, CLUSTER, "Cluster list") -DEFINE_MTYPE(BGPD, CLUSTER_VAL, "Cluster list val") - -DEFINE_MTYPE(BGPD, BGP_PROCESS_QUEUE, "BGP Process queue") -DEFINE_MTYPE(BGPD, BGP_CLEAR_NODE_QUEUE, "BGP node clear queue") - -DEFINE_MTYPE(BGPD, TRANSIT, "BGP transit attr") -DEFINE_MTYPE(BGPD, TRANSIT_VAL, "BGP transit val") - -DEFINE_MTYPE(BGPD, BGP_DEBUG_FILTER, "BGP debug filter") -DEFINE_MTYPE(BGPD, BGP_DEBUG_STR, "BGP debug filter string") - -DEFINE_MTYPE(BGPD, BGP_DISTANCE, "BGP distance") -DEFINE_MTYPE(BGPD, BGP_NEXTHOP_CACHE, "BGP nexthop") -DEFINE_MTYPE(BGPD, BGP_CONFED_LIST, "BGP confed list") -DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface") -DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface") -DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info") -DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array") -DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list") -DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp") -DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate") -DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address") -DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address") - -DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution") -DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information") -DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information") -DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV") - -DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options") -DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value") - -DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community") -DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string") -DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value") - -DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information") -DEFINE_MTYPE(BGPD, BGP_EVPN_MH_INFO, "BGP EVPN MH Information") -DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP") -DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_ES_INFO, "BGP EVPN PATH ES Information") -DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP") -DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information") -DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information") -DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VRF, "BGP EVPN ES-per-VRF Information") -DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT") -DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT") -DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP") - -DEFINE_MTYPE(BGPD, BGP_FLOWSPEC, "BGP flowspec") -DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE, "BGP flowspec rule") -DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str") -DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled") -DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name") -DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index") - -DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie") -DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service") +DEFINE_MGROUP(BGPD, "bgpd"); +DEFINE_MTYPE(BGPD, BGP, "BGP instance"); +DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details"); +DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer"); +DEFINE_MTYPE(BGPD, BGP_PEER_HOST, "BGP peer hostname"); +DEFINE_MTYPE(BGPD, BGP_PEER_IFNAME, "BGP peer ifname"); +DEFINE_MTYPE(BGPD, PEER_GROUP, "Peer group"); +DEFINE_MTYPE(BGPD, PEER_GROUP_HOST, "BGP Peer group hostname"); +DEFINE_MTYPE(BGPD, PEER_DESC, "Peer description"); +DEFINE_MTYPE(BGPD, PEER_PASSWORD, "Peer password string"); +DEFINE_MTYPE(BGPD, BGP_PEER_AF, "BGP peer af"); +DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group"); +DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup"); +DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet"); +DEFINE_MTYPE(BGPD, ATTR, "BGP attribute"); +DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath"); +DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg"); +DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data"); +DEFINE_MTYPE(BGPD, AS_STR, "BGP aspath str"); + +DEFINE_MTYPE(BGPD, BGP_TABLE, "BGP table"); +DEFINE_MTYPE(BGPD, BGP_NODE, "BGP node"); +DEFINE_MTYPE(BGPD, BGP_ROUTE, "BGP route"); +DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info"); +DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected"); +DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static"); +DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr"); +DEFINE_MTYPE(BGPD, BGP_ADVERTISE, "BGP adv"); +DEFINE_MTYPE(BGPD, BGP_SYNCHRONISE, "BGP synchronise"); +DEFINE_MTYPE(BGPD, BGP_ADJ_IN, "BGP adj in"); +DEFINE_MTYPE(BGPD, BGP_ADJ_OUT, "BGP adj out"); +DEFINE_MTYPE(BGPD, BGP_MPATH_INFO, "BGP multipath info"); + +DEFINE_MTYPE(BGPD, AS_LIST, "BGP AS list"); +DEFINE_MTYPE(BGPD, AS_FILTER, "BGP AS filter"); +DEFINE_MTYPE(BGPD, AS_FILTER_STR, "BGP AS filter str"); + +DEFINE_MTYPE(BGPD, COMMUNITY, "community"); +DEFINE_MTYPE(BGPD, COMMUNITY_VAL, "community val"); +DEFINE_MTYPE(BGPD, COMMUNITY_STR, "community str"); + +DEFINE_MTYPE(BGPD, ECOMMUNITY, "extcommunity"); +DEFINE_MTYPE(BGPD, ECOMMUNITY_VAL, "extcommunity val"); +DEFINE_MTYPE(BGPD, ECOMMUNITY_STR, "extcommunity str"); + +DEFINE_MTYPE(BGPD, COMMUNITY_LIST, "community-list"); +DEFINE_MTYPE(BGPD, COMMUNITY_LIST_NAME, "community-list name"); +DEFINE_MTYPE(BGPD, COMMUNITY_LIST_ENTRY, "community-list entry"); +DEFINE_MTYPE(BGPD, COMMUNITY_LIST_CONFIG, "community-list config"); +DEFINE_MTYPE(BGPD, COMMUNITY_LIST_HANDLER, "community-list handler"); + +DEFINE_MTYPE(BGPD, CLUSTER, "Cluster list"); +DEFINE_MTYPE(BGPD, CLUSTER_VAL, "Cluster list val"); + +DEFINE_MTYPE(BGPD, BGP_PROCESS_QUEUE, "BGP Process queue"); +DEFINE_MTYPE(BGPD, BGP_CLEAR_NODE_QUEUE, "BGP node clear queue"); + +DEFINE_MTYPE(BGPD, TRANSIT, "BGP transit attr"); +DEFINE_MTYPE(BGPD, TRANSIT_VAL, "BGP transit val"); + +DEFINE_MTYPE(BGPD, BGP_DEBUG_FILTER, "BGP debug filter"); +DEFINE_MTYPE(BGPD, BGP_DEBUG_STR, "BGP debug filter string"); + +DEFINE_MTYPE(BGPD, BGP_DISTANCE, "BGP distance"); +DEFINE_MTYPE(BGPD, BGP_NEXTHOP_CACHE, "BGP nexthop"); +DEFINE_MTYPE(BGPD, BGP_CONFED_LIST, "BGP confed list"); +DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface"); +DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface"); +DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info"); +DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array"); +DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list"); +DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp"); +DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate"); +DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address"); +DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address"); + +DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution"); +DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information"); +DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information"); +DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV"); + +DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options"); +DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value"); + +DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community"); +DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string"); +DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value"); + +DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information"); +DEFINE_MTYPE(BGPD, BGP_EVPN_MH_INFO, "BGP EVPN MH Information"); +DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP"); +DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_MH_INFO, "BGP EVPN PATH MH Information"); +DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_ES_INFO, "BGP EVPN PATH ES Information"); +DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_NH_INFO, "BGP EVPN PATH NH Information"); +DEFINE_MTYPE(BGPD, BGP_EVPN_NH, "BGP EVPN Nexthop"); +DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP"); +DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information"); +DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information"); +DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VRF, "BGP EVPN ES-per-VRF Information"); +DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT"); +DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT"); +DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP"); + +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC, "BGP flowspec"); +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE, "BGP flowspec rule"); +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str"); +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled"); +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name"); +DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index"); + +DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie"); +DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 63998e95ac..29923424e3 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -24,115 +24,118 @@ #include "memory.h" -DECLARE_MGROUP(BGPD) -DECLARE_MTYPE(BGP) -DECLARE_MTYPE(BGP_LISTENER) -DECLARE_MTYPE(BGP_PEER) -DECLARE_MTYPE(BGP_PEER_HOST) -DECLARE_MTYPE(BGP_PEER_IFNAME) -DECLARE_MTYPE(PEER_GROUP) -DECLARE_MTYPE(PEER_GROUP_HOST) -DECLARE_MTYPE(PEER_DESC) -DECLARE_MTYPE(PEER_PASSWORD) -DECLARE_MTYPE(BGP_PEER_AF) -DECLARE_MTYPE(BGP_UPDGRP) -DECLARE_MTYPE(BGP_UPD_SUBGRP) -DECLARE_MTYPE(BGP_PACKET) -DECLARE_MTYPE(ATTR) -DECLARE_MTYPE(AS_PATH) -DECLARE_MTYPE(AS_SEG) -DECLARE_MTYPE(AS_SEG_DATA) -DECLARE_MTYPE(AS_STR) - -DECLARE_MTYPE(BGP_TABLE) -DECLARE_MTYPE(BGP_NODE) -DECLARE_MTYPE(BGP_ROUTE) -DECLARE_MTYPE(BGP_ROUTE_EXTRA) -DECLARE_MTYPE(BGP_CONN) -DECLARE_MTYPE(BGP_STATIC) -DECLARE_MTYPE(BGP_ADVERTISE_ATTR) -DECLARE_MTYPE(BGP_ADVERTISE) -DECLARE_MTYPE(BGP_SYNCHRONISE) -DECLARE_MTYPE(BGP_ADJ_IN) -DECLARE_MTYPE(BGP_ADJ_OUT) -DECLARE_MTYPE(BGP_MPATH_INFO) - -DECLARE_MTYPE(AS_LIST) -DECLARE_MTYPE(AS_FILTER) -DECLARE_MTYPE(AS_FILTER_STR) - -DECLARE_MTYPE(COMMUNITY) -DECLARE_MTYPE(COMMUNITY_VAL) -DECLARE_MTYPE(COMMUNITY_STR) - -DECLARE_MTYPE(ECOMMUNITY) -DECLARE_MTYPE(ECOMMUNITY_VAL) -DECLARE_MTYPE(ECOMMUNITY_STR) - -DECLARE_MTYPE(COMMUNITY_LIST) -DECLARE_MTYPE(COMMUNITY_LIST_NAME) -DECLARE_MTYPE(COMMUNITY_LIST_ENTRY) -DECLARE_MTYPE(COMMUNITY_LIST_CONFIG) -DECLARE_MTYPE(COMMUNITY_LIST_HANDLER) - -DECLARE_MTYPE(CLUSTER) -DECLARE_MTYPE(CLUSTER_VAL) - -DECLARE_MTYPE(BGP_PROCESS_QUEUE) -DECLARE_MTYPE(BGP_CLEAR_NODE_QUEUE) - -DECLARE_MTYPE(TRANSIT) -DECLARE_MTYPE(TRANSIT_VAL) - -DECLARE_MTYPE(BGP_DEBUG_FILTER) -DECLARE_MTYPE(BGP_DEBUG_STR) - -DECLARE_MTYPE(BGP_DISTANCE) -DECLARE_MTYPE(BGP_NEXTHOP_CACHE) -DECLARE_MTYPE(BGP_CONFED_LIST) -DECLARE_MTYPE(PEER_UPDATE_SOURCE) -DECLARE_MTYPE(PEER_CONF_IF) -DECLARE_MTYPE(BGP_DAMP_INFO) -DECLARE_MTYPE(BGP_DAMP_ARRAY) -DECLARE_MTYPE(BGP_DAMP_REUSELIST) -DECLARE_MTYPE(BGP_REGEXP) -DECLARE_MTYPE(BGP_AGGREGATE) -DECLARE_MTYPE(BGP_ADDR) -DECLARE_MTYPE(TIP_ADDR) - -DECLARE_MTYPE(BGP_REDIST) -DECLARE_MTYPE(BGP_FILTER_NAME) -DECLARE_MTYPE(BGP_DUMP_STR) -DECLARE_MTYPE(ENCAP_TLV) - -DECLARE_MTYPE(BGP_TEA_OPTIONS) -DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE) - -DECLARE_MTYPE(LCOMMUNITY) -DECLARE_MTYPE(LCOMMUNITY_STR) -DECLARE_MTYPE(LCOMMUNITY_VAL) - -DECLARE_MTYPE(BGP_EVPN_MH_INFO) -DECLARE_MTYPE(BGP_EVPN_ES) -DECLARE_MTYPE(BGP_EVPN_ES_EVI) -DECLARE_MTYPE(BGP_EVPN_ES_VRF) -DECLARE_MTYPE(BGP_EVPN_ES_VTEP) -DECLARE_MTYPE(BGP_EVPN_PATH_ES_INFO) -DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP) - -DECLARE_MTYPE(BGP_EVPN) -DECLARE_MTYPE(BGP_EVPN_IMPORT_RT) -DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT) -DECLARE_MTYPE(BGP_EVPN_MACIP) - -DECLARE_MTYPE(BGP_FLOWSPEC) -DECLARE_MTYPE(BGP_FLOWSPEC_RULE) -DECLARE_MTYPE(BGP_FLOWSPEC_RULE_STR) -DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED) -DECLARE_MTYPE(BGP_FLOWSPEC_NAME) -DECLARE_MTYPE(BGP_FLOWSPEC_INDEX) - -DECLARE_MTYPE(BGP_SRV6_L3VPN) -DECLARE_MTYPE(BGP_SRV6_VPN) +DECLARE_MGROUP(BGPD); +DECLARE_MTYPE(BGP); +DECLARE_MTYPE(BGP_LISTENER); +DECLARE_MTYPE(BGP_PEER); +DECLARE_MTYPE(BGP_PEER_HOST); +DECLARE_MTYPE(BGP_PEER_IFNAME); +DECLARE_MTYPE(PEER_GROUP); +DECLARE_MTYPE(PEER_GROUP_HOST); +DECLARE_MTYPE(PEER_DESC); +DECLARE_MTYPE(PEER_PASSWORD); +DECLARE_MTYPE(BGP_PEER_AF); +DECLARE_MTYPE(BGP_UPDGRP); +DECLARE_MTYPE(BGP_UPD_SUBGRP); +DECLARE_MTYPE(BGP_PACKET); +DECLARE_MTYPE(ATTR); +DECLARE_MTYPE(AS_PATH); +DECLARE_MTYPE(AS_SEG); +DECLARE_MTYPE(AS_SEG_DATA); +DECLARE_MTYPE(AS_STR); + +DECLARE_MTYPE(BGP_TABLE); +DECLARE_MTYPE(BGP_NODE); +DECLARE_MTYPE(BGP_ROUTE); +DECLARE_MTYPE(BGP_ROUTE_EXTRA); +DECLARE_MTYPE(BGP_CONN); +DECLARE_MTYPE(BGP_STATIC); +DECLARE_MTYPE(BGP_ADVERTISE_ATTR); +DECLARE_MTYPE(BGP_ADVERTISE); +DECLARE_MTYPE(BGP_SYNCHRONISE); +DECLARE_MTYPE(BGP_ADJ_IN); +DECLARE_MTYPE(BGP_ADJ_OUT); +DECLARE_MTYPE(BGP_MPATH_INFO); + +DECLARE_MTYPE(AS_LIST); +DECLARE_MTYPE(AS_FILTER); +DECLARE_MTYPE(AS_FILTER_STR); + +DECLARE_MTYPE(COMMUNITY); +DECLARE_MTYPE(COMMUNITY_VAL); +DECLARE_MTYPE(COMMUNITY_STR); + +DECLARE_MTYPE(ECOMMUNITY); +DECLARE_MTYPE(ECOMMUNITY_VAL); +DECLARE_MTYPE(ECOMMUNITY_STR); + +DECLARE_MTYPE(COMMUNITY_LIST); +DECLARE_MTYPE(COMMUNITY_LIST_NAME); +DECLARE_MTYPE(COMMUNITY_LIST_ENTRY); +DECLARE_MTYPE(COMMUNITY_LIST_CONFIG); +DECLARE_MTYPE(COMMUNITY_LIST_HANDLER); + +DECLARE_MTYPE(CLUSTER); +DECLARE_MTYPE(CLUSTER_VAL); + +DECLARE_MTYPE(BGP_PROCESS_QUEUE); +DECLARE_MTYPE(BGP_CLEAR_NODE_QUEUE); + +DECLARE_MTYPE(TRANSIT); +DECLARE_MTYPE(TRANSIT_VAL); + +DECLARE_MTYPE(BGP_DEBUG_FILTER); +DECLARE_MTYPE(BGP_DEBUG_STR); + +DECLARE_MTYPE(BGP_DISTANCE); +DECLARE_MTYPE(BGP_NEXTHOP_CACHE); +DECLARE_MTYPE(BGP_CONFED_LIST); +DECLARE_MTYPE(PEER_UPDATE_SOURCE); +DECLARE_MTYPE(PEER_CONF_IF); +DECLARE_MTYPE(BGP_DAMP_INFO); +DECLARE_MTYPE(BGP_DAMP_ARRAY); +DECLARE_MTYPE(BGP_DAMP_REUSELIST); +DECLARE_MTYPE(BGP_REGEXP); +DECLARE_MTYPE(BGP_AGGREGATE); +DECLARE_MTYPE(BGP_ADDR); +DECLARE_MTYPE(TIP_ADDR); + +DECLARE_MTYPE(BGP_REDIST); +DECLARE_MTYPE(BGP_FILTER_NAME); +DECLARE_MTYPE(BGP_DUMP_STR); +DECLARE_MTYPE(ENCAP_TLV); + +DECLARE_MTYPE(BGP_TEA_OPTIONS); +DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE); + +DECLARE_MTYPE(LCOMMUNITY); +DECLARE_MTYPE(LCOMMUNITY_STR); +DECLARE_MTYPE(LCOMMUNITY_VAL); + +DECLARE_MTYPE(BGP_EVPN_MH_INFO); +DECLARE_MTYPE(BGP_EVPN_ES); +DECLARE_MTYPE(BGP_EVPN_ES_EVI); +DECLARE_MTYPE(BGP_EVPN_ES_VRF); +DECLARE_MTYPE(BGP_EVPN_ES_VTEP); +DECLARE_MTYPE(BGP_EVPN_PATH_ES_INFO); +DECLARE_MTYPE(BGP_EVPN_PATH_MH_INFO); +DECLARE_MTYPE(BGP_EVPN_PATH_NH_INFO); +DECLARE_MTYPE(BGP_EVPN_NH); +DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP); + +DECLARE_MTYPE(BGP_EVPN); +DECLARE_MTYPE(BGP_EVPN_IMPORT_RT); +DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT); +DECLARE_MTYPE(BGP_EVPN_MACIP); + +DECLARE_MTYPE(BGP_FLOWSPEC); +DECLARE_MTYPE(BGP_FLOWSPEC_RULE); +DECLARE_MTYPE(BGP_FLOWSPEC_RULE_STR); +DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED); +DECLARE_MTYPE(BGP_FLOWSPEC_NAME); +DECLARE_MTYPE(BGP_FLOWSPEC_INDEX); + +DECLARE_MTYPE(BGP_SRV6_L3VPN); +DECLARE_MTYPE(BGP_SRV6_VPN); #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index d9acda8bd0..a902c63dea 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -2043,7 +2043,7 @@ int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd, DEFUN (show_bgp_ip_vpn_all_rd, show_bgp_ip_vpn_all_rd_cmd, - "show bgp "BGP_AFI_CMD_STR" vpn all [rd ASN:NN_OR_IP-ADDRESS:NN] [json]", + "show bgp "BGP_AFI_CMD_STR" vpn all [rd <ASN:NN_OR_IP-ADDRESS:NN|all>] [json]", SHOW_STR BGP_STR BGP_VPNVX_HELP_STR @@ -2051,6 +2051,7 @@ DEFUN (show_bgp_ip_vpn_all_rd, "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" JSON_STR) { int ret; @@ -2059,7 +2060,9 @@ DEFUN (show_bgp_ip_vpn_all_rd, int idx = 0; if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { - if (argv_find(argv, argc, "rd", &idx)) { + /* Constrain search if user supplies RD && RD != "all" */ + if (argv_find(argv, argc, "rd", &idx) + && strcmp(argv[idx + 1]->arg, "all")) { ret = str2prefix_rd(argv[idx + 1]->arg, &prd); if (!ret) { vty_out(vty, @@ -2080,26 +2083,28 @@ DEFUN (show_bgp_ip_vpn_all_rd, ALIAS(show_bgp_ip_vpn_all_rd, show_bgp_ip_vpn_rd_cmd, - "show bgp "BGP_AFI_CMD_STR" vpn rd ASN:NN_OR_IP-ADDRESS:NN [json]", + "show bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> [json]", SHOW_STR BGP_STR BGP_VPNVX_HELP_STR "Display VPN NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" JSON_STR) #ifdef KEEP_OLD_VPN_COMMANDS DEFUN (show_ip_bgp_vpn_rd, show_ip_bgp_vpn_rd_cmd, - "show ip bgp "BGP_AFI_CMD_STR" vpn rd ASN:NN_OR_IP-ADDRESS:NN", + "show ip bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all>", SHOW_STR IP_STR BGP_STR BGP_AFI_HELP_STR "Address Family modifier\n" "Display information for a route distinguisher\n" - "VPN Route Distinguisher\n") + "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n") { int idx_ext_community = argc - 1; int ret; @@ -2108,6 +2113,10 @@ DEFUN (show_ip_bgp_vpn_rd, int idx = 0; if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { + if (!strcmp(argv[idx_ext_community]->arg, "all")) + return bgp_show_mpls_vpn(vty, afi, NULL, + bgp_show_type_normal, NULL, 0, + 0); ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); @@ -2157,13 +2166,14 @@ DEFUN (show_ip_bgp_vpn_all_tags, DEFUN (show_ip_bgp_vpn_rd_tags, show_ip_bgp_vpn_rd_tags_cmd, - "show [ip] bgp <vpnv4|vpnv6> rd ASN:NN_OR_IP-ADDRESS:NN tags", + "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> tags", SHOW_STR IP_STR BGP_STR BGP_VPNVX_HELP_STR "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" "Display BGP tags for prefixes\n") { int idx_ext_community = 5; @@ -2173,6 +2183,10 @@ DEFUN (show_ip_bgp_vpn_rd_tags, int idx = 0; if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { + if (!strcmp(argv[idx_ext_community]->arg, "all")) + return bgp_show_mpls_vpn(vty, afi, NULL, + bgp_show_type_normal, NULL, 1, + 0); ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); @@ -2247,13 +2261,14 @@ DEFUN (show_ip_bgp_vpn_all_neighbor_routes, DEFUN (show_ip_bgp_vpn_rd_neighbor_routes, show_ip_bgp_vpn_rd_neighbor_routes_cmd, - "show [ip] bgp <vpnv4|vpnv6> rd ASN:NN_OR_IP-ADDRESS:NN neighbors A.B.C.D routes [json]", + "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors A.B.C.D routes [json]", SHOW_STR IP_STR BGP_STR BGP_VPNVX_HELP_STR "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n" @@ -2265,26 +2280,32 @@ DEFUN (show_ip_bgp_vpn_rd_neighbor_routes, union sockunion su; struct peer *peer; struct prefix_rd prd; + bool prefix_rd_all = false; bool uj = use_json(argc, argv); afi_t afi; int idx = 0; if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { - ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); - if (!ret) { - if (uj) { - json_object *json_no = NULL; - json_no = json_object_new_object(); - json_object_string_add( - json_no, "warning", - "Malformed Route Distinguisher"); - vty_out(vty, "%s\n", - json_object_to_json_string(json_no)); - json_object_free(json_no); - } else - vty_out(vty, - "%% Malformed Route Distinguisher\n"); - return CMD_WARNING; + if (!strcmp(argv[idx_ext_community]->arg, "all")) + prefix_rd_all = true; + else { + ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); + if (!ret) { + if (uj) { + json_object *json_no = NULL; + json_no = json_object_new_object(); + json_object_string_add( + json_no, "warning", + "Malformed Route Distinguisher"); + vty_out(vty, "%s\n", + json_object_to_json_string( + json_no)); + json_object_free(json_no); + } else + vty_out(vty, + "%% Malformed Route Distinguisher\n"); + return CMD_WARNING; + } } ret = str2sockunion(argv[idx_ipv4]->arg, &su); @@ -2320,8 +2341,14 @@ DEFUN (show_ip_bgp_vpn_rd_neighbor_routes, return CMD_WARNING; } - return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_neighbor, - &su, 0, uj); + if (prefix_rd_all) + return bgp_show_mpls_vpn(vty, afi, NULL, + bgp_show_type_neighbor, &su, 0, + uj); + else + return bgp_show_mpls_vpn(vty, afi, &prd, + bgp_show_type_neighbor, &su, 0, + uj); } return CMD_SUCCESS; } @@ -2387,13 +2414,14 @@ DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes, DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes, show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd, - "show [ip] bgp <vpnv4|vpnv6> rd ASN:NN_OR_IP-ADDRESS:NN neighbors A.B.C.D advertised-routes [json]", + "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors A.B.C.D advertised-routes [json]", SHOW_STR IP_STR BGP_STR BGP_VPNVX_HELP_STR "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" + "All VPN Route Distinguishers\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n" @@ -2442,6 +2470,9 @@ DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes, return CMD_WARNING; } + if (!strcmp(argv[idx_ext_community]->arg, "all")) + return show_adj_route_vpn(vty, peer, NULL, AFI_IP, + SAFI_MPLS_VPN, uj); ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); if (!ret) { if (uj) { diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c index b74cf37ac7..6f75856d54 100644 --- a/bgpd/bgp_mplsvpn_snmp.c +++ b/bgpd/bgp_mplsvpn_snmp.c @@ -1478,10 +1478,16 @@ static struct bgp_path_info *bgpL3vpnRte_lookup(struct variable *v, oid name[], oid_copy_str(&name[namelen], (*l3vpn_bgp)->name, vrf_name_len); oid_index = namelen + vrf_name_len; - name[oid_index++] = - v4 ? INETADDRESSTYPEIPV4 : INETADDRESSTYPEIPV6; - oid_copy_addr(&name[oid_index], &p->u.prefix4, - addr_len); + if (v4) { + name[oid_index++] = INETADDRESSTYPEIPV4; + oid_copy_in_addr(&name[oid_index], + &p->u.prefix4); + } else { + name[oid_index++] = INETADDRESSTYPEIPV6; + oid_copy_in6_addr(&name[oid_index], + &p->u.prefix6); + } + oid_index += addr_len; name[oid_index++] = p->prefixlen; name[oid_index++] = *policy >> 8; @@ -1493,9 +1499,8 @@ static struct bgp_path_info *bgpL3vpnRte_lookup(struct variable *v, oid name[], INETADDRESSTYPEUNKNOWN; else { name[oid_index++] = INETADDRESSTYPEIPV4; - oid_copy_addr(&name[oid_index], - &attr->nexthop, - sizeof(struct in_addr)); + oid_copy_in_addr(&name[oid_index], + &attr->nexthop); oid_index += sizeof(struct in_addr); } } else { @@ -1505,11 +1510,9 @@ static struct bgp_path_info *bgpL3vpnRte_lookup(struct variable *v, oid name[], INETADDRESSTYPEUNKNOWN; else { name[oid_index++] = INETADDRESSTYPEIPV6; - oid_copy_addr( + oid_copy_in6_addr( &name[oid_index], - (struct in_addr *)&attr - ->mp_nexthop_global, - sizeof(struct in6_addr)); + &attr->mp_nexthop_global); oid_index += sizeof(struct in6_addr); } } diff --git a/bgpd/bgp_nb.c b/bgpd/bgp_nb.c index f65a4be677..2547439499 100644 --- a/bgpd/bgp_nb.c +++ b/bgpd/bgp_nb.c @@ -7406,6 +7406,76 @@ const struct frr_yang_module_info frr_bgp_info = { } }, { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-import", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-export", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-import", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-export", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-import", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-export", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-import", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-export", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-import", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-export", + .cbs = { + .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify, + .destroy = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy, + } + }, + { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client", .cbs = { .modify = bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify, @@ -10004,6 +10074,76 @@ const struct frr_yang_module_info frr_bgp_info = { } }, { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-import", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-export", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-import", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-export", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-import", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-export", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-import", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-export", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-import", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-export", + .cbs = { + .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify, + .destroy = bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy, + } + }, + { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client", .cbs = { .modify = bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify, diff --git a/bgpd/bgp_nb.h b/bgpd/bgp_nb.h index eb7725d3dd..57f379b6cc 100644 --- a/bgpd/bgp_nb.h +++ b/bgpd/bgp_nb.h @@ -3325,6 +3325,48 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_route_server struct nb_cb_modify_args *args); int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify( struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify( + struct nb_cb_modify_args *args); +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy( + struct nb_cb_destroy_args *args); int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify( struct nb_cb_modify_args *args); int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify( @@ -4529,6 +4571,46 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_route_server_route_ struct nb_cb_modify_args *args); int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguration_modify( struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy( + struct nb_cb_destroy_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify( + struct nb_cb_modify_args *args); +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy( + struct nb_cb_destroy_args *args); int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify( struct nb_cb_modify_args *args); int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_server_route_server_client_modify( diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c index 721ce5b5c6..5a88bd08d9 100644 --- a/bgpd/bgp_nb_config.c +++ b/bgpd/bgp_nb_config.c @@ -32,20 +32,20 @@ #include "bgpd/bgp_io.h" #include "bgpd/bgp_damp.h" -DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp)) +DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp)); FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY, { .val_ulong = 10, .match_profile = "datacenter", }, { .val_ulong = 120 }, -) +); FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME, { .val_ulong = 9, .match_profile = "datacenter", }, { .val_ulong = 180 }, -) +); FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE, { .val_ulong = 3, .match_profile = "datacenter", }, { .val_ulong = 60 }, -) +); int routing_control_plane_protocols_name_validate( struct nb_cb_create_args *args) @@ -158,8 +158,26 @@ int bgp_router_destroy(struct nb_cb_destroy_args *args) struct bgp *tmp_bgp; for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { - if (tmp_bgp->inst_type - == BGP_INSTANCE_TYPE_VRF) { + if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) + continue; + if (CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], + BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], + BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_VRF_EXPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_VRF_EXPORT) || + (bgp == bgp_get_evpn() && + (CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))) || + (tmp_bgp->vnihash && hashcount(tmp_bgp->vnihash))) { snprintf( args->errmsg, args->errmsg_len, "Cannot delete default BGP instance. Dependent VRF instances exist\n"); @@ -3146,8 +3164,7 @@ int bgp_neighbors_neighbor_neighbor_remote_as_remote_as_type_modify( return NB_OK; str2sockunion(peer_str, &su); - ret = peer_remote_as(bgp, &su, NULL, &as, as_type, AFI_IP, - SAFI_UNICAST); + ret = peer_remote_as(bgp, &su, NULL, &as, as_type); if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0) return NB_ERR_INCONSISTENCY; @@ -3202,8 +3219,7 @@ int bgp_neighbors_neighbor_neighbor_remote_as_remote_as_modify( as = yang_dnode_get_uint32(args->dnode, NULL); str2sockunion(peer_str, &su); - ret = peer_remote_as(bgp, &su, NULL, &as, as_type, AFI_IP, - SAFI_UNICAST); + ret = peer_remote_as(bgp, &su, NULL, &as, as_type); if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret) < 0) return NB_ERR_INCONSISTENCY; @@ -4370,8 +4386,7 @@ int bgp_neighbors_unnumbered_neighbor_create(struct nb_cb_create_args *args) "./neighbor-remote-as/remote-as"); } - if (peer_conf_interface_create(bgp, peer_str, AFI_IP, - SAFI_UNICAST, v6_only, + if (peer_conf_interface_create(bgp, peer_str, v6_only, peer_grp_str, as_type, as, args->errmsg, args->errmsg_len)) return NB_ERR_INCONSISTENCY; @@ -4440,9 +4455,9 @@ int bgp_neighbors_unnumbered_neighbor_v6only_modify( v6_only = yang_dnode_get_bool(args->dnode, NULL); - if (peer_conf_interface_create( - bgp, peer_str, AFI_IP, SAFI_UNICAST, v6_only, NULL, - AS_UNSPECIFIED, 0, args->errmsg, args->errmsg_len)) + if (peer_conf_interface_create(bgp, peer_str, v6_only, NULL, + AS_UNSPECIFIED, 0, args->errmsg, + args->errmsg_len)) return NB_ERR_INCONSISTENCY; break; @@ -5174,8 +5189,6 @@ void bgp_neighbors_unnumbered_neighbor_neighbor_remote_as_apply_finish( int ret; as_t as = 0; struct peer *peer = NULL; - afi_t afi = AFI_IP; - safi_t safi = SAFI_UNICAST; bgp = nb_running_get_entry(args->dnode, NULL, true); peer_str = yang_dnode_get_string(args->dnode, "../interface"); @@ -5185,7 +5198,7 @@ void bgp_neighbors_unnumbered_neighbor_neighbor_remote_as_apply_finish( peer = peer_lookup_by_conf_if(bgp, peer_str); - ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi, safi); + ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type); if (ret < 0 && !peer) { snprintf(args->errmsg, args->errmsg_len, @@ -21835,8 +21848,7 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config case NB_EV_PREPARE: case NB_EV_ABORT: case NB_EV_APPLY: - /* TODO: implement me. */ - break; + return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN); } return NB_OK; @@ -21850,8 +21862,7 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_ipv6_labeled_unicast_filter_config case NB_EV_PREPARE: case NB_EV_ABORT: case NB_EV_APPLY: - /* TODO: implement me. */ - break; + return bgp_neighbor_afi_safi_plist_destroy(args, FILTER_IN); } return NB_OK; @@ -22979,8 +22990,7 @@ int bgp_neighbors_neighbor_afi_safis_afi_safi_l3vpn_ipv4_unicast_filter_config_p case NB_EV_ABORT: return NB_OK; case NB_EV_APPLY: - bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN); - break; + return bgp_neighbor_afi_safi_plist_modify(args, FILTER_IN); } return NB_OK; @@ -35526,6 +35536,350 @@ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_soft_reconfi /* * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-import + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args, + RMAP_IN); + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args, + RMAP_IN); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-export + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return bgp_unnumbered_neighbor_afi_safi_rmap_modify(args, + RMAP_OUT); + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return bgp_unnumbered_neighbor_afi_safi_rmap_destroy(args, + RMAP_OUT); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-import + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-export + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-import + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-export + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-import + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-export + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-import + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-export + */ +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client */ int bgp_neighbors_unnumbered_neighbor_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify( @@ -47019,6 +47373,346 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_soft_reconfiguratio /* * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-import + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_IN); + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_IN); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/rmap-export + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return bgp_peer_group_afi_safi_rmap_modify(args, RMAP_OUT); + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_rmap_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-import + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/plist-export + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_plist_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-import + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/access-list-export + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_access_list_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-import + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/as-path-filter-list-export + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_as_path_filter_list_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-import + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_import_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/l2vpn-evpn/filter-config/unsuppress-map-export + */ +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +int bgp_peer_groups_peer_group_afi_safis_afi_safi_l2vpn_evpn_filter_config_unsuppress_map_export_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + /* TODO: implement me. */ + break; + } + + return NB_OK; +} + +/* + * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-bgp:bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec/route-reflector/route-reflector-client */ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv4_flowspec_route_reflector_route_reflector_client_modify( @@ -47557,7 +48251,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_rm case NB_EV_ABORT: break; case NB_EV_APPLY: - return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN); + return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT); } return NB_OK; @@ -47591,7 +48285,7 @@ int bgp_peer_groups_peer_group_afi_safis_afi_safi_ipv6_flowspec_filter_config_pl case NB_EV_ABORT: break; case NB_EV_APPLY: - return bgp_peer_group_afi_safi_rmap_destroy(args, RMAP_OUT); + return bgp_peer_group_afi_safi_plist_destroy(args, FILTER_IN); } return NB_OK; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 03ff27c7ca..4821ce8ddb 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -544,7 +544,7 @@ static int bgp_accept(struct thread *thread) peer1->host); peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as, - peer1->as, peer1->as_type, 0, 0, NULL); + peer1->as, peer1->as_type, NULL); hash_release(peer->bgp->peerhash, peer); hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index c6fa37fa8d..9c8d7878c5 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -194,6 +194,16 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, bnc->srte_color, bnc->bgp->name_pretty, peer); } + } else { + if (BGP_DEBUG(nht, NHT)) { + char buf[PREFIX2STR_BUFFER]; + + zlog_debug( + "Found existing bnc %s(%s) flags 0x%x ifindex %d #paths %d peer %p", + bnc_str(bnc, buf, PREFIX2STR_BUFFER), + bnc->bgp->name_pretty, bnc->flags, bnc->ifindex, + bnc->path_count, bnc->nht_info); + } } if (is_bgp_static_route) { @@ -237,6 +247,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); } + if (peer && (bnc->ifindex != ifindex)) { + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); + UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); + bnc->ifindex = ifindex; + } if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) { SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); @@ -454,17 +469,21 @@ static void bgp_nht_ifp_table_handle(struct bgp *bgp, bnc->last_update = bgp_clock(); bnc->change_flags = 0; + /* + * For interface based routes ( ala the v6 LL routes + * that this was written for ) the metric received + * for the connected route is 0 not 1. + */ + bnc->metric = 0; if (up) { SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); - bnc->metric = 1; bnc->nexthop_num = 1; } else { UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED); bnc->nexthop_num = 0; - bnc->metric = 0; } evaluate_paths(bnc); @@ -502,6 +521,11 @@ static int bgp_nht_ifp_initial(struct thread *thread) if (!ifp) return 0; + if (BGP_DEBUG(nht, NHT)) + zlog_debug( + "Handle NHT initial update for Intf %s(%d) status %s", + ifp->name, ifp->ifindex, if_is_up(ifp) ? "up" : "down"); + if (if_is_up(ifp)) bgp_nht_ifp_up(ifp); else diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index e08f19fb45..24df324633 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -68,12 +68,12 @@ DEFINE_HOOK(bgp_packet_dump, (struct peer *peer, uint8_t type, bgp_size_t size, struct stream *s), - (peer, type, size, s)) + (peer, type, size, s)); DEFINE_HOOK(bgp_packet_send, (struct peer *peer, uint8_t type, bgp_size_t size, struct stream *s), - (peer, type, size, s)) + (peer, type, size, s)); /** * Sets marker and type fields for a BGP message. diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index d32f091d0c..d69c862304 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -26,12 +26,12 @@ DECLARE_HOOK(bgp_packet_dump, (struct peer *peer, uint8_t type, bgp_size_t size, struct stream *s), - (peer, type, size, s)) + (peer, type, size, s)); DECLARE_HOOK(bgp_packet_send, (struct peer *peer, uint8_t type, bgp_size_t size, struct stream *s), - (peer, type, size, s)) + (peer, type, size, s)); #define BGP_NLRI_LENGTH 1U #define BGP_TOTAL_ATTR_LEN 2U diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index 171522f8ae..2c6c2c3861 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -37,12 +37,12 @@ #include "bgpd/bgp_flowspec_private.h" #include "bgpd/bgp_errors.h" -DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry") -DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match") -DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action") -DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule") -DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context") -DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value") +DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry"); +DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match"); +DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action"); +DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule"); +DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context"); +DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value"); /* chain strings too long to fit in one line */ #define FSPEC_ACTION_EXCEED_LIMIT "flowspec actions exceeds limit" diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 87fd5f28ca..35a9316221 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -71,6 +71,7 @@ #include "bgpd/bgp_mac.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_trace.h" +#include "bgpd/bgp_rpki.h" #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" @@ -95,12 +96,12 @@ DEFINE_HOOK(bgp_snmp_update_stats, (struct bgp_node *rn, struct bgp_path_info *pi, bool added), - (rn, pi, added)) + (rn, pi, added)); DEFINE_HOOK(bgp_rpki_prefix_status, (struct peer *peer, struct attr *attr, const struct prefix *prefix), - (peer, attr, prefix)) + (peer, attr, prefix)); /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; @@ -126,7 +127,7 @@ static const struct message bgp_pmsi_tnltype_str[] = { DEFINE_HOOK(bgp_process, (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, struct peer *peer, bool withdraw), - (bgp, afi, safi, bn, peer, withdraw)) + (bgp, afi, safi, bn, peer, withdraw)); /** Test if path is suppressed. */ static bool bgp_path_suppressed(struct bgp_path_info *pi) @@ -250,8 +251,8 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) if (e->aggr_suppressors) list_delete(&e->aggr_suppressors); - if (e->es_info) - bgp_evpn_path_es_info_free(e->es_info); + if (e->mh_info) + bgp_evpn_path_mh_info_free(e->mh_info); if ((*extra)->bgp_fs_iprule) list_delete(&((*extra)->bgp_fs_iprule)); @@ -565,6 +566,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, int internal_as_route; int confed_as_route; int ret = 0; + int igp_metric_ret = 0; + int peer_sort_ret = -1; char new_buf[PATH_ADDPATH_STR_BUFFER]; char exist_buf[PATH_ADDPATH_STR_BUFFER]; uint32_t new_mm_seq; @@ -971,7 +974,9 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, zlog_debug( "%s: %s wins over %s due to eBGP peer > iBGP peer", pfx_buf, new_buf, exist_buf); - return 1; + if (!CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) + return 1; + peer_sort_ret = 1; } if (exist_sort == BGP_PEER_EBGP @@ -981,7 +986,9 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, zlog_debug( "%s: %s loses to %s due to iBGP peer < eBGP peer", pfx_buf, new_buf, exist_buf); - return 0; + if (!CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) + return 0; + peer_sort_ret = 0; } /* 8. IGP metric check. */ @@ -993,19 +1000,19 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, existm = exist->extra->igpmetric; if (newm < existm) { - if (debug) + if (debug && peer_sort_ret < 0) zlog_debug( "%s: %s wins over %s due to IGP metric %u < %u", pfx_buf, new_buf, exist_buf, newm, existm); - ret = 1; + igp_metric_ret = 1; } if (newm > existm) { - if (debug) + if (debug && peer_sort_ret < 0) zlog_debug( "%s: %s loses to %s due to IGP metric %u > %u", pfx_buf, new_buf, exist_buf, newm, existm); - ret = 0; + igp_metric_ret = 0; } /* 9. Same IGP metric. Compare the cluster list length as @@ -1023,21 +1030,21 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, existm = BGP_CLUSTER_LIST_LENGTH(exist->attr); if (newm < existm) { - if (debug) + if (debug && peer_sort_ret < 0) zlog_debug( "%s: %s wins over %s due to CLUSTER_LIST length %u < %u", pfx_buf, new_buf, exist_buf, newm, existm); - ret = 1; + igp_metric_ret = 1; } if (newm > existm) { - if (debug) + if (debug && peer_sort_ret < 0) zlog_debug( "%s: %s loses to %s due to CLUSTER_LIST length %u > %u", pfx_buf, new_buf, exist_buf, newm, existm); - ret = 0; + igp_metric_ret = 0; } } } @@ -1051,7 +1058,10 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, zlog_debug( "%s: %s wins over %s due to confed-external peer > confed-internal peer", pfx_buf, new_buf, exist_buf); - return 1; + if (!CHECK_FLAG(bgp->flags, + BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) + return 1; + peer_sort_ret = 1; } if (exist_sort == BGP_PEER_CONFED @@ -1061,7 +1071,10 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, zlog_debug( "%s: %s loses to %s due to confed-internal peer < confed-external peer", pfx_buf, new_buf, exist_buf); - return 0; + if (!CHECK_FLAG(bgp->flags, + BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) + return 0; + peer_sort_ret = 0; } } @@ -1122,20 +1135,40 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * TODO: If unequal cost ibgp multipath is enabled we can * mark the paths as equal here instead of returning */ - if (debug) { - if (ret == 1) - zlog_debug( - "%s: %s wins over %s after IGP metric comparison", - pfx_buf, new_buf, exist_buf); - else - zlog_debug( - "%s: %s loses to %s after IGP metric comparison", - pfx_buf, new_buf, exist_buf); + + /* Prior to the addition of BGP_FLAG_PEERTYPE_MULTIPATH_RELAX, + * if either step 7 or 10 (peer type checks) yielded a winner, + * that result was returned immediately. Returning from step 10 + * ignored the return value computed in steps 8 and 9 (IGP + * metric checks). In order to preserve that behavior, if + * peer_sort_ret is set, return that rather than igp_metric_ret. + */ + ret = peer_sort_ret; + if (peer_sort_ret < 0) { + ret = igp_metric_ret; + if (debug) { + if (ret == 1) + zlog_debug( + "%s: %s wins over %s after IGP metric comparison", + pfx_buf, new_buf, exist_buf); + else + zlog_debug( + "%s: %s loses to %s after IGP metric comparison", + pfx_buf, new_buf, exist_buf); + } + *reason = bgp_path_selection_igp_metric; } - *reason = bgp_path_selection_igp_metric; return ret; } + /* + * At this point, the decision whether to set *paths_eq = 1 has been + * completed. If we deferred returning because of bestpath peer-type + * relax configuration, return now. + */ + if (peer_sort_ret >= 0) + return peer_sort_ret; + /* 12. If both paths are external, prefer the path that was received first (the oldest one). This step minimizes route-flap, since a newer path won't displace an older one, even if it was the @@ -7551,18 +7584,20 @@ static const char *bgp_origin2str(uint8_t origin) return "n/a"; } -static const char *bgp_rpki_validation2str(int v_state) +static const char *bgp_rpki_validation2str(enum rpki_states v_state) { switch (v_state) { - case 1: + case RPKI_NOT_BEING_USED: + return "not used"; + case RPKI_VALID: return "valid"; - case 2: + case RPKI_NOTFOUND: return "not found"; - case 3: + case RPKI_INVALID: return "invalid"; - default: - break; } + + assert(!"We should never get here this is a dev escape"); return "ERROR"; } @@ -8856,15 +8891,17 @@ void route_vty_out(struct vty *vty, const struct prefix *p, if (safi == SAFI_EVPN) { struct bgp_path_es_info *path_es_info = NULL; - if (path->extra) - path_es_info = path->extra->es_info; - if (bgp_evpn_is_esi_valid(&attr->esi)) { /* XXX - add these params to the json out */ vty_out(vty, "%*s", 20, " "); vty_out(vty, "ESI:%s", esi_to_str(&attr->esi, esi_buf, sizeof(esi_buf))); + + if (path->extra && path->extra->mh_info) + path_es_info = + path->extra->mh_info->es_info; + if (path_es_info && path_es_info->es) vty_out(vty, " VNI: %u", path_es_info->vni); @@ -9547,9 +9584,10 @@ static void route_vty_out_detail_es_info(struct vty *vty, } } -void route_vty_out_detail(struct vty *vty, struct bgp *bgp, - struct bgp_dest *bn, struct bgp_path_info *path, - afi_t afi, safi_t safi, json_object *json_paths) +void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, + struct bgp_path_info *path, afi_t afi, safi_t safi, + enum rpki_states rpki_curr_state, + json_object *json_paths) { char buf[INET6_ADDRSTRLEN]; char buf1[BUFSIZ]; @@ -9580,7 +9618,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, int i; char *nexthop_hostname = bgp_nexthop_hostname(path->peer, path->nexthop); - int rpki_validation_state = 0; if (json_paths) { json_path = json_object_new_object(); @@ -9626,12 +9663,20 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, buf1, sizeof(buf1)); if (is_pi_family_evpn(parent_ri)) { vty_out(vty, - " Imported from %s:%pFX, VNI %s\n", + " Imported from %s:%pFX, VNI %s", buf1, (struct prefix_evpn *) bgp_dest_get_prefix( dest), tag_buf); + if (attr->es_flags & ATTR_ES_L3_NHG) + vty_out(vty, ", L3NHG %s", + (attr->es_flags + & ATTR_ES_L3_NHG_ACTIVE) + ? "active" + : "inactive"); + vty_out(vty, "\n"); + } else vty_out(vty, " Imported from %s:%pFX\n", @@ -10179,18 +10224,14 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, } } - const struct prefix *p = bgp_dest_get_prefix(bn); - if (p->family == AF_INET || p->family == AF_INET6) - rpki_validation_state = hook_call(bgp_rpki_prefix_status, - path->peer, path->attr, p); - if (rpki_validation_state) { + if (rpki_curr_state != RPKI_NOT_BEING_USED) { if (json_paths) json_object_string_add( json_path, "rpkiValidationState", - bgp_rpki_validation2str(rpki_validation_state)); + bgp_rpki_validation2str(rpki_curr_state)); else - vty_out(vty, ", validation-state: %s", - bgp_rpki_validation2str(rpki_validation_state)); + vty_out(vty, ", rpki validation-state: %s", + bgp_rpki_validation2str(rpki_curr_state)); } if (json_bestpath) @@ -10510,7 +10551,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, struct bgp_table *table, enum bgp_show_type type, void *output_arg, char *rd, int is_last, unsigned long *output_cum, unsigned long *total_cum, - unsigned long *json_header_depth, uint8_t show_flags) + unsigned long *json_header_depth, uint8_t show_flags, + enum rpki_states rpki_target_state) { struct bgp_path_info *pi; struct bgp_dest *dest; @@ -10559,6 +10601,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, /* Start processing of routes. */ for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { const struct prefix *dest_p = bgp_dest_get_prefix(dest); + enum rpki_states rpki_curr_state = RPKI_NOT_BEING_USED; pi = bgp_dest_get_bgp_path_info(dest); if (pi == NULL) @@ -10572,6 +10615,18 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, for (; pi; pi = pi->next) { total_count++; + + if (type == bgp_show_type_rpki) { + if (dest_p->family == AF_INET + || dest_p->family == AF_INET6) + rpki_curr_state = hook_call( + bgp_rpki_prefix_status, + pi->peer, pi->attr, dest_p); + if (rpki_target_state != RPKI_NOT_BEING_USED + && rpki_curr_state != rpki_target_state) + continue; + } + if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_neighbor || type == bgp_show_type_dampend_paths @@ -10881,7 +10936,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, bgp_show_table(vty, bgp, safi, itable, type, output_arg, rd, next == NULL, &output_cum, &total_cum, &json_header_depth, - show_flags); + show_flags, RPKI_NOT_BEING_USED); if (next == NULL) show_msg = false; } @@ -10899,7 +10954,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, } static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_show_type type, void *output_arg, - uint8_t show_flags) + uint8_t show_flags, enum rpki_states rpki_target_state) { struct bgp_table *table; unsigned long json_header_depth = 0; @@ -10934,7 +10989,8 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, safi = SAFI_UNICAST; return bgp_show_table(vty, bgp, safi, table, type, output_arg, NULL, 1, - NULL, NULL, &json_header_depth, show_flags); + NULL, NULL, &json_header_depth, show_flags, + rpki_target_state); } static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi, @@ -10968,7 +11024,7 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi, : bgp->name); } bgp_show(vty, bgp, afi, safi, bgp_show_type_normal, NULL, - show_flags); + show_flags, RPKI_NOT_BEING_USED); } if (use_json) @@ -11187,15 +11243,25 @@ static void bgp_show_path_info(struct prefix_rd *pfx_rd, struct bgp_dest *bgp_node, struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, json_object *json, enum bgp_path_type pathtype, - int *display) + int *display, enum rpki_states rpki_target_state) { struct bgp_path_info *pi; int header = 1; char rdbuf[RD_ADDRSTRLEN]; json_object *json_header = NULL; json_object *json_paths = NULL; + const struct prefix *p = bgp_dest_get_prefix(bgp_node); for (pi = bgp_dest_get_bgp_path_info(bgp_node); pi; pi = pi->next) { + enum rpki_states rpki_curr_state = RPKI_NOT_BEING_USED; + + if (p->family == AF_INET || p->family == AF_INET6) + rpki_curr_state = hook_call(bgp_rpki_prefix_status, + pi->peer, pi->attr, p); + + if (rpki_target_state != RPKI_NOT_BEING_USED + && rpki_curr_state != rpki_target_state) + continue; if (json && !json_paths) { /* Instantiate json_paths only if path is valid */ @@ -11221,9 +11287,8 @@ static void bgp_show_path_info(struct prefix_rd *pfx_rd, || (pathtype == BGP_PATH_SHOW_MULTIPATH && (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH) || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)))) - route_vty_out_detail(vty, bgp, bgp_node, - pi, AFI_IP, safi, - json_paths); + route_vty_out_detail(vty, bgp, bgp_node, pi, AFI_IP, + safi, rpki_curr_state, json_paths); } if (json && json_paths) { @@ -11238,6 +11303,7 @@ static void bgp_show_path_info(struct prefix_rd *pfx_rd, static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, struct bgp_table *rib, const char *ip_str, afi_t afi, safi_t safi, + enum rpki_states rpki_target_state, struct prefix_rd *prd, int prefix_check, enum bgp_path_type pathtype, bool use_json) { @@ -11285,7 +11351,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, json, pathtype, - &display); + &display, rpki_target_state); bgp_dest_unlock_node(rm); } @@ -11344,7 +11410,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, json, pathtype, - &display); + &display, rpki_target_state); bgp_dest_unlock_node(rm); } @@ -11371,7 +11437,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, || dest_p->prefixlen == match.prefixlen) { bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json, pathtype, - &display); + &display, rpki_target_state); } bgp_dest_unlock_node(dest); @@ -11397,7 +11463,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, int prefix_check, enum bgp_path_type pathtype, - bool use_json) + enum rpki_states rpki_target_state, bool use_json) { if (!bgp) { bgp = bgp_get_default(); @@ -11415,8 +11481,8 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, safi = SAFI_UNICAST; return bgp_show_route_in_table(vty, bgp, bgp->rib[afi][safi], ip_str, - afi, safi, prd, prefix_check, pathtype, - use_json); + afi, safi, rpki_target_state, prd, + prefix_check, pathtype, use_json); } static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc, @@ -11458,9 +11524,9 @@ static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc, } ret = bgp_show(vty, bgp, afi, safi, - (exact ? bgp_show_type_lcommunity_exact - : bgp_show_type_lcommunity), - lcom, show_flags); + (exact ? bgp_show_type_lcommunity_exact + : bgp_show_type_lcommunity), + lcom, show_flags, RPKI_NOT_BEING_USED); lcommunity_free(&lcom); return ret; @@ -11488,7 +11554,7 @@ static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp, return bgp_show(vty, bgp, afi, safi, (exact ? bgp_show_type_lcommunity_list_exact : bgp_show_type_lcommunity_list), - list, show_flags); + list, show_flags, RPKI_NOT_BEING_USED); } DEFUN (show_ip_bgp_large_community_list, @@ -11570,7 +11636,8 @@ DEFUN (show_ip_bgp_large_community, exact_match, afi, safi, uj); } else return bgp_show(vty, bgp, afi, safi, - bgp_show_type_lcommunity_all, NULL, show_flags); + bgp_show_type_lcommunity_all, NULL, show_flags, + RPKI_NOT_BEING_USED); } static int bgp_table_stats_single(struct vty *vty, struct bgp *bgp, afi_t afi, @@ -11818,6 +11885,7 @@ DEFPY (show_ip_bgp_json, |accept-own|accept-own-nexthop|route-filter-v6\ |route-filter-v4|route-filter-translated-v6\ |route-filter-translated-v4] [exact-match]\ + |rpki <invalid|valid|notfound>\ ] [json$uj | wide$wide]", SHOW_STR IP_STR @@ -11847,6 +11915,10 @@ DEFPY (show_ip_bgp_json, "RT translated VPNv6 route filtering (well-known community)\n" "RT translated VPNv4 route filtering (well-known community)\n" "Exact match of the communities\n" + "RPKI route types\n" + "A valid path as determined by rpki\n" + "A invalid path as determined by rpki\n" + "A path that has no rpki data\n" JSON_STR "Increase table width for longer prefixes\n") { @@ -11859,7 +11931,7 @@ DEFPY (show_ip_bgp_json, char *community = NULL; bool first = true; uint8_t show_flags = 0; - + enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED; if (uj) { argc--; @@ -11916,6 +11988,14 @@ DEFPY (show_ip_bgp_json, sh_type = bgp_show_type_community_all; } + if (argv_find(argv, argc, "rpki", &idx)) { + sh_type = bgp_show_type_rpki; + if (argv_find(argv, argc, "valid", &idx)) + rpki_target_state = RPKI_VALID; + else if (argv_find(argv, argc, "invalid", &idx)) + rpki_target_state = RPKI_INVALID; + } + if (!all) { /* show bgp: AFI_IP6, show ip bgp: AFI_IP */ if (community) @@ -11924,7 +12004,7 @@ DEFPY (show_ip_bgp_json, show_flags); else return bgp_show(vty, bgp, afi, safi, sh_type, NULL, - show_flags); + show_flags, rpki_target_state); } else { /* show <ip> bgp ipv4 all: AFI_IP, show <ip> bgp ipv6 all: * AFI_IP6 */ @@ -11961,7 +12041,8 @@ DEFPY (show_ip_bgp_json, safi, show_flags); else bgp_show(vty, bgp, afi, safi, sh_type, - NULL, show_flags); + NULL, show_flags, + rpki_target_state); if (uj) vty_out(vty, "}\n"); } @@ -11992,7 +12073,8 @@ DEFPY (show_ip_bgp_json, safi, show_flags); else bgp_show(vty, bgp, afi, safi, sh_type, - NULL, show_flags); + NULL, show_flags, + rpki_target_state); if (uj) vty_out(vty, "}\n"); } @@ -12005,7 +12087,7 @@ DEFPY (show_ip_bgp_json, DEFUN (show_ip_bgp_route, show_ip_bgp_route_cmd, - "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [<bestpath|multipath>] [json]", + "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [<bestpath|multipath>] [rpki <valid|invalid|notfound>] [json]", SHOW_STR IP_STR BGP_STR @@ -12018,6 +12100,10 @@ DEFUN (show_ip_bgp_route, "IPv6 prefix\n" "Display only the bestpath\n" "Display only multipaths\n" + "Display only paths that match the specified rpki state\n" + "A valid path as determined by rpki\n" + "A invalid path as determined by rpki\n" + "A path that has no rpki data\n" JSON_STR) { int prefix_check = 0; @@ -12074,7 +12160,7 @@ DEFUN (show_ip_bgp_route, path_type = BGP_PATH_SHOW_ALL; return bgp_show_route(vty, bgp, prefix, afi, safi, NULL, prefix_check, - path_type, uj); + path_type, RPKI_NOT_BEING_USED, uj); } DEFUN (show_ip_bgp_regexp, @@ -12169,7 +12255,8 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr, return CMD_WARNING; } - rc = bgp_show(vty, bgp, afi, safi, type, regex, show_flags); + rc = bgp_show(vty, bgp, afi, safi, type, regex, show_flags, + RPKI_NOT_BEING_USED); bgp_regex_free(regex); return rc; } @@ -12188,7 +12275,8 @@ static int bgp_show_prefix_list(struct vty *vty, struct bgp *bgp, return CMD_WARNING; } - return bgp_show(vty, bgp, afi, safi, type, plist, show_flags); + return bgp_show(vty, bgp, afi, safi, type, plist, show_flags, + RPKI_NOT_BEING_USED); } static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp, @@ -12205,7 +12293,8 @@ static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp, return CMD_WARNING; } - return bgp_show(vty, bgp, afi, safi, type, as_list, show_flags); + return bgp_show(vty, bgp, afi, safi, type, as_list, show_flags, + RPKI_NOT_BEING_USED); } static int bgp_show_route_map(struct vty *vty, struct bgp *bgp, @@ -12221,7 +12310,8 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp, return CMD_WARNING; } - return bgp_show(vty, bgp, afi, safi, type, rmap, show_flags); + return bgp_show(vty, bgp, afi, safi, type, rmap, show_flags, + RPKI_NOT_BEING_USED); } static int bgp_show_community(struct vty *vty, struct bgp *bgp, @@ -12240,7 +12330,7 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp, ret = bgp_show(vty, bgp, afi, safi, (exact ? bgp_show_type_community_exact : bgp_show_type_community), - com, show_flags); + com, show_flags, RPKI_NOT_BEING_USED); community_free(&com); return ret; @@ -12262,7 +12352,7 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp, return bgp_show(vty, bgp, afi, safi, (exact ? bgp_show_type_community_list_exact : bgp_show_type_community_list), - list, show_flags); + list, show_flags, RPKI_NOT_BEING_USED); } static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp, @@ -12281,7 +12371,8 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp, return CMD_WARNING; } - ret = bgp_show(vty, bgp, afi, safi, type, p, show_flags); + ret = bgp_show(vty, bgp, afi, safi, type, p, show_flags, + RPKI_NOT_BEING_USED); prefix_free(&p); return ret; } @@ -12969,7 +13060,8 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix, } return bgp_show_route(vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, - BGP_PATH_SHOW_ALL, use_json(argc, argv)); + BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, + use_json(argc, argv)); } #endif /* KEEP_OLD_VPN_COMMANDS */ @@ -13003,7 +13095,7 @@ DEFUN (show_bgp_l2vpn_evpn_route_prefix, } return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, prefix_check, BGP_PATH_SHOW_ALL, - use_json(argc, argv)); + RPKI_NOT_BEING_USED, use_json(argc, argv)); } static void show_adj_route_header(struct vty *vty, struct bgp *bgp, @@ -13723,7 +13815,8 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer, if (safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; - return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, show_flags); + return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, show_flags, + RPKI_NOT_BEING_USED); } DEFUN (show_ip_bgp_flowspec_routes_detailed, @@ -13756,7 +13849,7 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed, return CMD_WARNING; return bgp_show(vty, bgp, afi, safi, bgp_show_type_detail, NULL, - show_flags); + show_flags, RPKI_NOT_BEING_USED); } DEFUN (show_ip_bgp_neighbor_routes, @@ -13824,13 +13917,14 @@ struct bgp_distance { DEFUN (show_bgp_afi_vpn_rd_route, show_bgp_afi_vpn_rd_route_cmd, - "show bgp "BGP_AFI_CMD_STR" vpn rd ASN:NN_OR_IP-ADDRESS:NN <A.B.C.D/M|X:X::X:X/M> [json]", + "show bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> <A.B.C.D/M|X:X::X:X/M> [json]", SHOW_STR BGP_STR BGP_AFI_HELP_STR "Address Family modifier\n" "Display information for a route distinguisher\n" "Route Distinguisher\n" + "All Route Distinguishers\n" "Network in the BGP routing table to display\n" "Network in the BGP routing table to display\n" JSON_STR) @@ -13845,6 +13939,12 @@ DEFUN (show_bgp_afi_vpn_rd_route, return CMD_WARNING; } + if (!strcmp(argv[5]->arg, "all")) + return bgp_show_route(vty, NULL, argv[6]->arg, afi, + SAFI_MPLS_VPN, NULL, 0, BGP_PATH_SHOW_ALL, + RPKI_NOT_BEING_USED, + use_json(argc, argv)); + ret = str2prefix_rd(argv[5]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); @@ -13852,7 +13952,8 @@ DEFUN (show_bgp_afi_vpn_rd_route, } return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd, - 0, BGP_PATH_SHOW_ALL, use_json(argc, argv)); + 0, BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, + use_json(argc, argv)); } static struct bgp_distance *bgp_distance_new(void) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 766e5ade92..0a4fd026e4 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -28,6 +28,7 @@ #include "nexthop.h" #include "bgp_table.h" #include "bgp_addpath_types.h" +#include "bgp_rpki.h" struct bgp_nexthop_cache; struct bgp_route_evpn; @@ -56,6 +57,7 @@ enum bgp_show_type { bgp_show_type_dampend_paths, bgp_show_type_damp_neighbor, bgp_show_type_detail, + bgp_show_type_rpki, }; enum bgp_show_adj_route_type { @@ -102,7 +104,9 @@ enum bgp_show_adj_route_type { #define BGP_NLRI_PARSE_ERROR_EVPN_TYPE1_SIZE -15 #define BGP_NLRI_PARSE_ERROR -32 -/* MAC-IP/type-2 path_info in the VNI routing table is linked to the +/* 1. local MAC-IP/type-2 paths in the VNI routing table are linked to the + * destination ES + * 2. remote MAC-IP paths in the global routing table are linked to the * destination ES */ struct bgp_path_es_info { @@ -113,6 +117,27 @@ struct bgp_path_es_info { struct bgp_evpn_es *es; /* memory used for linking the path to the destination ES */ struct listnode es_listnode; + uint8_t flags; +/* Path is linked to the VNI list */ +#define BGP_EVPN_PATH_ES_INFO_VNI_LIST (1 << 0) +/* Path is linked to the global list */ +#define BGP_EVPN_PATH_ES_INFO_GLOBAL_LIST (1 << 1) +}; + +/* IP paths imported into the VRF from an EVPN route source + * are linked to the nexthop/VTEP IP + */ +struct bgp_path_evpn_nh_info { + /* back pointer to the route */ + struct bgp_path_info *pi; + struct bgp_evpn_nh *nh; + /* memory used for linking the path to the nexthop */ + struct listnode nh_listnode; +}; + +struct bgp_path_mh_info { + struct bgp_path_es_info *es_info; + struct bgp_path_evpn_nh_info *nh_info; }; /* Ancillary information to struct bgp_path_info, @@ -202,7 +227,7 @@ struct bgp_path_info_extra { /* presence of FS pbr iprule based entry */ struct list *bgp_fs_iprule; /* Destination Ethernet Segment links for EVPN MH */ - struct bgp_path_es_info *es_info; + struct bgp_path_mh_info *mh_info; }; struct bgp_path_info { @@ -550,7 +575,7 @@ static inline bool bgp_check_advertise(struct bgp *bgp, struct bgp_dest *dest) DECLARE_HOOK(bgp_process, (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, struct peer *peer, bool withdraw), - (bgp, afi, safi, bn, peer, withdraw)) + (bgp, afi, safi, bn, peer, withdraw)); /* BGP show options */ #define BGP_SHOW_OPT_JSON (1 << 0) @@ -740,7 +765,8 @@ extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, struct bgp_path_info *path, afi_t afi, - safi_t safi, json_object *json_paths); + safi_t safi, enum rpki_states, + json_object *json_paths); extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, struct bgp_table *table, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b7f3289ffc..7692bb7ffe 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -40,6 +40,7 @@ #include "queue.h" #include "frrstr.h" #include "network.h" +#include "lib/northbound_cli.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -3429,81 +3430,6 @@ static const struct route_map_rule_cmd route_set_originator_id_cmd = { route_set_originator_id_free, }; -/* Add bgp route map rule. */ -static int bgp_route_match_add(struct vty *vty, const char *command, - const char *arg, route_map_event_t type) -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - int retval = CMD_SUCCESS; - enum rmap_compile_rets ret; - - ret = route_map_add_match(index, command, arg, type); - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% BGP Can't find rule.\n"); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% BGP Argument is malformed.\n"); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_SUCCESS: - /* - * Intentionally doing nothing here. - */ - break; - } - - return retval; -} - -/* Delete bgp route map rule. */ -static int bgp_route_match_delete(struct vty *vty, const char *command, - const char *arg, route_map_event_t type) -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - enum rmap_compile_rets ret; - int retval = CMD_SUCCESS; - char *dep_name = NULL; - const char *tmpstr; - char *rmap_name = NULL; - - if (type != RMAP_EVENT_MATCH_DELETED) { - /* ignore the mundane, the types without any dependency */ - if (arg == NULL) { - if ((tmpstr = route_map_get_match_arg(index, command)) - != NULL) - dep_name = - XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr); - } else { - dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg); - } - rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name); - } - - ret = route_map_delete_match(index, command, dep_name, type); - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% BGP Can't find rule.\n"); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% BGP Argument is malformed.\n"); - retval = CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_SUCCESS: - /* - * Nothing to do here - */ - break; - } - - XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); - XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); - - return retval; -} - /* * This is the workhorse routine for processing in/out routemap * modifications. @@ -3914,29 +3840,40 @@ static void bgp_route_map_event(const char *rmap_name) route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); } -DEFUN (match_mac_address, - match_mac_address_cmd, - "match mac address WORD", - MATCH_STR - "mac address\n" - "Match address of route\n" - "MAC Access-list name\n") +DEFUN_YANG (match_mac_address, + match_mac_address_cmd, + "match mac address WORD", + MATCH_STR + "mac address\n" + "Match address of route\n" + "MAC Access-list name\n") { - return bgp_route_match_add(vty, "mac address", argv[3]->arg, - RMAP_EVENT_FILTER_ADDED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:mac-address-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[3]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_mac_address, - no_match_mac_address_cmd, - "no match mac address WORD", - NO_STR - MATCH_STR - "mac\n" - "Match address of route\n" - "MAC acess-list name\n") +DEFUN_YANG (no_match_mac_address, + no_match_mac_address_cmd, + "no match mac address WORD", + NO_STR + MATCH_STR + "mac\n" + "Match address of route\n" + "MAC acess-list name\n") { - return bgp_route_match_delete(vty, "mac address", argv[4]->arg, - RMAP_EVENT_FILTER_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:mac-address-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } /* @@ -3963,241 +3900,377 @@ static const char *parse_evpn_rt_type(const char *num_rt_type) return num_rt_type; } -DEFUN (match_evpn_route_type, - match_evpn_route_type_cmd, - "match evpn route-type <macip|2|multicast|3|prefix|5>", - MATCH_STR - EVPN_HELP_STR - EVPN_TYPE_HELP_STR - EVPN_TYPE_2_HELP_STR - EVPN_TYPE_2_HELP_STR - EVPN_TYPE_3_HELP_STR - EVPN_TYPE_3_HELP_STR - EVPN_TYPE_5_HELP_STR - EVPN_TYPE_5_HELP_STR) -{ - return bgp_route_match_add(vty, "evpn route-type", - parse_evpn_rt_type(argv[3]->arg), - RMAP_EVENT_MATCH_ADDED); -} - -DEFUN (no_match_evpn_route_type, - no_match_evpn_route_type_cmd, - "no match evpn route-type <macip|2|multicast|3|prefix|5>", - NO_STR - MATCH_STR - EVPN_HELP_STR - EVPN_TYPE_HELP_STR - EVPN_TYPE_2_HELP_STR - EVPN_TYPE_2_HELP_STR - EVPN_TYPE_3_HELP_STR - EVPN_TYPE_3_HELP_STR - EVPN_TYPE_5_HELP_STR - EVPN_TYPE_5_HELP_STR) +DEFUN_YANG (match_evpn_route_type, + match_evpn_route_type_cmd, + "match evpn route-type <macip|2|multicast|3|prefix|5>", + MATCH_STR + EVPN_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_5_HELP_STR + EVPN_TYPE_5_HELP_STR) { - return bgp_route_match_delete(vty, "evpn route-type", - parse_evpn_rt_type(argv[4]->arg), - RMAP_EVENT_MATCH_DELETED); -} + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:evpn-route-type']"; + char xpath_value[XPATH_MAXLEN]; + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:evpn-route-type", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + parse_evpn_rt_type(argv[3]->arg)); -DEFUN (match_evpn_vni, - match_evpn_vni_cmd, - "match evpn vni " CMD_VNI_RANGE, - MATCH_STR - EVPN_HELP_STR - "Match VNI\n" - "VNI ID\n") + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_evpn_route_type, + no_match_evpn_route_type_cmd, + "no match evpn route-type <macip|2|multicast|3|prefix|5>", + NO_STR + MATCH_STR + EVPN_HELP_STR + EVPN_TYPE_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_2_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_3_HELP_STR + EVPN_TYPE_5_HELP_STR + EVPN_TYPE_5_HELP_STR) { - return bgp_route_match_add(vty, "evpn vni", argv[3]->arg, - RMAP_EVENT_MATCH_ADDED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:evpn-route-type']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_evpn_vni, - no_match_evpn_vni_cmd, - "no match evpn vni " CMD_VNI_RANGE, - NO_STR - MATCH_STR - EVPN_HELP_STR - "Match VNI\n" - "VNI ID\n") + +DEFUN_YANG (match_evpn_vni, + match_evpn_vni_cmd, + "match evpn vni " CMD_VNI_RANGE, + MATCH_STR + EVPN_HELP_STR + "Match VNI\n" + "VNI ID\n") +{ + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:evpn-vni']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:evpn-vni", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[3]->arg); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_evpn_vni, + no_match_evpn_vni_cmd, + "no match evpn vni " CMD_VNI_RANGE, + NO_STR + MATCH_STR + EVPN_HELP_STR + "Match VNI\n" + "VNI ID\n") { - return bgp_route_match_delete(vty, "evpn vni", argv[4]->arg, - RMAP_EVENT_MATCH_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:evpn-vni']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:evpn-vni", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, argv[3]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_evpn_default_route, - match_evpn_default_route_cmd, - "match evpn default-route", - MATCH_STR - EVPN_HELP_STR - "default EVPN type-5 route\n") +DEFUN_YANG (match_evpn_default_route, + match_evpn_default_route_cmd, + "match evpn default-route", + MATCH_STR + EVPN_HELP_STR + "default EVPN type-5 route\n") { - return bgp_route_match_add(vty, "evpn default-route", NULL, - RMAP_EVENT_MATCH_ADDED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:evpn-default-route']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:evpn-default-route", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, NULL); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_evpn_default_route, - no_match_evpn_default_route_cmd, - "no match evpn default-route", - NO_STR - MATCH_STR - EVPN_HELP_STR - "default EVPN type-5 route\n") +DEFUN_YANG (no_match_evpn_default_route, + no_match_evpn_default_route_cmd, + "no match evpn default-route", + NO_STR + MATCH_STR + EVPN_HELP_STR + "default EVPN type-5 route\n") { - return bgp_route_match_delete(vty, "evpn default-route", NULL, - RMAP_EVENT_MATCH_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:evpn-default-route']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } -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") +DEFUN_YANG (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); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:evpn-rd']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:route-distinguisher", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[3]->arg); + + return nb_cli_apply_changes(vty, NULL); } -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") +DEFUN_YANG (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); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:evpn-rd']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFPY(match_vrl_source_vrf, +DEFPY_YANG(match_vrl_source_vrf, match_vrl_source_vrf_cmd, "match source-vrf NAME$vrf_name", MATCH_STR "source vrf\n" "The VRF name\n") { - return bgp_route_match_add(vty, "source-vrf", vrf_name, - RMAP_EVENT_MATCH_ADDED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:source-vrf']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:source-vrf", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, vrf_name); + + return nb_cli_apply_changes(vty, NULL); } -DEFPY(no_match_vrl_source_vrf, +DEFPY_YANG(no_match_vrl_source_vrf, no_match_vrl_source_vrf_cmd, "no match source-vrf NAME$vrf_name", - NO_STR - MATCH_STR + NO_STR MATCH_STR "source vrf\n" "The VRF name\n") { - return bgp_route_match_delete(vty, "source-vrf", vrf_name, - RMAP_EVENT_MATCH_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:source-vrf']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_peer, +DEFPY_YANG (match_peer, match_peer_cmd, - "match peer <A.B.C.D|X:X::X:X|WORD>", + "match peer <A.B.C.D$addrv4|X:X::X:X$addrv6|WORD$intf>", MATCH_STR "Match peer address\n" "IP address of peer\n" "IPv6 address of peer\n" "Interface name of peer\n") { - int idx_ip = 2; - return bgp_route_match_add(vty, "peer", argv[idx_ip]->arg, - RMAP_EVENT_MATCH_ADDED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:peer']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + if (addrv4_str) { + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:peer-ipv4-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + addrv4_str); + } else if (addrv6_str) { + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:peer-ipv6-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + addrv6_str); + } else { + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:peer-interface", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, intf); + } + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_peer_local, - match_peer_local_cmd, - "match peer local", - MATCH_STR - "Match peer address\n" - "Static or Redistributed routes\n") +DEFUN_YANG (match_peer_local, + match_peer_local_cmd, + "match peer local", + MATCH_STR + "Match peer address\n" + "Static or Redistributed routes\n") { - return bgp_route_match_add(vty, "peer", "local", - RMAP_EVENT_MATCH_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:peer']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:peer-local", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_peer, - no_match_peer_cmd, - "no match peer [<local|A.B.C.D|X:X::X:X|WORD>]", - NO_STR - MATCH_STR - "Match peer address\n" - "Static or Redistributed routes\n" - "IP address of peer\n" - "IPv6 address of peer\n" - "Interface name of peer\n") +DEFUN_YANG (no_match_peer, + no_match_peer_cmd, + "no match peer [<local|A.B.C.D|X:X::X:X|WORD>]", + NO_STR + MATCH_STR + "Match peer address\n" + "Static or Redistributed routes\n" + "IP address of peer\n" + "IPv6 address of peer\n" + "Interface name of peer\n") { - int idx_peer = 3; + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:peer']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); - if (argc <= idx_peer) - return bgp_route_match_delete(vty, "peer", NULL, - RMAP_EVENT_MATCH_DELETED); - return bgp_route_match_delete(vty, "peer", argv[idx_peer]->arg, - RMAP_EVENT_MATCH_DELETED); + return nb_cli_apply_changes(vty, NULL); } #ifdef HAVE_SCRIPTING -DEFUN (match_script, - match_script_cmd, - "[no] match script WORD", - NO_STR - MATCH_STR - "Execute script to determine match\n" - "The script name to run, without .lua; e.g. 'myroutemap' to run myroutemap.lua\n") +DEFUN_YANG (match_script, + match_script_cmd, + "[no] match script WORD", + NO_STR + MATCH_STR + "Execute script to determine match\n" + "The script name to run, without .lua; e.g. 'myroutemap' to run myroutemap.lua\n") { bool no = strmatch(argv[0]->text, "no"); int i = 0; argv_find(argv, argc, "WORD", &i); const char *script = argv[i]->arg; + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-script']"; + char xpath_value[XPATH_MAXLEN]; if (no) { - return bgp_route_match_delete(vty, "script", script, - RMAP_EVENT_FILTER_DELETED); - } else { - return bgp_route_match_add(vty, "script", script, - RMAP_EVENT_FILTER_ADDED); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:script", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, + script); + + return nb_cli_apply_changes(vty, NULL); } + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:script", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + script); + + return nb_cli_apply_changes(vty, NULL); } #endif /* HAVE_SCRIPTING */ /* match probability */ -DEFUN (match_probability, - match_probability_cmd, - "match probability (0-100)", - MATCH_STR - "Match portion of routes defined by percentage value\n" - "Percentage of routes\n") +DEFUN_YANG (match_probability, + match_probability_cmd, + "match probability (0-100)", + MATCH_STR + "Match portion of routes defined by percentage value\n" + "Percentage of routes\n") { int idx_number = 2; - return bgp_route_match_add(vty, "probability", argv[idx_number]->arg, - RMAP_EVENT_MATCH_ADDED); + + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:probability']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:probability", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_number]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_probability, - no_match_probability_cmd, - "no match probability [(1-99)]", - NO_STR - MATCH_STR - "Match portion of routes defined by percentage value\n" - "Percentage of routes\n") +DEFUN_YANG (no_match_probability, + no_match_probability_cmd, + "no match probability [(1-99)]", + NO_STR + MATCH_STR + "Match portion of routes defined by percentage value\n" + "Percentage of routes\n") { int idx_number = 3; + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:probability']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + if (argc <= idx_number) - return bgp_route_match_delete(vty, "probability", NULL, - RMAP_EVENT_MATCH_DELETED); - return bgp_route_match_delete(vty, "probability", argv[idx_number]->arg, - RMAP_EVENT_MATCH_DELETED); + return nb_cli_apply_changes(vty, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:probability", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, + argv[idx_number]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_ip_route_source, +DEFPY_YANG (match_ip_route_source, match_ip_route_source_cmd, "match ip route-source <(1-199)|(1300-2699)|WORD>", MATCH_STR @@ -4207,102 +4280,134 @@ DEFUN (match_ip_route_source, "IP access-list number (expanded range)\n" "IP standard access-list name\n") { + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:ip-route-source']"; + char xpath_value[XPATH_MAXLEN + 32]; int idx_acl = 3; - return bgp_route_match_add(vty, "ip route-source", argv[idx_acl]->arg, - RMAP_EVENT_FILTER_ADDED); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:list-name", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_acl]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_ip_route_source, - no_match_ip_route_source_cmd, - "no match ip route-source [<(1-199)|(1300-2699)|WORD>]", - NO_STR - MATCH_STR - IP_STR - "Match advertising source address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" - "IP standard access-list name\n") +DEFUN_YANG (no_match_ip_route_source, + no_match_ip_route_source_cmd, + "no match ip route-source [<(1-199)|(1300-2699)|WORD>]", + NO_STR + MATCH_STR + IP_STR + "Match advertising source address of route\n" + "IP access-list number\n" + "IP access-list number (expanded range)\n" + "IP standard access-list name\n") { - int idx_number = 4; - if (argc <= idx_number) - return bgp_route_match_delete(vty, "ip route-source", NULL, - RMAP_EVENT_FILTER_DELETED); - return bgp_route_match_delete(vty, "ip route-source", - argv[idx_number]->arg, - RMAP_EVENT_FILTER_DELETED); -} + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:ip-route-source']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} -DEFUN (match_ip_route_source_prefix_list, - match_ip_route_source_prefix_list_cmd, - "match ip route-source prefix-list WORD", - MATCH_STR - IP_STR - "Match advertising source address of route\n" - "Match entries of prefix-lists\n" - "IP prefix-list name\n") +DEFUN_YANG (match_ip_route_source_prefix_list, + match_ip_route_source_prefix_list_cmd, + "match ip route-source prefix-list WORD", + MATCH_STR + IP_STR + "Match advertising source address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") { int idx_word = 4; - return bgp_route_match_add(vty, "ip route-source prefix-list", - argv[idx_word]->arg, RMAP_EVENT_PLIST_ADDED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:ip-route-source-prefix-list']"; + char xpath_value[XPATH_MAXLEN + 32]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_word]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_ip_route_source_prefix_list, - no_match_ip_route_source_prefix_list_cmd, - "no match ip route-source prefix-list [WORD]", - NO_STR - MATCH_STR - IP_STR - "Match advertising source address of route\n" - "Match entries of prefix-lists\n" - "IP prefix-list name\n") +DEFUN_YANG (no_match_ip_route_source_prefix_list, + no_match_ip_route_source_prefix_list_cmd, + "no match ip route-source prefix-list [WORD]", + NO_STR + MATCH_STR + IP_STR + "Match advertising source address of route\n" + "Match entries of prefix-lists\n" + "IP prefix-list name\n") { - int idx_word = 5; - if (argc <= idx_word) - return bgp_route_match_delete(vty, - "ip route-source prefix-list", - NULL, RMAP_EVENT_PLIST_DELETED); - return bgp_route_match_delete(vty, "ip route-source prefix-list", - argv[idx_word]->arg, - RMAP_EVENT_PLIST_DELETED); -} + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:ip-route-source-prefix-list']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} -DEFUN (match_local_pref, - match_local_pref_cmd, - "match local-preference (0-4294967295)", - MATCH_STR - "Match local-preference of route\n" - "Metric value\n") +DEFUN_YANG (match_local_pref, + match_local_pref_cmd, + "match local-preference (0-4294967295)", + MATCH_STR + "Match local-preference of route\n" + "Metric value\n") { int idx_number = 2; - return bgp_route_match_add(vty, "local-preference", - argv[idx_number]->arg, - RMAP_EVENT_MATCH_ADDED); + + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-local-preference']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:local-preference", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_number]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_local_pref, - no_match_local_pref_cmd, - "no match local-preference [(0-4294967295)]", - NO_STR - MATCH_STR - "Match local preference of route\n" - "Local preference value\n") +DEFUN_YANG (no_match_local_pref, + no_match_local_pref_cmd, + "no match local-preference [(0-4294967295)]", + NO_STR + MATCH_STR + "Match local preference of route\n" + "Local preference value\n") { int idx_localpref = 3; + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-local-preference']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + if (argc <= idx_localpref) - return bgp_route_match_delete(vty, "local-preference", NULL, - RMAP_EVENT_MATCH_DELETED); - return bgp_route_match_delete(vty, "local-preference", - argv[idx_localpref]->arg, - RMAP_EVENT_MATCH_DELETED); + return nb_cli_apply_changes(vty, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:local-preference", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, + argv[idx_localpref]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_community, +DEFPY_YANG (match_community, match_community_cmd, "match community <(1-99)|(100-500)|WORD> [exact-match]", MATCH_STR @@ -4312,478 +4417,608 @@ DEFUN (match_community, "Community-list name\n" "Do exact matching of communities\n") { + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-community']"; + char xpath_value[XPATH_MAXLEN]; + char xpath_match[XPATH_MAXLEN]; int idx_comm_list = 2; - int ret; - char *argstr; - size_t argstr_len; - if (argc == 4) { - argstr_len = strlen(argv[idx_comm_list]->arg) - + strlen("exact-match") + 2; - argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, argstr_len); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(argstr, argstr_len, "%s exact-match", - argv[idx_comm_list]->arg); - } else - argstr = argv[idx_comm_list]->arg; - - ret = bgp_route_match_add(vty, "community", argstr, - RMAP_EVENT_CLIST_ADDED); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_comm_list]->arg); - if (argstr != argv[idx_comm_list]->arg) - XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); - - return ret; -} - -DEFUN (no_match_community, - no_match_community_cmd, - "no match community [<(1-99)|(100-500)|WORD> [exact-match]]", - NO_STR - MATCH_STR - "Match BGP community list\n" - "Community-list number (standard)\n" - "Community-list number (expanded)\n" - "Community-list name\n" - "Do exact matching of communities\n") -{ - return bgp_route_match_delete(vty, "community", NULL, - RMAP_EVENT_CLIST_DELETED); -} + if (argc == 4) { + snprintf( + xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + xpath); + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, + "true"); + } else { + snprintf( + xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + xpath); + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, + "false"); + } -DEFUN (match_lcommunity, - match_lcommunity_cmd, - "match large-community <(1-99)|(100-500)|WORD> [exact-match]", - MATCH_STR - "Match BGP large community list\n" - "Large Community-list number (standard)\n" - "Large Community-list number (expanded)\n" - "Large Community-list name\n" - "Do exact matching of communities\n") -{ + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_community, + no_match_community_cmd, + "no match community [<(1-99)|(100-500)|WORD> [exact-match]]", + NO_STR + MATCH_STR + "Match BGP community list\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Do exact matching of communities\n") +{ + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-community']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG (match_lcommunity, + match_lcommunity_cmd, + "match large-community <(1-99)|(100-500)|WORD> [exact-match]", + MATCH_STR + "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n" + "Do exact matching of communities\n") +{ + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-large-community']"; + char xpath_value[XPATH_MAXLEN]; + char xpath_match[XPATH_MAXLEN]; int idx_lcomm_list = 2; - int ret; - char *argstr; - size_t argstr_len; - if (argc == 4) { - argstr_len = strlen(argv[idx_lcomm_list]->arg) - + strlen("exact-match") + 2; - argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, argstr_len); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(argstr, argstr_len, "%s exact-match", - argv[idx_lcomm_list]->arg); - } else - argstr = argv[idx_lcomm_list]->arg; + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_lcomm_list]->arg); - ret = bgp_route_match_add(vty, "large-community", argstr, - RMAP_EVENT_LLIST_ADDED); - if (argstr != argv[idx_lcomm_list]->arg) - XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); + if (argc == 4) { + snprintf( + xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + xpath); + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, + "true"); + } else { + snprintf( + xpath_match, sizeof(xpath_match), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + xpath); + nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, + "false"); + } - return ret; + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_lcommunity, - no_match_lcommunity_cmd, - "no match large-community [<(1-99)|(100-500)|WORD> [exact-match]]", - NO_STR - MATCH_STR - "Match BGP large community list\n" - "Large Community-list number (standard)\n" - "Large Community-list number (expanded)\n" - "Large Community-list name\n" - "Do exact matching of communities\n") +DEFUN_YANG (no_match_lcommunity, + no_match_lcommunity_cmd, + "no match large-community [<(1-99)|(100-500)|WORD> [exact-match]]", + NO_STR + MATCH_STR + "Match BGP large community list\n" + "Large Community-list number (standard)\n" + "Large Community-list number (expanded)\n" + "Large Community-list name\n" + "Do exact matching of communities\n") { - return bgp_route_match_delete(vty, "large-community", NULL, - RMAP_EVENT_LLIST_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-large-community']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_ecommunity, - match_ecommunity_cmd, - "match extcommunity <(1-99)|(100-500)|WORD>", - MATCH_STR - "Match BGP/VPN extended community list\n" - "Extended community-list number (standard)\n" - "Extended community-list number (expanded)\n" - "Extended community-list name\n") +DEFPY_YANG (match_ecommunity, + match_ecommunity_cmd, + "match extcommunity <(1-99)|(100-500)|WORD>", + MATCH_STR + "Match BGP/VPN extended community list\n" + "Extended community-list number (standard)\n" + "Extended community-list number (expanded)\n" + "Extended community-list name\n") { + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-extcommunity']"; + char xpath_value[XPATH_MAXLEN]; int idx_comm_list = 2; - return bgp_route_match_add(vty, "extcommunity", - argv[idx_comm_list]->arg, - RMAP_EVENT_ECLIST_ADDED); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_comm_list]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_ecommunity, - no_match_ecommunity_cmd, - "no match extcommunity [<(1-99)|(100-500)|WORD>]", - NO_STR - MATCH_STR - "Match BGP/VPN extended community list\n" - "Extended community-list number (standard)\n" - "Extended community-list number (expanded)\n" - "Extended community-list name\n") +DEFUN_YANG (no_match_ecommunity, + no_match_ecommunity_cmd, + "no match extcommunity [<(1-99)|(100-500)|WORD>]", + NO_STR + MATCH_STR + "Match BGP/VPN extended community list\n" + "Extended community-list number (standard)\n" + "Extended community-list number (expanded)\n" + "Extended community-list name\n") { - return bgp_route_match_delete(vty, "extcommunity", NULL, - RMAP_EVENT_ECLIST_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-extcommunity']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_aspath, - match_aspath_cmd, - "match as-path WORD", - MATCH_STR - "Match BGP AS path list\n" - "AS path access-list name\n") +DEFUN_YANG (match_aspath, + match_aspath_cmd, + "match as-path WORD", + MATCH_STR + "Match BGP AS path list\n" + "AS path access-list name\n") { int idx_word = 2; - return bgp_route_match_add(vty, "as-path", argv[idx_word]->arg, - RMAP_EVENT_ASLIST_ADDED); + + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:as-path-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_word]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_aspath, - no_match_aspath_cmd, - "no match as-path [WORD]", - NO_STR - MATCH_STR - "Match BGP AS path list\n" - "AS path access-list name\n") +DEFUN_YANG (no_match_aspath, + no_match_aspath_cmd, + "no match as-path [WORD]", + NO_STR + MATCH_STR + "Match BGP AS path list\n" + "AS path access-list name\n") { - return bgp_route_match_delete(vty, "as-path", NULL, - RMAP_EVENT_ASLIST_DELETED); -} + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:as-path-list']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); -DEFUN (match_origin, - match_origin_cmd, - "match origin <egp|igp|incomplete>", - MATCH_STR - "BGP origin code\n" - "remote EGP\n" - "local IGP\n" - "unknown heritage\n") + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (match_origin, + match_origin_cmd, + "match origin <egp|igp|incomplete>", + MATCH_STR + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") { int idx_origin = 2; + const char *origin_type; + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-origin']"; + char xpath_value[XPATH_MAXLEN]; + if (strncmp(argv[idx_origin]->arg, "igp", 2) == 0) - return bgp_route_match_add(vty, "origin", "igp", - RMAP_EVENT_MATCH_ADDED); - if (strncmp(argv[idx_origin]->arg, "egp", 1) == 0) - return bgp_route_match_add(vty, "origin", "egp", - RMAP_EVENT_MATCH_ADDED); - if (strncmp(argv[idx_origin]->arg, "incomplete", 2) == 0) - return bgp_route_match_add(vty, "origin", "incomplete", - RMAP_EVENT_MATCH_ADDED); + origin_type = "igp"; + else if (strncmp(argv[idx_origin]->arg, "egp", 1) == 0) + origin_type = "egp"; + else if (strncmp(argv[idx_origin]->arg, "incomplete", 2) == 0) + origin_type = "incomplete"; + else { + vty_out(vty, "%% Invalid match origin type\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:origin", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, origin_type); - vty_out(vty, "%% Invalid match origin type\n"); - return CMD_WARNING_CONFIG_FAILED; + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_origin, - no_match_origin_cmd, - "no match origin [<egp|igp|incomplete>]", - NO_STR - MATCH_STR - "BGP origin code\n" - "remote EGP\n" - "local IGP\n" - "unknown heritage\n") +DEFUN_YANG (no_match_origin, + no_match_origin_cmd, + "no match origin [<egp|igp|incomplete>]", + NO_STR + MATCH_STR + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") { - return bgp_route_match_delete(vty, "origin", NULL, - RMAP_EVENT_MATCH_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:match-origin']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_table_id, - set_table_id_cmd, - "set table (1-4294967295)", - SET_STR - "export route to non-main kernel table\n" - "Kernel routing table id\n") +DEFUN_YANG (set_table_id, + set_table_id_cmd, + "set table (1-4294967295)", + SET_STR + "export route to non-main kernel table\n" + "Kernel routing table id\n") { - int idx_id = 2; - - VTY_DECLVAR_CONTEXT(route_map_index, index); - - return generic_set_add(vty, index, "table", argv[idx_id]->arg); + int idx_number = 2; + const char *xpath = "./set-action[action='frr-bgp-route-map:table']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:table", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_number]->arg); + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_set_table_id, + no_set_table_id_cmd, + "no set table", + NO_STR + SET_STR + "export route to non-main kernel table\n") +{ + const char *xpath = "./set-action[action='frr-bgp-route-map:table']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (set_ip_nexthop_peer, + set_ip_nexthop_peer_cmd, + "[no] set ip next-hop peer-address", + NO_STR + SET_STR + IP_STR + "Next hop address\n" + "Use peer address (for BGP only)\n") +{ + char xpath_value[XPATH_MAXLEN]; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-ipv4-nexthop']"; + + if (strmatch(argv[0]->text, "no")) + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + else { + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:ipv4-nexthop", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + "peer-address"); + } + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_table_id, - no_set_table_id_cmd, - "no set table", - NO_STR - SET_STR - "export route to non-main kernel table\n") +DEFUN_YANG (set_ip_nexthop_unchanged, + set_ip_nexthop_unchanged_cmd, + "[no] set ip next-hop unchanged", + NO_STR + SET_STR + IP_STR + "Next hop address\n" + "Don't modify existing Next hop address\n") { - VTY_DECLVAR_CONTEXT(route_map_index, index); + char xpath_value[XPATH_MAXLEN]; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-ipv4-nexthop']"; - return generic_set_delete(vty, index, "table", NULL); + if (strmatch(argv[0]->text, "no")) + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + else { + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:ipv4-nexthop", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + "unchanged"); + } + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_ip_nexthop_peer, - set_ip_nexthop_peer_cmd, - "[no] set ip next-hop peer-address", - NO_STR - SET_STR - IP_STR - "Next hop address\n" - "Use peer address (for BGP only)\n") +DEFUN_YANG (set_distance, + set_distance_cmd, + "set distance (0-255)", + SET_STR + "BGP Administrative Distance to use\n" + "Distance value\n") { - int (*func)(struct vty *, struct route_map_index *, const char *, - const char *) = strmatch(argv[0]->text, "no") - ? generic_set_delete - : generic_set_add; + int idx_number = 2; + const char *xpath = "./set-action[action='frr-bgp-route-map:distance']"; + char xpath_value[XPATH_MAXLEN]; - return func(vty, VTY_GET_CONTEXT(route_map_index), "ip next-hop", - "peer-address"); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:distance", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_number]->arg); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_ip_nexthop_unchanged, - set_ip_nexthop_unchanged_cmd, - "[no] set ip next-hop unchanged", - NO_STR - SET_STR - IP_STR - "Next hop address\n" - "Don't modify existing Next hop address\n") +DEFUN_YANG (no_set_distance, + no_set_distance_cmd, + "no set distance [(0-255)]", + NO_STR SET_STR + "BGP Administrative Distance to use\n" + "Distance value\n") { - int (*func)(struct vty *, struct route_map_index *, const char *, - const char *) = strmatch(argv[0]->text, "no") - ? generic_set_delete - : generic_set_add; + const char *xpath = "./set-action[action='frr-bgp-route-map:distance']"; - return func(vty, VTY_GET_CONTEXT(route_map_index), "ip next-hop", - "unchanged"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_distance, - set_distance_cmd, - "set distance (0-255)", - SET_STR - "BGP Administrative Distance to use\n" - "Distance value\n") +DEFUN_YANG (set_local_pref, + set_local_pref_cmd, + "set local-preference WORD", + SET_STR + "BGP local preference path attribute\n" + "Preference value (0-4294967295)\n") { int idx_number = 2; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-local-preference']"; + char xpath_value[XPATH_MAXLEN]; - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "distance", argv[idx_number]->arg); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:local-pref", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_number]->arg); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_distance, - no_set_distance_cmd, - "no set distance [(0-255)]", - NO_STR SET_STR - "BGP Administrative Distance to use\n" - "Distance value\n") +DEFUN_YANG (no_set_local_pref, + no_set_local_pref_cmd, + "no set local-preference [WORD]", + NO_STR + SET_STR + "BGP local preference path attribute\n" + "Preference value (0-4294967295)\n") { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "distance", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-local-preference']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_local_pref, - set_local_pref_cmd, - "set local-preference WORD", - SET_STR - "BGP local preference path attribute\n" - "Preference value (0-4294967295)\n") +DEFUN_YANG (set_weight, + set_weight_cmd, + "set weight (0-4294967295)", + SET_STR + "BGP weight for routing table\n" + "Weight value\n") { int idx_number = 2; - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "local-preference", argv[idx_number]->arg); -} - + const char *xpath = "./set-action[action='frr-bgp-route-map:weight']"; + char xpath_value[XPATH_MAXLEN]; -DEFUN (no_set_local_pref, - no_set_local_pref_cmd, - "no set local-preference [WORD]", - NO_STR - SET_STR - "BGP local preference path attribute\n" - "Preference value (0-4294967295)\n") -{ - int idx_localpref = 3; - if (argc <= idx_localpref) - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "local-preference", NULL); - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "local-preference", argv[idx_localpref]->arg); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:weight", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_number]->arg); + return nb_cli_apply_changes(vty, NULL); } - -DEFUN (set_weight, - set_weight_cmd, - "set weight (0-4294967295)", - SET_STR - "BGP weight for routing table\n" - "Weight value\n") +DEFUN_YANG (no_set_weight, + no_set_weight_cmd, + "no set weight [(0-4294967295)]", + NO_STR + SET_STR + "BGP weight for routing table\n" + "Weight value\n") { - int idx_number = 2; - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), "weight", - argv[idx_number]->arg); -} + const char *xpath = "./set-action[action='frr-bgp-route-map:weight']"; - -DEFUN (no_set_weight, - no_set_weight_cmd, - "no set weight [(0-4294967295)]", - NO_STR - SET_STR - "BGP weight for routing table\n" - "Weight value\n") -{ - int idx_weight = 3; - if (argc <= idx_weight) - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "weight", NULL); - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "weight", argv[idx_weight]->arg); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_label_index, - set_label_index_cmd, - "set label-index (0-1048560)", - SET_STR - "Label index to associate with the prefix\n" - "Label index value\n") +DEFUN_YANG (set_label_index, + set_label_index_cmd, + "set label-index (0-1048560)", + SET_STR + "Label index to associate with the prefix\n" + "Label index value\n") { int idx_number = 2; - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "label-index", argv[idx_number]->arg); + const char *xpath = + "./set-action[action='frr-bgp-route-map:label-index']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:label-index", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_number]->arg); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_label_index, - no_set_label_index_cmd, - "no set label-index [(0-1048560)]", - NO_STR - SET_STR - "Label index to associate with the prefix\n" - "Label index value\n") +DEFUN_YANG (no_set_label_index, + no_set_label_index_cmd, + "no set label-index [(0-1048560)]", + NO_STR + SET_STR + "Label index to associate with the prefix\n" + "Label index value\n") { - int idx_label_index = 3; - if (argc <= idx_label_index) - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "label-index", NULL); - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "label-index", argv[idx_label_index]->arg); + const char *xpath = + "./set-action[action='frr-bgp-route-map:label-index']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_aspath_prepend_asn, - set_aspath_prepend_asn_cmd, - "set as-path prepend (1-4294967295)...", - SET_STR - "Transform BGP AS_PATH attribute\n" - "Prepend to the as-path\n" - "AS number\n") +DEFUN_YANG (set_aspath_prepend_asn, + set_aspath_prepend_asn_cmd, + "set as-path prepend (1-4294967295)...", + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + "AS number\n") { int idx_asn = 3; int ret; char *str; str = argv_concat(argv, argc, idx_asn); - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "as-path prepend", str); - XFREE(MTYPE_TMP, str); + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-prepend']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:prepend-as-path", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); + ret = nb_cli_apply_changes(vty, NULL); + XFREE(MTYPE_TMP, str); return ret; } -DEFUN (set_aspath_prepend_lastas, - set_aspath_prepend_lastas_cmd, - "set as-path prepend last-as (1-10)", - SET_STR - "Transform BGP AS_PATH attribute\n" - "Prepend to the as-path\n" - "Use the peer's AS-number\n" - "Number of times to insert\n") +DEFUN_YANG (set_aspath_prepend_lastas, + set_aspath_prepend_lastas_cmd, + "set as-path prepend last-as (1-10)", + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + "Use the peer's AS-number\n" + "Number of times to insert\n") { - return set_aspath_prepend_asn(self, vty, argc, argv); + int idx_num = 4; + + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-prepend']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:last-as", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_num]->arg); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_aspath_prepend, - no_set_aspath_prepend_cmd, - "no set as-path prepend [(1-4294967295)]", - NO_STR - SET_STR - "Transform BGP AS_PATH attribute\n" - "Prepend to the as-path\n" - "AS number\n") +DEFUN_YANG (no_set_aspath_prepend, + no_set_aspath_prepend_cmd, + "no set as-path prepend [(1-4294967295)]", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + "AS number\n") { - int idx_asn = 4; - int ret; - char *str; + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-prepend']"; - str = argv_concat(argv, argc, idx_asn); - ret = generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "as-path prepend", str); - XFREE(MTYPE_TMP, str); - return ret; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_aspath_prepend_lastas, - no_set_aspath_prepend_lastas_cmd, - "no set as-path prepend last-as [(1-10)]", - NO_STR - SET_STR - "Transform BGP AS_PATH attribute\n" - "Prepend to the as-path\n" - "Use the peers AS-number\n" - "Number of times to insert\n") +DEFUN_YANG (no_set_aspath_prepend_lastas, + no_set_aspath_prepend_lastas_cmd, + "no set as-path prepend last-as [(1-10)]", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + "Use the peers AS-number\n" + "Number of times to insert\n") { - return no_set_aspath_prepend(self, vty, argc, argv); + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-prepend']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_aspath_exclude, - set_aspath_exclude_cmd, - "set as-path exclude (1-4294967295)...", - SET_STR - "Transform BGP AS-path attribute\n" - "Exclude from the as-path\n" - "AS number\n") +DEFUN_YANG (set_aspath_exclude, + set_aspath_exclude_cmd, + "set as-path exclude (1-4294967295)...", + SET_STR + "Transform BGP AS-path attribute\n" + "Exclude from the as-path\n" + "AS number\n") { int idx_asn = 3; int ret; char *str; str = argv_concat(argv, argc, idx_asn); - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "as-path exclude", str); + + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-exclude']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:exclude-as-path", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); + ret = nb_cli_apply_changes(vty, NULL); XFREE(MTYPE_TMP, str); return ret; } -DEFUN (no_set_aspath_exclude, - no_set_aspath_exclude_cmd, - "no set as-path exclude (1-4294967295)...", - NO_STR - SET_STR - "Transform BGP AS_PATH attribute\n" - "Exclude from the as-path\n" - "AS number\n") +DEFUN_YANG (no_set_aspath_exclude, + no_set_aspath_exclude_cmd, + "no set as-path exclude (1-4294967295)...", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Exclude from the as-path\n" + "AS number\n") { - int idx_asn = 4; - int ret; - char *str; + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-exclude']"; - str = argv_concat(argv, argc, idx_asn); - ret = generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "as-path exclude", str); - XFREE(MTYPE_TMP, str); - return ret; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -ALIAS(no_set_aspath_exclude, no_set_aspath_exclude_all_cmd, - "no set as-path exclude", - NO_STR SET_STR - "Transform BGP AS_PATH attribute\n" - "Exclude from the as-path\n") +ALIAS_YANG (no_set_aspath_exclude, no_set_aspath_exclude_all_cmd, + "no set as-path exclude", + NO_STR SET_STR + "Transform BGP AS_PATH attribute\n" + "Exclude from the as-path\n") -DEFUN (set_community, - set_community_cmd, - "set community AA:NN...", - SET_STR - "BGP community attribute\n" - COMMUNITY_VAL_STR) +DEFUN_YANG (set_community, + set_community_cmd, + "set community AA:NN...", + SET_STR + "BGP community attribute\n" + COMMUNITY_VAL_STR) { int idx_aa_nn = 2; int i; @@ -4792,9 +5027,18 @@ DEFUN (set_community, struct buffer *b; struct community *com = NULL; char *str; - char *argstr; + char *argstr = NULL; int ret; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-community']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:community-string", + xpath); + b = buffer_new(1024); for (i = idx_aa_nn; i < argc; i++) { @@ -4870,50 +5114,61 @@ DEFUN (set_community, argstr = XCALLOC(MTYPE_TMP, argstr_sz); strlcpy(argstr, str, argstr_sz); strlcat(argstr, " additive", argstr_sz); - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "community", argstr); - XFREE(MTYPE_TMP, argstr); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argstr); } else - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "community", str); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); + + ret = nb_cli_apply_changes(vty, NULL); + if (argstr) + XFREE(MTYPE_TMP, argstr); community_free(&com); return ret; } -DEFUN (set_community_none, - set_community_none_cmd, - "set community none", - SET_STR - "BGP community attribute\n" - "No community attribute\n") +DEFUN_YANG (set_community_none, + set_community_none_cmd, + "set community none", + SET_STR + "BGP community attribute\n" + "No community attribute\n") { - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "community", "none"); + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-community']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:community-none", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "true"); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_community, - no_set_community_cmd, - "no set community AA:NN...", - NO_STR - SET_STR - "BGP community attribute\n" - COMMUNITY_VAL_STR) +DEFUN_YANG (no_set_community, + no_set_community_cmd, + "no set community AA:NN...", + NO_STR + SET_STR + "BGP community attribute\n" + COMMUNITY_VAL_STR) { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "community", NULL); -} + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-community']"; -ALIAS (no_set_community, - no_set_community_short_cmd, - "no set community", - NO_STR - SET_STR - "BGP community attribute\n") + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} +ALIAS_YANG (no_set_community, + no_set_community_short_cmd, + "no set community", + NO_STR + SET_STR + "BGP community attribute\n") -DEFUN (set_community_delete, +DEFPY_YANG (set_community_delete, set_community_delete_cmd, "set comm-list <(1-99)|(100-500)|WORD> delete", SET_STR @@ -4923,93 +5178,124 @@ DEFUN (set_community_delete, "Community-list name\n" "Delete matching communities\n") { + const char *xpath = + "./set-action[action='frr-bgp-route-map:comm-list-delete']"; + char xpath_value[XPATH_MAXLEN]; int idx_comm_list = 2; - char *args; - args = argv_concat(argv, argc, idx_comm_list); - generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), "comm-list", - args); - XFREE(MTYPE_TMP, args); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:comm-list-name", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_comm_list]->arg); + + return nb_cli_apply_changes(vty, NULL); - return CMD_SUCCESS; } -DEFUN (no_set_community_delete, - no_set_community_delete_cmd, - "no set comm-list [<(1-99)|(100-500)|WORD> delete]", - NO_STR - SET_STR - "set BGP community list (for deletion)\n" - "Community-list number (standard)\n" - "Community-list number (expanded)\n" - "Community-list name\n" - "Delete matching communities\n") +DEFUN_YANG (no_set_community_delete, + no_set_community_delete_cmd, + "no set comm-list [<(1-99)|(100-500)|WORD> delete]", + NO_STR + SET_STR + "set BGP community list (for deletion)\n" + "Community-list number (standard)\n" + "Community-list number (expanded)\n" + "Community-list name\n" + "Delete matching communities\n") { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "comm-list", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:comm-list-delete']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_lcommunity, - set_lcommunity_cmd, - "set large-community AA:BB:CC...", - SET_STR - "BGP large community attribute\n" - "Large Community number in aa:bb:cc format or additive\n") +DEFUN_YANG (set_lcommunity, + set_lcommunity_cmd, + "set large-community AA:BB:CC...", + SET_STR + "BGP large community attribute\n" + "Large Community number in aa:bb:cc format or additive\n") { - int ret; char *str; + int ret; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-large-community']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:large-community-string", + xpath); str = argv_concat(argv, argc, 2); - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "large-community", str); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); + ret = nb_cli_apply_changes(vty, NULL); XFREE(MTYPE_TMP, str); - return ret; } -DEFUN (set_lcommunity_none, - set_lcommunity_none_cmd, - "set large-community none", - SET_STR - "BGP large community attribute\n" - "No large community attribute\n") +DEFUN_YANG (set_lcommunity_none, + set_lcommunity_none_cmd, + "set large-community none", + SET_STR + "BGP large community attribute\n" + "No large community attribute\n") { - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "large-community", "none"); + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-large-community']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:large-community-none", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "true"); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_lcommunity, - no_set_lcommunity_cmd, - "no set large-community none", - NO_STR - SET_STR - "BGP large community attribute\n" - "No community attribute\n") +DEFUN_YANG (no_set_lcommunity, + no_set_lcommunity_cmd, + "no set large-community none", + NO_STR + SET_STR + "BGP large community attribute\n" + "No community attribute\n") { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "large-community", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-large-community']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_lcommunity1, - no_set_lcommunity1_cmd, - "no set large-community AA:BB:CC...", - NO_STR - SET_STR - "BGP large community attribute\n" - "Large community in AA:BB:CC... format or additive\n") +DEFUN_YANG (no_set_lcommunity1, + no_set_lcommunity1_cmd, + "no set large-community AA:BB:CC...", + NO_STR + SET_STR + "BGP large community attribute\n" + "Large community in AA:BB:CC... format or additive\n") { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "large-community", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-large-community']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -ALIAS (no_set_lcommunity1, - no_set_lcommunity1_short_cmd, - "no set large-community", - NO_STR - SET_STR - "BGP large community attribute\n") +ALIAS_YANG (no_set_lcommunity1, + no_set_lcommunity1_short_cmd, + "no set large-community", + NO_STR + SET_STR + "BGP large community attribute\n") -DEFUN (set_lcommunity_delete, +DEFPY_YANG (set_lcommunity_delete, set_lcommunity_delete_cmd, "set large-comm-list <(1-99)|(100-500)|WORD> delete", SET_STR @@ -5019,336 +5305,401 @@ DEFUN (set_lcommunity_delete, "Large Community-list name\n" "Delete matching large communities\n") { + const char *xpath = + "./set-action[action='frr-bgp-route-map:large-comm-list-delete']"; + char xpath_value[XPATH_MAXLEN]; int idx_lcomm_list = 2; - char *args; - args = argv_concat(argv, argc, idx_lcomm_list); - generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "large-comm-list", args); - XFREE(MTYPE_TMP, args); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - return CMD_SUCCESS; + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:comm-list-name", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_lcomm_list]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_lcommunity_delete, - no_set_lcommunity_delete_cmd, - "no set large-comm-list <(1-99)|(100-500)|WORD> [delete]", - NO_STR - SET_STR - "set BGP large community list (for deletion)\n" - "Large Community-list number (standard)\n" - "Large Communitly-list number (expanded)\n" - "Large Community-list name\n" - "Delete matching large communities\n") +DEFUN_YANG (no_set_lcommunity_delete, + no_set_lcommunity_delete_cmd, + "no set large-comm-list <(1-99)|(100-500)|WORD> [delete]", + NO_STR + SET_STR + "set BGP large community list (for deletion)\n" + "Large Community-list number (standard)\n" + "Large Communitly-list number (expanded)\n" + "Large Community-list name\n" + "Delete matching large communities\n") { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "large-comm-list", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:large-comm-list-delete']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -ALIAS (no_set_lcommunity_delete, - no_set_lcommunity_delete_short_cmd, - "no set large-comm-list", - NO_STR - SET_STR - "set BGP large community list (for deletion)\n") +ALIAS_YANG (no_set_lcommunity_delete, + no_set_lcommunity_delete_short_cmd, + "no set large-comm-list", + NO_STR + SET_STR + "set BGP large community list (for deletion)\n") -DEFUN (set_ecommunity_rt, - set_ecommunity_rt_cmd, - "set extcommunity rt ASN:NN_OR_IP-ADDRESS:NN...", - SET_STR - "BGP extended community attribute\n" - "Route Target extended community\n" - "VPN extended community\n") +DEFUN_YANG (set_ecommunity_rt, + set_ecommunity_rt_cmd, + "set extcommunity rt ASN:NN_OR_IP-ADDRESS:NN...", + SET_STR + "BGP extended community attribute\n" + "Route Target extended community\n" + "VPN extended community\n") { int idx_asn_nn = 3; - int ret; char *str; + int ret; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-extcommunity-rt']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:extcommunity-rt", xpath); str = argv_concat(argv, argc, idx_asn_nn); - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "extcommunity rt", str); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); + ret = nb_cli_apply_changes(vty, NULL); XFREE(MTYPE_TMP, str); - return ret; } -DEFUN (no_set_ecommunity_rt, - no_set_ecommunity_rt_cmd, - "no set extcommunity rt ASN:NN_OR_IP-ADDRESS:NN...", - NO_STR - SET_STR - "BGP extended community attribute\n" - "Route Target extended community\n" - "VPN extended community\n") -{ - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "extcommunity rt", NULL); -} - -ALIAS (no_set_ecommunity_rt, - no_set_ecommunity_rt_short_cmd, - "no set extcommunity rt", - NO_STR - SET_STR - "BGP extended community attribute\n" - "Route Target extended community\n") - -DEFUN (set_ecommunity_soo, - set_ecommunity_soo_cmd, - "set extcommunity soo ASN:NN_OR_IP-ADDRESS:NN...", - SET_STR - "BGP extended community attribute\n" - "Site-of-Origin extended community\n" - "VPN extended community\n") +DEFUN_YANG (no_set_ecommunity_rt, + no_set_ecommunity_rt_cmd, + "no set extcommunity rt ASN:NN_OR_IP-ADDRESS:NN...", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Route Target extended community\n" + "VPN extended community\n") +{ + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-extcommunity-rt']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +ALIAS_YANG (no_set_ecommunity_rt, + no_set_ecommunity_rt_short_cmd, + "no set extcommunity rt", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Route Target extended community\n") + +DEFUN_YANG (set_ecommunity_soo, + set_ecommunity_soo_cmd, + "set extcommunity soo ASN:NN_OR_IP-ADDRESS:NN...", + SET_STR + "BGP extended community attribute\n" + "Site-of-Origin extended community\n" + "VPN extended community\n") { int idx_asn_nn = 3; - int ret; char *str; + int ret; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-extcommunity-soo']"; + char xpath_value[XPATH_MAXLEN]; + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:extcommunity-soo", + xpath); str = argv_concat(argv, argc, idx_asn_nn); - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "extcommunity soo", str); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); + ret = nb_cli_apply_changes(vty, NULL); XFREE(MTYPE_TMP, str); return ret; } - -DEFUN (no_set_ecommunity_soo, - no_set_ecommunity_soo_cmd, - "no set extcommunity soo ASN:NN_OR_IP-ADDRESS:NN...", - NO_STR - SET_STR - "BGP extended community attribute\n" - "Site-of-Origin extended community\n" - "VPN extended community\n") +DEFUN_YANG (no_set_ecommunity_soo, + no_set_ecommunity_soo_cmd, + "no set extcommunity soo ASN:NN_OR_IP-ADDRESS:NN...", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Site-of-Origin extended community\n" + "VPN extended community\n") +{ + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-extcommunity-soo']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +ALIAS_YANG (no_set_ecommunity_soo, + no_set_ecommunity_soo_short_cmd, + "no set extcommunity soo", + NO_STR + SET_STR + "GP extended community attribute\n" + "Site-of-Origin extended community\n") + +DEFUN_YANG (set_ecommunity_lb, + set_ecommunity_lb_cmd, + "set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]", + SET_STR + "BGP extended community attribute\n" + "Link bandwidth extended community\n" + "Bandwidth value in Mbps\n" + "Cumulative bandwidth of all multipaths (outbound-only)\n" + "Internally computed bandwidth based on number of multipaths (outbound-only)\n" + "Attribute is set as non-transitive\n") { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "extcommunity soo", NULL); -} - -ALIAS (no_set_ecommunity_soo, - no_set_ecommunity_soo_short_cmd, - "no set extcommunity soo", - NO_STR - SET_STR - "GP extended community attribute\n" - "Site-of-Origin extended community\n") + int idx_lb = 3; + int idx_non_transitive = 4; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-extcommunity-lb']"; + char xpath_lb_type[XPATH_MAXLEN]; + char xpath_bandwidth[XPATH_MAXLEN]; + char xpath_non_transitive[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath_lb_type, sizeof(xpath_lb_type), + "%s/rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type", + xpath); + snprintf(xpath_bandwidth, sizeof(xpath_bandwidth), + "%s/rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth", + xpath); + snprintf(xpath_non_transitive, sizeof(xpath_non_transitive), + "%s/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific", + xpath); + + if ((strcmp(argv[idx_lb]->arg, "cumulative")) == 0) + nb_cli_enqueue_change(vty, xpath_lb_type, NB_OP_MODIFY, + "cumulative-bandwidth"); + else if ((strcmp(argv[idx_lb]->arg, "num-multipaths")) == 0) + nb_cli_enqueue_change(vty, xpath_lb_type, NB_OP_MODIFY, + "computed-bandwidth"); + else { + nb_cli_enqueue_change(vty, xpath_lb_type, NB_OP_MODIFY, + "explicit-bandwidth"); + nb_cli_enqueue_change(vty, xpath_bandwidth, NB_OP_MODIFY, + argv[idx_lb]->arg); + } -DEFUN (set_ecommunity_lb, - set_ecommunity_lb_cmd, - "set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]", - SET_STR - "BGP extended community attribute\n" - "Link bandwidth extended community\n" - "Bandwidth value in Mbps\n" - "Cumulative bandwidth of all multipaths (outbound-only)\n" - "Internally computed bandwidth based on number of multipaths (outbound-only)\n" - "Attribute is set as non-transitive\n") + if (argv[idx_non_transitive]) + nb_cli_enqueue_change(vty, xpath_non_transitive, NB_OP_MODIFY, + "true"); + else + nb_cli_enqueue_change(vty, xpath_non_transitive, NB_OP_MODIFY, + "false"); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_set_ecommunity_lb, + no_set_ecommunity_lb_cmd, + "no set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Link bandwidth extended community\n" + "Bandwidth value in Mbps\n" + "Cumulative bandwidth of all multipaths (outbound-only)\n" + "Internally computed bandwidth based on number of multipaths (outbound-only)\n" + "Attribute is set as non-transitive\n") +{ + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-extcommunity-lb']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +ALIAS_YANG (no_set_ecommunity_lb, + no_set_ecommunity_lb_short_cmd, + "no set extcommunity bandwidth", + NO_STR + SET_STR + "BGP extended community attribute\n" + "Link bandwidth extended community\n") + +DEFUN_YANG (set_origin, + set_origin_cmd, + "set origin <egp|igp|incomplete>", + SET_STR + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") { - int idx_lb = 3; - int ret; - char *str; + int idx_origin = 2; + const char *origin_type; + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-origin']"; + char xpath_value[XPATH_MAXLEN]; - str = argv_concat(argv, argc, idx_lb); - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "extcommunity bandwidth", str); - XFREE(MTYPE_TMP, str); - return ret; -} + if (strncmp(argv[idx_origin]->arg, "igp", 2) == 0) + origin_type = "igp"; + else if (strncmp(argv[idx_origin]->arg, "egp", 1) == 0) + origin_type = "egp"; + else if (strncmp(argv[idx_origin]->arg, "incomplete", 2) == 0) + origin_type = "incomplete"; + else { + vty_out(vty, "%% Invalid match origin type\n"); + return CMD_WARNING_CONFIG_FAILED; + } + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:origin", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, origin_type); -DEFUN (no_set_ecommunity_lb, - no_set_ecommunity_lb_cmd, - "no set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]", - NO_STR - SET_STR - "BGP extended community attribute\n" - "Link bandwidth extended community\n" - "Bandwidth value in Mbps\n" - "Cumulative bandwidth of all multipaths (outbound-only)\n" - "Internally computed bandwidth based on number of multipaths (outbound-only)\n" - "Attribute is set as non-transitive\n") -{ - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "extcommunity bandwidth", NULL); + return nb_cli_apply_changes(vty, NULL); } -ALIAS (no_set_ecommunity_lb, - no_set_ecommunity_lb_short_cmd, - "no set extcommunity bandwidth", - NO_STR - SET_STR - "BGP extended community attribute\n" - "Link bandwidth extended community\n") - -DEFUN (set_origin, - set_origin_cmd, - "set origin <egp|igp|incomplete>", - SET_STR - "BGP origin code\n" - "remote EGP\n" - "local IGP\n" - "unknown heritage\n") +DEFUN_YANG (no_set_origin, + no_set_origin_cmd, + "no set origin [<egp|igp|incomplete>]", + NO_STR + SET_STR + "BGP origin code\n" + "remote EGP\n" + "local IGP\n" + "unknown heritage\n") { - int idx_origin = 2; - if (strncmp(argv[idx_origin]->arg, "igp", 2) == 0) - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "origin", "igp"); - if (strncmp(argv[idx_origin]->arg, "egp", 1) == 0) - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "origin", "egp"); - if (strncmp(argv[idx_origin]->arg, "incomplete", 2) == 0) - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "origin", "incomplete"); + const char *xpath = + "./set-action[action='frr-bgp-route-map:set-origin']"; - vty_out(vty, "%% Invalid set origin type\n"); - return CMD_WARNING_CONFIG_FAILED; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } - -DEFUN (no_set_origin, - no_set_origin_cmd, - "no set origin [<egp|igp|incomplete>]", - NO_STR - SET_STR - "BGP origin code\n" - "remote EGP\n" - "local IGP\n" - "unknown heritage\n") +DEFUN_YANG (set_atomic_aggregate, + set_atomic_aggregate_cmd, + "set atomic-aggregate", + SET_STR + "BGP atomic aggregate attribute\n" ) { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "origin", NULL); -} + const char *xpath = + "./set-action[action='frr-bgp-route-map:atomic-aggregate']"; + char xpath_value[XPATH_MAXLEN]; + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:atomic-aggregate", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, NULL); -DEFUN (set_atomic_aggregate, - set_atomic_aggregate_cmd, - "set atomic-aggregate", - SET_STR - "BGP atomic aggregate attribute\n" ) -{ - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "atomic-aggregate", NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_atomic_aggregate, - no_set_atomic_aggregate_cmd, - "no set atomic-aggregate", - NO_STR - SET_STR - "BGP atomic aggregate attribute\n" ) +DEFUN_YANG (no_set_atomic_aggregate, + no_set_atomic_aggregate_cmd, + "no set atomic-aggregate", + NO_STR + SET_STR + "BGP atomic aggregate attribute\n" ) { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "atomic-aggregate", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:atomic-aggregate']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_aggregator_as, - set_aggregator_as_cmd, - "set aggregator as (1-4294967295) A.B.C.D", - SET_STR - "BGP aggregator attribute\n" - "AS number of aggregator\n" - "AS number\n" - "IP address of aggregator\n") +DEFUN_YANG (set_aggregator_as, + set_aggregator_as_cmd, + "set aggregator as (1-4294967295) A.B.C.D", + SET_STR + "BGP aggregator attribute\n" + "AS number of aggregator\n" + "AS number\n" + "IP address of aggregator\n") { int idx_number = 3; int idx_ipv4 = 4; - int ret; - struct in_addr address; - char *argstr; - size_t argstr_len; + char xpath_asn[XPATH_MAXLEN]; + char xpath_addr[XPATH_MAXLEN]; + const char *xpath = + "./set-action[action='frr-bgp-route-map:aggregator']"; - ret = inet_aton(argv[idx_ipv4]->arg, &address); - if (ret == 0) { - vty_out(vty, "Aggregator IP address is invalid\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - argstr_len = - strlen(argv[idx_number]->arg) + strlen(argv[idx_ipv4]->arg) + 2; - argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, argstr_len); - - snprintf(argstr, argstr_len, "%s %s", argv[idx_number]->arg, - argv[idx_ipv4]->arg); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "aggregator as", argstr); + snprintf( + xpath_asn, sizeof(xpath_asn), + "%s/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn", + xpath); + nb_cli_enqueue_change(vty, xpath_asn, NB_OP_MODIFY, + argv[idx_number]->arg); - XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); + snprintf( + xpath_addr, sizeof(xpath_addr), + "%s/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address", + xpath); + nb_cli_enqueue_change(vty, xpath_addr, NB_OP_MODIFY, + argv[idx_ipv4]->arg); - return ret; + return nb_cli_apply_changes(vty, NULL); } - -DEFUN (no_set_aggregator_as, - no_set_aggregator_as_cmd, - "no set aggregator as [(1-4294967295) A.B.C.D]", - NO_STR - SET_STR - "BGP aggregator attribute\n" - "AS number of aggregator\n" - "AS number\n" - "IP address of aggregator\n") +DEFUN_YANG (no_set_aggregator_as, + no_set_aggregator_as_cmd, + "no set aggregator as [(1-4294967295) A.B.C.D]", + NO_STR + SET_STR + "BGP aggregator attribute\n" + "AS number of aggregator\n" + "AS number\n" + "IP address of aggregator\n") { - int idx_asn = 4; - int idx_ip = 5; - int ret; - struct in_addr address; - char *argstr; - size_t argstr_len; - - if (argc <= idx_asn) - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "aggregator as", NULL); - - ret = inet_aton(argv[idx_ip]->arg, &address); - if (ret == 0) { - vty_out(vty, "Aggregator IP address is invalid\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - argstr_len = strlen(argv[idx_asn]->arg) + strlen(argv[idx_ip]->arg) + 2; - argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, argstr_len); + const char *xpath = + "./set-action[action='frr-bgp-route-map:aggregator']"; - snprintf(argstr, argstr_len, "%s %s", argv[idx_asn]->arg, - argv[idx_ip]->arg); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} - ret = generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "aggregator as", argstr); +DEFUN_YANG (match_ipv6_next_hop, + match_ipv6_next_hop_cmd, + "match ipv6 next-hop X:X::X:X", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") +{ + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:ipv6-nexthop']"; + char xpath_value[XPATH_MAXLEN]; - XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:ipv6-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[3]->arg); - return ret; + return nb_cli_apply_changes(vty, NULL); } -DEFUN (match_ipv6_next_hop, - match_ipv6_next_hop_cmd, - "match ipv6 next-hop X:X::X:X", - MATCH_STR - IPV6_STR - "Match IPv6 next-hop address of route\n" - "IPv6 address of next hop\n") +DEFUN_YANG (no_match_ipv6_next_hop, + no_match_ipv6_next_hop_cmd, + "no match ipv6 next-hop X:X::X:X", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") { - int idx_ipv6 = 3; - return bgp_route_match_add(vty, "ipv6 next-hop", argv[idx_ipv6]->arg, - RMAP_EVENT_MATCH_ADDED); -} + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:ipv6-nexthop']"; -DEFUN (no_match_ipv6_next_hop, - no_match_ipv6_next_hop_cmd, - "no match ipv6 next-hop X:X::X:X", - NO_STR - MATCH_STR - IPV6_STR - "Match IPv6 next-hop address of route\n" - "IPv6 address of next hop\n") -{ - int idx_ipv6 = 4; - return bgp_route_match_delete(vty, "ipv6 next-hop", argv[idx_ipv6]->arg, - RMAP_EVENT_MATCH_DELETED); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFPY (match_ipv4_next_hop, +DEFPY_YANG (match_ipv4_next_hop, match_ipv4_next_hop_cmd, "match ip next-hop address A.B.C.D", MATCH_STR @@ -5357,13 +5708,20 @@ DEFPY (match_ipv4_next_hop, "IP address\n" "IP address of next-hop\n") { - int idx_ipv4 = 4; + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:ipv4-nexthop']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:ipv4-address", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[4]->arg); - return bgp_route_match_add(vty, "ip next-hop address", - argv[idx_ipv4]->arg, RMAP_EVENT_MATCH_ADDED); + return nb_cli_apply_changes(vty, NULL); } -DEFPY (no_match_ipv4_next_hop, +DEFPY_YANG (no_match_ipv4_next_hop, no_match_ipv4_next_hop_cmd, "no match ip next-hop address [A.B.C.D]", NO_STR @@ -5373,264 +5731,312 @@ DEFPY (no_match_ipv4_next_hop, "IP address\n" "IP address of next-hop\n") { - return bgp_route_match_delete(vty, "ip next-hop address", NULL, - RMAP_EVENT_MATCH_DELETED); + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:ipv4-nexthop']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_ipv6_nexthop_peer, - set_ipv6_nexthop_peer_cmd, - "set ipv6 next-hop peer-address", - SET_STR - IPV6_STR - "Next hop address\n" - "Use peer address (for BGP only)\n") +DEFUN_YANG (set_ipv6_nexthop_peer, + set_ipv6_nexthop_peer_cmd, + "set ipv6 next-hop peer-address", + SET_STR + IPV6_STR + "Next hop address\n" + "Use peer address (for BGP only)\n") { - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 next-hop peer-address", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-peer-address']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:preference", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_ipv6_nexthop_peer, - no_set_ipv6_nexthop_peer_cmd, - "no set ipv6 next-hop peer-address", - NO_STR - SET_STR - IPV6_STR - "IPv6 next-hop address\n" - "Use peer address (for BGP only)\n") +DEFUN_YANG (no_set_ipv6_nexthop_peer, + no_set_ipv6_nexthop_peer_cmd, + "no set ipv6 next-hop peer-address", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "Use peer address (for BGP only)\n") { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 next-hop peer-address", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-peer-address']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_ipv6_nexthop_prefer_global, - set_ipv6_nexthop_prefer_global_cmd, - "set ipv6 next-hop prefer-global", - SET_STR - IPV6_STR - "IPv6 next-hop address\n" - "Prefer global over link-local if both exist\n") +DEFUN_YANG (set_ipv6_nexthop_prefer_global, + set_ipv6_nexthop_prefer_global_cmd, + "set ipv6 next-hop prefer-global", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "Prefer global over link-local if both exist\n") { - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 next-hop prefer-global", NULL); - ; + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-prefer-global']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:preference", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_ipv6_nexthop_prefer_global, - no_set_ipv6_nexthop_prefer_global_cmd, - "no set ipv6 next-hop prefer-global", - NO_STR - SET_STR - IPV6_STR - "IPv6 next-hop address\n" - "Prefer global over link-local if both exist\n") +DEFUN_YANG (no_set_ipv6_nexthop_prefer_global, + no_set_ipv6_nexthop_prefer_global_cmd, + "no set ipv6 next-hop prefer-global", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "Prefer global over link-local if both exist\n") { - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 next-hop prefer-global", NULL); + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-prefer-global']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (set_ipv6_nexthop_global, - set_ipv6_nexthop_global_cmd, - "set ipv6 next-hop global X:X::X:X", - SET_STR - IPV6_STR - "IPv6 next-hop address\n" - "IPv6 global address\n" - "IPv6 address of next hop\n") +DEFUN_YANG (set_ipv6_nexthop_global, + set_ipv6_nexthop_global_cmd, + "set ipv6 next-hop global X:X::X:X", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 global address\n" + "IPv6 address of next hop\n") { int idx_ipv6 = 4; - struct in6_addr addr; - int ret; + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-nexthop-global']"; + char xpath_value[XPATH_MAXLEN]; - ret = inet_pton(AF_INET6, argv[idx_ipv6]->arg, &addr); - if (!ret) { - vty_out(vty, "%% Malformed nexthop address\n"); - return CMD_WARNING_CONFIG_FAILED; - } - if (IN6_IS_ADDR_UNSPECIFIED(&addr) || IN6_IS_ADDR_LOOPBACK(&addr) - || IN6_IS_ADDR_MULTICAST(&addr) || IN6_IS_ADDR_LINKLOCAL(&addr)) { - vty_out(vty, "%% Invalid global nexthop address\n"); - return CMD_WARNING_CONFIG_FAILED; - } + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:ipv6-address", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_ipv6]->arg); - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 next-hop global", argv[idx_ipv6]->arg); + return nb_cli_apply_changes(vty, NULL); } - -DEFUN (no_set_ipv6_nexthop_global, - no_set_ipv6_nexthop_global_cmd, - "no set ipv6 next-hop global X:X::X:X", - NO_STR - SET_STR - IPV6_STR - "IPv6 next-hop address\n" - "IPv6 global address\n" - "IPv6 address of next hop\n") +DEFUN_YANG (no_set_ipv6_nexthop_global, + no_set_ipv6_nexthop_global_cmd, + "no set ipv6 next-hop global X:X::X:X", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "IPv6 global address\n" + "IPv6 address of next hop\n") { - int idx_ipv6 = 5; - if (argc <= idx_ipv6) - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 next-hop global", NULL); - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 next-hop global", argv[idx_ipv6]->arg); + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-nexthop-global']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } #ifdef KEEP_OLD_VPN_COMMANDS -DEFUN (set_vpn_nexthop, - set_vpn_nexthop_cmd, - "set <vpnv4 next-hop A.B.C.D|vpnv6 next-hop X:X::X:X>", - SET_STR - "VPNv4 information\n" - "VPN next-hop address\n" - "IP address of next hop\n" - "VPNv6 information\n" - "VPN next-hop address\n" - "IPv6 address of next hop\n") +DEFUN_YANG (set_vpn_nexthop, + set_vpn_nexthop_cmd, + "set <vpnv4 next-hop A.B.C.D|vpnv6 next-hop X:X::X:X>", + SET_STR + "VPNv4 information\n" + "VPN next-hop address\n" + "IP address of next hop\n" + "VPNv6 information\n" + "VPN next-hop address\n" + "IPv6 address of next hop\n") { int idx_ip = 3; afi_t afi; int idx = 0; + char xpath_value[XPATH_MAXLEN]; if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { - if (afi == AFI_IP) - return generic_set_add( - vty, VTY_GET_CONTEXT(route_map_index), - "ipv4 vpn next-hop", argv[idx_ip]->arg); - else - return generic_set_add( - vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 vpn next-hop", argv[idx_ip]->arg); + if (afi == AFI_IP) { + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv4-vpn-address']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:ipv4-address", + xpath); + } else { + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-vpn-address']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:ipv6-address", + xpath); + } + + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_ip]->arg); + + return nb_cli_apply_changes(vty, NULL); } + return CMD_SUCCESS; } -DEFUN (no_set_vpn_nexthop, - no_set_vpn_nexthop_cmd, - "no set <vpnv4 next-hop A.B.C.D|vpnv6 next-hop X:X::X:X>", - NO_STR - SET_STR - "VPNv4 information\n" - "VPN next-hop address\n" - "IP address of next hop\n" - "VPNv6 information\n" - "VPN next-hop address\n" - "IPv6 address of next hop\n") +DEFUN_YANG (no_set_vpn_nexthop, + no_set_vpn_nexthop_cmd, + "no set <vpnv4 next-hop A.B.C.D|vpnv6 next-hop X:X::X:X>", + NO_STR + SET_STR + "VPNv4 information\n" + "VPN next-hop address\n" + "IP address of next hop\n" + "VPNv6 information\n" + "VPN next-hop address\n" + "IPv6 address of next hop\n") { - int idx_ip = 4; - char *arg; afi_t afi; int idx = 0; - if (argc <= idx_ip) - arg = NULL; - else - arg = argv[idx_ip]->arg; if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { - if (afi == AFI_IP) - return generic_set_delete( - vty, VTY_GET_CONTEXT(route_map_index), - "ipv4 vpn next-hop", arg); - else - return generic_set_delete( - vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 vpn next-hop", argv[idx_ip]->arg); + if (afi == AFI_IP) { + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv4-vpn-address']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } else { + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-vpn-address']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes(vty, NULL); } return CMD_SUCCESS; } #endif /* KEEP_OLD_VPN_COMMANDS */ -DEFUN (set_ipx_vpn_nexthop, - set_ipx_vpn_nexthop_cmd, - "set <ipv4|ipv6> vpn next-hop <A.B.C.D|X:X::X:X>", - SET_STR - "IPv4 information\n" - "IPv6 information\n" - "VPN information\n" - "VPN next-hop address\n" - "IP address of next hop\n" - "IPv6 address of next hop\n") +DEFUN_YANG (set_ipx_vpn_nexthop, + set_ipx_vpn_nexthop_cmd, + "set <ipv4|ipv6> vpn next-hop <A.B.C.D|X:X::X:X>", + SET_STR + "IPv4 information\n" + "IPv6 information\n" + "VPN information\n" + "VPN next-hop address\n" + "IP address of next hop\n" + "IPv6 address of next hop\n") { int idx_ip = 4; afi_t afi; int idx = 0; + char xpath_value[XPATH_MAXLEN]; if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { - if (afi == AFI_IP) - return generic_set_add( - vty, VTY_GET_CONTEXT(route_map_index), - "ipv4 vpn next-hop", argv[idx_ip]->arg); - else - return generic_set_add( - vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 vpn next-hop", argv[idx_ip]->arg); + if (afi == AFI_IP) { + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv4-vpn-address']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:ipv4-address", + xpath); + } else { + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-vpn-address']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:ipv6-address", + xpath); + } + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_ip]->arg); + return nb_cli_apply_changes(vty, NULL); } return CMD_SUCCESS; } -DEFUN (no_set_ipx_vpn_nexthop, - no_set_ipx_vpn_nexthop_cmd, - "no set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]", - NO_STR - SET_STR - "IPv4 information\n" - "IPv6 information\n" - "VPN information\n" - "VPN next-hop address\n" - "IP address of next hop\n" - "IPv6 address of next hop\n") -{ - int idx_ip = 5; - char *arg; +DEFUN_YANG (no_set_ipx_vpn_nexthop, + no_set_ipx_vpn_nexthop_cmd, + "no set <ipv4|ipv6> vpn next-hop [<A.B.C.D|X:X::X:X>]", + NO_STR + SET_STR + "IPv4 information\n" + "IPv6 information\n" + "VPN information\n" + "VPN next-hop address\n" + "IP address of next hop\n" + "IPv6 address of next hop\n") +{ afi_t afi; int idx = 0; - if (argc <= idx_ip) - arg = NULL; - else - arg = argv[idx_ip]->arg; if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { - if (afi == AFI_IP) - return generic_set_delete( - vty, VTY_GET_CONTEXT(route_map_index), - "ipv4 vpn next-hop", arg); - else - return generic_set_delete( - vty, VTY_GET_CONTEXT(route_map_index), - "ipv6 vpn next-hop", arg); + if (afi == AFI_IP) { + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv4-vpn-address']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } else { + const char *xpath = + "./set-action[action='frr-bgp-route-map:ipv6-vpn-address']"; + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } + return nb_cli_apply_changes(vty, NULL); } return CMD_SUCCESS; } -DEFUN (set_originator_id, - set_originator_id_cmd, - "set originator-id A.B.C.D", - SET_STR - "BGP originator ID attribute\n" - "IP address of originator\n") +DEFUN_YANG (set_originator_id, + set_originator_id_cmd, + "set originator-id A.B.C.D", + SET_STR + "BGP originator ID attribute\n" + "IP address of originator\n") { int idx_ipv4 = 2; - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "originator-id", argv[idx_ipv4]->arg); -} + const char *xpath = + "./set-action[action='frr-bgp-route-map:originator-id']"; + char xpath_value[XPATH_MAXLEN]; + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:originator-id", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_ipv4]->arg); -DEFUN (no_set_originator_id, - no_set_originator_id_cmd, - "no set originator-id [A.B.C.D]", - NO_STR - SET_STR - "BGP originator ID attribute\n" - "IP address of originator\n") + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_set_originator_id, + no_set_originator_id_cmd, + "no set originator-id [A.B.C.D]", + NO_STR + SET_STR + "BGP originator ID attribute\n" + "IP address of originator\n") { - int idx = 0; - char *arg = - argv_find(argv, argc, "A.B.C.D", &idx) ? argv[idx]->arg : NULL; + const char *xpath = + "./set-action[action='frr-bgp-route-map:originator-id']"; - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "originator-id", arg); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } - /* Initialization of route map. */ void bgp_route_map_init(void) { diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c new file mode 100644 index 0000000000..fc59122184 --- /dev/null +++ b/bgpd/bgp_routemap_nb.c @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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 "lib/command.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/routemap.h" +#include "bgpd/bgpd.h" +#include "bgpd/bgp_routemap_nb.h" + +/* clang-format off */ +const struct frr_yang_module_info frr_bgp_route_map_info = { + .name = "frr-bgp-route-map", + .nodes = { + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:local-preference", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_local_preference_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_local_preference_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:script", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_script_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_script_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:origin", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_origin_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_origin_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:rpki", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_rpki_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_rpki_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:probability", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_probability_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_probability_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:source-vrf", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-ipv4-address", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv4_address_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv4_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-interface", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_peer_interface_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_peer_interface_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-ipv6-address", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-local", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_peer_local_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_peer_local_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:list-name", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_list_name_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_list_name_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:evpn-default-route", + .cbs = { + .create = lib_route_map_entry_match_condition_rmap_match_condition_evpn_default_route_create, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_evpn_default_route_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:evpn-vni", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_evpn_vni_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_evpn_vni_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:evpn-route-type", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:route-distinguisher", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list", + .cbs = { + .apply_finish = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:ipv4-address", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:ipv6-address", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:distance", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_distance_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_distance_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-rt", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-soo", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_soo_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_soo_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:ipv4-address", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_ipv4_address_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_ipv4_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:ipv4-nexthop", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_ipv4_nexthop_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_ipv4_nexthop_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:ipv6-address", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_ipv6_address_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_ipv6_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:preference", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_preference_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_preference_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:label-index", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_label_index_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_label_index_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:local-pref", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_local_pref_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_local_pref_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:weight", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_weight_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_weight_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:origin", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_origin_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_origin_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:originator-id", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_originator_id_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_originator_id_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:table", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_table_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_table_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:atomic-aggregate", + .cbs = { + .create = lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_create, + .destroy = lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:prepend-as-path", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:last-as", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_last_as_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_last_as_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:exclude-as-path", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_exclude_as_path_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_exclude_as_path_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:community-none", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_community_none_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_community_none_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:community-string", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_community_string_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_community_string_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:large-community-none", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_large_community_none_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_large_community_none_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:large-community-string", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_large_community_string_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator", + .cbs = { + .apply_finish = lib_route_map_entry_set_action_rmap_set_action_aggregator_finish, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:comm-list-name", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb", + .cbs = { + .apply_finish = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h new file mode 100644 index 0000000000..a15f521513 --- /dev/null +++ b/bgpd/bgp_routemap_nb.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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_BGP_ROUTEMAP_NB_H_ +#define _FRR_BGP_ROUTEMAP_NB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct frr_yang_module_info frr_bgp_route_map_info; + +/* prototypes */ +int lib_route_map_entry_match_condition_rmap_match_condition_local_preference_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_local_preference_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_script_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_script_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_origin_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_origin_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_rpki_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_rpki_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_probability_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_probability_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv4_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv4_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_peer_interface_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_peer_interface_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_peer_local_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_peer_local_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_extended_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_extended_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_list_name_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_list_name_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_evpn_default_route_create(struct nb_cb_create_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_evpn_default_route_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_evpn_vni_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_evpn_vni_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy(struct nb_cb_destroy_args *args); +void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(struct nb_cb_apply_finish_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_distance_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_distance_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_soo_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_soo_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv4_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv4_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv4_nexthop_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv4_nexthop_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_preference_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_preference_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_label_index_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_label_index_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_local_pref_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_local_pref_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_weight_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_weight_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_origin_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_origin_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_originator_id_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_originator_id_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_table_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_table_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_create(struct nb_cb_create_args *args); +int lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_last_as_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_last_as_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_exclude_as_path_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_exclude_as_path_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_community_none_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_community_none_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_community_string_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_community_string_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_large_community_none_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_large_community_none_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_large_community_string_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy(struct nb_cb_destroy_args *args); +void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(struct nb_cb_apply_finish_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy(struct nb_cb_destroy_args *args); +void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(struct nb_cb_apply_finish_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c new file mode 100644 index 0000000000..ec6284273e --- /dev/null +++ b/bgpd/bgp_routemap_nb_config.c @@ -0,0 +1,2637 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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 "lib/command.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/routemap.h" +#include "bgpd/bgpd.h" +#include "bgpd/bgp_routemap_nb.h" + +/* Add bgp route map rule. */ +static int bgp_route_match_add(struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type, + char *errmsg, size_t errmsg_len) +{ + int retval = CMD_SUCCESS; + enum rmap_compile_rets ret; + + ret = route_map_add_match(index, command, arg, type); + switch (ret) { + case RMAP_RULE_MISSING: + snprintf(errmsg, errmsg_len, "%% BGP Can't find rule."); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + snprintf(errmsg, errmsg_len, "%% BGP Argument is malformed."); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + /* + * Intentionally doing nothing here. + */ + break; + } + + return retval; +} + +/* Delete bgp route map rule. */ +static int bgp_route_match_delete(struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type, + char *errmsg, size_t errmsg_len) +{ + enum rmap_compile_rets ret; + int retval = CMD_SUCCESS; + char *dep_name = NULL; + const char *tmpstr; + char *rmap_name = NULL; + + if (type != RMAP_EVENT_MATCH_DELETED) { + /* ignore the mundane, the types without any dependency */ + if (arg == NULL) { + if ((tmpstr = route_map_get_match_arg(index, command)) + != NULL) + dep_name = + XSTRDUP(MTYPE_ROUTE_MAP_RULE, tmpstr); + } else { + dep_name = XSTRDUP(MTYPE_ROUTE_MAP_RULE, arg); + } + rmap_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, index->map->name); + } + + ret = route_map_delete_match(index, command, dep_name, type); + switch (ret) { + case RMAP_RULE_MISSING: + snprintf(errmsg, errmsg_len, "%% BGP Can't find rule."); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_ERROR: + snprintf(errmsg, errmsg_len, + "%% BGP Argument is malformed."); + retval = CMD_WARNING_CONFIG_FAILED; + break; + case RMAP_COMPILE_SUCCESS: + /* + * Nothing to do here + */ + break; + } + + XFREE(MTYPE_ROUTE_MAP_RULE, dep_name); + XFREE(MTYPE_ROUTE_MAP_NAME, rmap_name); + + return retval; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:local-preference + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_local_preference_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *local_pref; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + local_pref = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "local-preference"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "local-preference", + local_pref, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_local_preference_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:script + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_script_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *script; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + script = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "script"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "script", + script, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_script_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:origin + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_origin_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *origin; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + origin = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "origin"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "origin", origin, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_origin_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:rpki + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_rpki_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *rpki; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + rpki = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "rpki"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "rpki", rpki, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_rpki_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:probability + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_probability_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *probability; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + probability = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "probability"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "probability", + probability, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_probability_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:source-vrf + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *vrf; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + vrf = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "source-vrf"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "source-vrf", vrf, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-ipv4-address + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv4_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "peer", peer, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv4_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-interface + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_peer_interface_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "peer", peer, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_peer_interface_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-ipv6-address + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "peer", peer, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-local + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_peer_local_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + bool value; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + value = yang_dnode_get_bool(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + if (value) { + ret = bgp_route_match_add(rhc->rhc_rmi, "peer", + "local", + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_peer_local_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:list-name + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_list_name_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *list_name; + enum rmap_compile_rets ret = RMAP_COMPILE_SUCCESS; + const char *condition; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + list_name = yang_dnode_get_string(args->dnode, NULL); + condition = yang_dnode_get_string(args->dnode, + "../../frr-route-map:condition"); + + if (IS_MATCH_AS_LIST(condition)) { + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "as-path"; + rhc->rhc_event = RMAP_EVENT_ASLIST_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "as-path", + list_name, RMAP_EVENT_ASLIST_ADDED, + args->errmsg, args->errmsg_len); + } else if (IS_MATCH_MAC_LIST(condition)) { + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "mac address"; + rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, + "mac address", + list_name, + RMAP_EVENT_FILTER_ADDED, + args->errmsg, args->errmsg_len); + } else if (IS_MATCH_ROUTE_SRC(condition)) { + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "ip route-source"; + rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, + "ip route-source", + list_name, RMAP_EVENT_FILTER_ADDED, + args->errmsg, args->errmsg_len); + } else if (IS_MATCH_ROUTE_SRC_PL(condition)) { + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "ip route-source prefix-list"; + rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, + "ip route-source prefix-list", + list_name, RMAP_EVENT_PLIST_ADDED, + args->errmsg, args->errmsg_len); + } + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:evpn-default-route + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_evpn_default_route_create( + struct nb_cb_create_args *args) +{ + struct routemap_hook_context *rhc; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "evpn default-route"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "evpn default-route", + NULL, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_evpn_default_route_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:evpn-vni + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_evpn_vni_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *vni; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + vni = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "evpn vni"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "evpn vni", vni, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_evpn_vni_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:evpn-route-type + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "evpn route-type"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "evpn route-type", + type, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:route-distinguisher + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *rd; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + rd = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "evpn rd"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "evpn rd", rd, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath = /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list + */ +void +lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( + struct nb_cb_apply_finish_args *args) +{ + struct routemap_hook_context *rhc; + const char *value; + bool exact_match = false; + char *argstr; + const char *condition; + route_map_event_t event; + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + value = yang_dnode_get_string(args->dnode, "./comm-list-name"); + + if (yang_dnode_exists(args->dnode, "./comm-list-name-exact-match")) + exact_match = yang_dnode_get_bool( + args->dnode, "./comm-list-name-exact-match"); + + if (exact_match) { + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, + strlen(value) + strlen("exact-match") + 2); + + snprintf(argstr, (strlen(value) + strlen("exact-match") + 2), + "%s exact-match", value); + } else + argstr = (char *)value; + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + + condition = yang_dnode_get_string(args->dnode, + "../../frr-route-map:condition"); + if (IS_MATCH_COMMUNITY(condition)) { + rhc->rhc_rule = "community"; + event = RMAP_EVENT_CLIST_ADDED; + rhc->rhc_event = RMAP_EVENT_CLIST_DELETED; + } else if (IS_MATCH_LCOMMUNITY(condition)) { + rhc->rhc_rule = "large-community"; + event = RMAP_EVENT_LLIST_ADDED; + rhc->rhc_event = RMAP_EVENT_LLIST_DELETED; + } else { + rhc->rhc_rule = "extcommunity"; + event = RMAP_EVENT_ECLIST_ADDED; + rhc->rhc_event = RMAP_EVENT_ECLIST_DELETED; + } + + bgp_route_match_add(rhc->rhc_rmi, rhc->rhc_rule, argstr, event, + args->errmsg, args->errmsg_len); + + if (argstr != value) + XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; + +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:ipv4-address + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "ip next-hop address"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, rhc->rhc_rule, + peer, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:ipv6-address + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "ipv6 next-hop"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, rhc->rhc_rule, + peer, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:distance + */ +int lib_route_map_entry_set_action_rmap_set_action_distance_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "distance"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "distance", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_distance_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-rt + */ +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "extcommunity rt"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "extcommunity rt", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-soo + */ +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_soo_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "extcommunity soo"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "extcommunity soo", + type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_soo_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:ipv4-address + */ +int lib_route_map_entry_set_action_rmap_set_action_ipv4_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *addr; + int rv = CMD_SUCCESS; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + addr = yang_dnode_get_string(args->dnode, NULL); + + rhc->rhc_shook = generic_set_delete; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + rhc->rhc_rule = "ipv4 vpn next-hop"; + + rv = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, addr, + args->errmsg, args->errmsg_len); + + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_ipv4_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:ipv4-nexthop + */ +int lib_route_map_entry_set_action_rmap_set_action_ipv4_nexthop_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "ip next-hop"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, type, + args->errmsg, args->errmsg_len); + + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_ipv4_nexthop_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:ipv6-address + */ +int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *addr; + int rv = CMD_SUCCESS; + const char *action = NULL; + struct in6_addr i6a; + + action = yang_dnode_get_string(args->dnode, + "../../frr-route-map:action"); + switch (args->event) { + case NB_EV_VALIDATE: + if (action && IS_SET_IPV6_NH_GLOBAL(action)) { + yang_dnode_get_ipv6(&i6a, args->dnode, NULL); + if (IN6_IS_ADDR_UNSPECIFIED(&i6a) + || IN6_IS_ADDR_LOOPBACK(&i6a) + || IN6_IS_ADDR_MULTICAST(&i6a) + || IN6_IS_ADDR_LINKLOCAL(&i6a)) + return NB_ERR_VALIDATION; + } + /* FALLTHROUGH */ + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + break; + } + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + addr = yang_dnode_get_string(args->dnode, NULL); + + rhc->rhc_shook = generic_set_delete; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + if (IS_SET_IPV6_NH_GLOBAL(action)) + /* Set destroy information. */ + rhc->rhc_rule = "ipv6 next-hop global"; + else + rhc->rhc_rule = "ipv6 vpn next-hop"; + + rv = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, addr, + args->errmsg, args->errmsg_len); + + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:preference + */ +int lib_route_map_entry_set_action_rmap_set_action_preference_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + int rv = CMD_SUCCESS; + const char *action = NULL; + bool value; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + value = yang_dnode_get_bool(args->dnode, NULL); + + rhc->rhc_shook = generic_set_delete; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + action = yang_dnode_get_string(args->dnode, + "../../frr-route-map:action"); + + if (value) { + if (IS_SET_IPV6_PEER_ADDR(action)) + /* Set destroy information. */ + rhc->rhc_rule = "ipv6 next-hop peer-address"; + else + rhc->rhc_rule = "ipv6 next-hop prefer-global"; + + rv = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, + NULL, + args->errmsg, args->errmsg_len); + } + + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_preference_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:label-index + */ +int lib_route_map_entry_set_action_rmap_set_action_label_index_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "label-index"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "label-index", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_label_index_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:local-pref + */ +int lib_route_map_entry_set_action_rmap_set_action_local_pref_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "local-preference"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "local-preference", + type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_local_pref_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:weight + */ +int lib_route_map_entry_set_action_rmap_set_action_weight_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "weight"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "weight", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_weight_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:origin + */ +int lib_route_map_entry_set_action_rmap_set_action_origin_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "origin"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "origin", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_origin_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:originator-id + */ +int lib_route_map_entry_set_action_rmap_set_action_originator_id_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "originator-id"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "originator-id", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_originator_id_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:table + */ +int lib_route_map_entry_set_action_rmap_set_action_table_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "table"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "table", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_table_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:atomic-aggregate + */ +int +lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_create( + struct nb_cb_create_args *args) +{ + struct routemap_hook_context *rhc; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "atomic-aggregate"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, NULL, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:prepend-as-path + */ +int +lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "as-path prepend"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "as-path prepend", + type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:last-as + */ +int lib_route_map_entry_set_action_rmap_set_action_last_as_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *value; + char *argstr; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + value = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "as-path prepend"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, + strlen(value) + strlen("last-as") + 2); + + snprintf(argstr, (strlen(value) + strlen("last-as") + 2), + "last-as %s", value); + + rv = generic_set_add(rhc->rhc_rmi, "as-path prepend", + argstr, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); + return NB_ERR_INCONSISTENCY; + } + + XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_last_as_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:exclude-as-path + */ +int +lib_route_map_entry_set_action_rmap_set_action_exclude_as_path_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "as-path exclude"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "as-path exclude", + type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_exclude_as_path_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:community-none + */ +int lib_route_map_entry_set_action_rmap_set_action_community_none_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + bool none = false; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + none = yang_dnode_get_bool(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "community"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + if (none) { + rv = generic_set_add(rhc->rhc_rmi, "community", + "none", + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + return NB_OK; + } + + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_community_none_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:community-string + */ +int +lib_route_map_entry_set_action_rmap_set_action_community_string_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "community"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "community", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_community_string_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:large-community-none + */ +int +lib_route_map_entry_set_action_rmap_set_action_large_community_none_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + bool none = false; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + none = yang_dnode_get_bool(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "large-community"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + if (none) { + rv = generic_set_add(rhc->rhc_rmi, + "large-community", + "none", + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + return NB_OK; + } + + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_large_community_none_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:large-community-string + */ +int +lib_route_map_entry_set_action_rmap_set_action_large_community_string_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "large-community"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "large-community", + type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * xpath = + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator + */ +void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish( + struct nb_cb_apply_finish_args *args) +{ + struct routemap_hook_context *rhc; + const char *asn; + const char *addr; + char *argstr; + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + asn = yang_dnode_get_string(args->dnode, "./aggregator-asn"); + addr = yang_dnode_get_string(args->dnode, "./aggregator-address"); + + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, + strlen(asn) + strlen(addr) + 2); + + snprintf(argstr, (strlen(asn) + strlen(addr) + 2), "%s %s", asn, addr); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "aggregator as"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, argstr, + args->errmsg, args->errmsg_len); + XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr); +} +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn + */ +int +lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address + */ +int +lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:comm-list-name + */ +int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *value; + const char *action; + int rv = CMD_SUCCESS; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + value = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + + action = yang_dnode_get_string(args->dnode, + "../../frr-route-map:action"); + if (IS_SET_COMM_LIST_DEL(action)) + rhc->rhc_rule = "comm-list"; + else + rhc->rhc_rule = "large-comm-list"; + + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, value, + args->errmsg, args->errmsg_len); + + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +enum e_community_lb_type { + EXPLICIT_BANDWIDTH, + CUMULATIVE_BANDWIDTH, + COMPUTED_BANDWIDTH +}; + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb + */ +void +lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( + struct nb_cb_apply_finish_args *args) +{ + struct routemap_hook_context *rhc; + int lb_type; + char str[VTY_BUFSIZ]; + uint16_t bandwidth; + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + lb_type = yang_dnode_get_enum(args->dnode, "./lb-type"); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "extcommunity bandwidth"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + switch (lb_type) { + case EXPLICIT_BANDWIDTH: + bandwidth = yang_dnode_get_uint16(args->dnode, "./bandwidth"); + snprintf(str, sizeof(str), "%d", bandwidth); + break; + case CUMULATIVE_BANDWIDTH: + snprintf(str, sizeof(str), "%s", "cumulative"); + break; + case COMPUTED_BANDWIDTH: + snprintf(str, sizeof(str), "%s", "num-multipaths"); + } + + if (yang_dnode_get_bool(args->dnode, "./two-octet-as-specific")) + strlcat(str, " non-transitive", sizeof(str)); + + generic_set_add(rhc->rhc_rmi, + "extcommunity bandwidth", str, + args->errmsg, args->errmsg_len); +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type + */ +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify( + struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy( + struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_destroy(args); +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth + */ +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_modify( + struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy( + struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_destroy(args); +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific + */ +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify( + struct nb_cb_modify_args *args) +{ + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy( + struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_destroy(args); +} diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 42951efb01..bb85ad393d 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -47,6 +47,9 @@ #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_route.h" +#include "bgpd/bgp_rpki.h" +#include "northbound_cli.h" + #include "lib/network.h" #include "lib/thread.h" #ifndef VTYSH_EXTRACT_PL @@ -60,12 +63,8 @@ #include "bgpd/bgp_rpki_clippy.c" #endif -DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server") -DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group") - -#define RPKI_VALID 1 -#define RPKI_NOTFOUND 2 -#define RPKI_INVALID 3 +DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server"); +DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group"); #define POLLING_PERIOD_DEFAULT 3600 #define EXPIRE_INTERVAL_DEFAULT 7200 @@ -1166,7 +1165,7 @@ DEFUN (show_rpki_prefix_table, return CMD_SUCCESS; } -DEFPY(show_rpki_as_number, show_rpki_as_number_cmd, +DEFPY (show_rpki_as_number, show_rpki_as_number_cmd, "show rpki as-number (1-4294967295)$by_asn", SHOW_STR RPKI_OUTPUT_STRING "Lookup by ASN in prefix table\n" @@ -1359,7 +1358,7 @@ DEFUN (no_debug_rpki, return CMD_SUCCESS; } -DEFUN (match_rpki, +DEFUN_YANG (match_rpki, match_rpki_cmd, "match rpki <valid|invalid|notfound>", MATCH_STR @@ -1368,27 +1367,19 @@ DEFUN (match_rpki, "Invalid prefix\n" "Prefix not found\n") { - VTY_DECLVAR_CONTEXT(route_map_index, index); - enum rmap_compile_rets ret; - - ret = route_map_add_match(index, "rpki", argv[2]->arg, - RMAP_EVENT_MATCH_ADDED); - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% BGP Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% BGP Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_SUCCESS: - return CMD_SUCCESS; - break; - } + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:rpki']"; + char xpath_value[XPATH_MAXLEN]; - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:rpki", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[2]->arg); + + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_match_rpki, +DEFUN_YANG (no_match_rpki, no_match_rpki_cmd, "no match rpki <valid|invalid|notfound>", NO_STR @@ -1398,26 +1389,11 @@ DEFUN (no_match_rpki, "Invalid prefix\n" "Prefix not found\n") { - VTY_DECLVAR_CONTEXT(route_map_index, index); - enum rmap_compile_rets ret; - - ret = route_map_delete_match(index, "rpki", argv[3]->arg, - RMAP_EVENT_MATCH_DELETED); - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "%% BGP Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_ERROR: - vty_out(vty, "%% BGP Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; - break; - case RMAP_COMPILE_SUCCESS: - return CMD_SUCCESS; - break; - } + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:rpki']"; - return CMD_SUCCESS; + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + return nb_cli_apply_changes(vty, NULL); } static void install_cli_commands(void) @@ -1471,4 +1447,5 @@ static void install_cli_commands(void) FRR_MODULE_SETUP(.name = "bgpd_rpki", .version = "0.3.6", .description = "Enable RPKI support for FRR.", - .init = bgp_rpki_module_init) + .init = bgp_rpki_module_init, +); diff --git a/eigrpd/eigrp_memory.h b/bgpd/bgp_rpki.h index 21ecba2aae..4dd4b4a2b2 100644 --- a/eigrpd/eigrp_memory.h +++ b/bgpd/bgp_rpki.h @@ -1,6 +1,8 @@ -/* eigrpd memory type declarations - * - * Copyright (C) 2017 Donald Sharp +/* + * bgp_rpki code + * Copyright (C) 2021 NVIDIA Corporation and Mellanox Technologies, LTD + * All Rights Reserved + * Donald Sharp * * This file is part of FRR. * @@ -18,26 +20,14 @@ * 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 __BGP_RPKI_H__ +#define __BGP_RPKI_H__ -#ifndef _FRR_EIGRP_MEMORY_H -#define _FRR_EIGRP_MEMORY_H - -#include "memory.h" - -DECLARE_MGROUP(EIGRPD) -DECLARE_MTYPE(EIGRP_TOP) -DECLARE_MTYPE(EIGRP_IF) -DECLARE_MTYPE(EIGRP_NEIGHBOR) -DECLARE_MTYPE(EIGRP_IF_PARAMS) -DECLARE_MTYPE(EIGRP_IF_INFO) -DECLARE_MTYPE(EIGRP_FIFO) -DECLARE_MTYPE(EIGRP_PACKET) -DECLARE_MTYPE(EIGRP_IPV4_INT_TLV) -DECLARE_MTYPE(EIGRP_SEQ_TLV) -DECLARE_MTYPE(EIGRP_AUTH_TLV) -DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV) -DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR) -DECLARE_MTYPE(EIGRP_ROUTE_DESCRIPTOR) -DECLARE_MTYPE(EIGRP_FSM_MSG) +enum rpki_states { + RPKI_NOT_BEING_USED, + RPKI_VALID, + RPKI_NOTFOUND, + RPKI_INVALID +}; -#endif /* _FRR_EIGRP_MEMORY_H */ +#endif diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 71868abc5f..3afdbea908 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -435,7 +435,7 @@ static struct peer *bgpPeerTable_lookup(struct variable *v, oid name[], if (peer == NULL) return NULL; - oid_copy_addr(name + namelen, addr, sizeof(struct in_addr)); + oid_copy_in_addr(name + namelen, addr); *length = sizeof(struct in_addr) + namelen; return peer; @@ -767,14 +767,12 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[], v->namelen + BGP_PATHATTR_ENTRY_OFFSET; offset = name + v->namelen; - oid_copy_addr(offset, &rn_p->u.prefix4, - IN_ADDR_SIZE); + oid_copy_in_addr(offset, &rn_p->u.prefix4); offset += IN_ADDR_SIZE; *offset = rn_p->prefixlen; offset++; - oid_copy_addr(offset, - &min->peer->su.sin.sin_addr, - IN_ADDR_SIZE); + oid_copy_in_addr(offset, + &min->peer->su.sin.sin_addr); addr->prefix = rn_p->u.prefix4; addr->prefixlen = rn_p->prefixlen; @@ -868,7 +866,7 @@ static int bgpTrapEstablished(struct peer *peer) if (ret == 0) return 0; - oid_copy_addr(index, &addr, IN_ADDR_SIZE); + oid_copy_in_addr(index, &addr); smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid, array_size(bgp_trap_oid), bgp_oid, @@ -887,7 +885,7 @@ static int bgpTrapBackwardTransition(struct peer *peer) if (ret == 0) return 0; - oid_copy_addr(index, &addr, IN_ADDR_SIZE); + oid_copy_in_addr(index, &addr); smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid, array_size(bgp_trap_oid), bgp_oid, @@ -914,4 +912,5 @@ static int bgp_snmp_module_init(void) FRR_MODULE_SETUP(.name = "bgpd_snmp", .version = FRR_VERSION, .description = "bgpd AgentX SNMP module", - .init = bgp_snmp_module_init) + .init = bgp_snmp_module_init, +); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 7e3aa2a48a..833bdec2ed 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -201,18 +201,17 @@ struct bgp_node *bgp_table_subtree_lookup(const struct bgp_table *table, } printfrr_ext_autoreg_p("BD", printfrr_bd) -static ssize_t printfrr_bd(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_bd(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct bgp_dest *dest = ptr; - const struct prefix *p; + const struct prefix *p = bgp_dest_get_prefix(dest); + char cbuf[PREFIX_STRLEN]; - if (dest) { - p = bgp_dest_get_prefix(dest); - prefix2str(p, buf, bsz); - } else { - strlcpy(buf, "NULL", bsz); - } + if (!dest) + return bputs(buf, "(null)"); - return 2; + /* need to get the real length even if buffer too small */ + prefix2str(p, cbuf, sizeof(cbuf)); + return bputs(buf, cbuf); } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4b012430d9..9ecf02aae0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -86,49 +86,49 @@ FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK, .match_version = "< 7.4", }, { .val_bool = true }, -) +); FRR_CFG_DEFAULT_BOOL(BGP_SHOW_HOSTNAME, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, -) +); FRR_CFG_DEFAULT_BOOL(BGP_SHOW_NEXTHOP_HOSTNAME, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, -) +); FRR_CFG_DEFAULT_BOOL(BGP_LOG_NEIGHBOR_CHANGES, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, -) +); FRR_CFG_DEFAULT_BOOL(BGP_DETERMINISTIC_MED, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, -) +); FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY, { .val_ulong = 10, .match_profile = "datacenter", }, { .val_ulong = 120 }, -) +); FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME, { .val_ulong = 9, .match_profile = "datacenter", }, { .val_ulong = 180 }, -) +); FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE, { .val_ulong = 3, .match_profile = "datacenter", }, { .val_ulong = 60 }, -) +); FRR_CFG_DEFAULT_BOOL(BGP_EBGP_REQUIRES_POLICY, { .val_bool = false, .match_profile = "datacenter", }, { .val_bool = false, .match_version = "< 7.4", }, { .val_bool = true }, -) +); FRR_CFG_DEFAULT_BOOL(BGP_SUPPRESS_DUPLICATES, { .val_bool = false, .match_version = "< 7.6", }, { .val_bool = true }, -) +); DEFINE_HOOK(bgp_inst_config_write, (struct bgp *bgp, struct vty *vty), - (bgp, vty)) -DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp)) + (bgp, vty)); +DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp)); #define GR_NO_OPER \ "The Graceful Restart No Operation was executed as cmd same as previous one." @@ -1324,16 +1324,19 @@ DEFUN_YANG_NOSH(router_bgp, as_t as; struct bgp *bgp; const char *name = NULL; - char as_str[12] = {'\0'}; enum bgp_instance_type inst_type; char base_xpath[XPATH_MAXLEN]; + const struct lyd_node *bgp_glb_dnode; // "router bgp" without an ASN if (argc == 2) { // Pending: Make VRF option available for ASN less config - bgp = bgp_get_default(); + snprintf(base_xpath, sizeof(base_xpath), FRR_BGP_GLOBAL_XPATH, + "frr-bgp:bgp", "bgp", VRF_DEFAULT_NAME); - if (bgp == NULL) { + bgp_glb_dnode = yang_dnode_get(vty->candidate_config->dnode, + base_xpath); + if (!bgp_glb_dnode) { vty_out(vty, "%% No BGP process is configured\n"); return CMD_WARNING_CONFIG_FAILED; } @@ -1343,31 +1346,19 @@ DEFUN_YANG_NOSH(router_bgp, return CMD_WARNING_CONFIG_FAILED; } - snprintf(base_xpath, sizeof(base_xpath), FRR_BGP_GLOBAL_XPATH, - "frr-bgp:bgp", "bgp", VRF_DEFAULT_NAME); - - nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); - snprintf(as_str, 12, "%d", bgp->as); - nb_cli_enqueue_change(vty, "./global/local-as", NB_OP_MODIFY, - as_str); - if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) { - nb_cli_enqueue_change(vty, - "./global/instance-type-view", - NB_OP_MODIFY, "true"); - } + as = yang_dnode_get_uint32(bgp_glb_dnode, "./global/local-as"); - nb_cli_pending_commit_check(vty); - ret = nb_cli_apply_changes(vty, base_xpath); - if (ret == CMD_SUCCESS) { - VTY_PUSH_XPATH(BGP_NODE, base_xpath); + VTY_PUSH_XPATH(BGP_NODE, base_xpath); - /* - * For backward compatibility with old commands we still - * need to use the qobj infrastructure. - */ + /* + * For backward compatibility with old commands we still + * need to use the qobj infrastructure. + */ + bgp = bgp_lookup(as, NULL); + if (bgp) VTY_PUSH_CONTEXT(BGP_NODE, bgp); - } - return ret; + + return CMD_SUCCESS; } // "router bgp X" @@ -1423,10 +1414,7 @@ DEFUN_YANG(no_router_bgp, "no router bgp [(1-4294967295)$instasn [<view|vrf> VIEWVRFNAME]]", NO_STR ROUTER_STR BGP_STR AS_STR BGP_INSTANCE_HELP_STR) { - int idx_asn = 3; int idx_vrf = 5; - as_t as = 0; - struct bgp *bgp; const char *name = NULL; char base_xpath[XPATH_MAXLEN]; const struct lyd_node *bgp_glb_dnode; @@ -1448,72 +1436,15 @@ DEFUN_YANG(no_router_bgp, vty_out(vty, "%% Please specify ASN and VRF\n"); return CMD_WARNING_CONFIG_FAILED; } - - /* tcli mode bgp would not be set until apply stage. */ - bgp = nb_running_get_entry(bgp_glb_dnode, NULL, false); - if (!bgp) - return CMD_SUCCESS; - - if (bgp->l3vni) { - vty_out(vty, "%% Please unconfigure l3vni %u", - bgp->l3vni); - return CMD_WARNING_CONFIG_FAILED; - } } else { - as = strtoul(argv[idx_asn]->arg, NULL, 10); - if (argc > 4) name = argv[idx_vrf]->arg; + else + name = VRF_DEFAULT_NAME; - /* Lookup bgp structure. */ - bgp = bgp_lookup(as, name); - if (!bgp) { - vty_out(vty, "%% Can't find BGP instance\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (bgp->l3vni) { - vty_out(vty, "%% Please unconfigure l3vni %u\n", - bgp->l3vni); - return CMD_WARNING_CONFIG_FAILED; - } - - /* Cannot delete default instance if vrf instances exist */ - if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { - struct listnode *node; - struct bgp *tmp_bgp; - - for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { - if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) - continue; - if (CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], - BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], - BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], - BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], - BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], - BGP_CONFIG_VRF_TO_VRF_EXPORT) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], - BGP_CONFIG_VRF_TO_VRF_EXPORT) || - (bgp == bgp_get_evpn() && - (CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], - BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST) || - CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], - BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))) || - (tmp_bgp->vnihash && hashcount(tmp_bgp->vnihash))) { - vty_out(vty, - "%% Cannot delete default BGP instance. Dependent VRF instances exist\n"); - return CMD_WARNING_CONFIG_FAILED; - } - } - } + snprintf(base_xpath, sizeof(base_xpath), FRR_BGP_GLOBAL_XPATH, + "frr-bgp:bgp", "bgp", name); } - snprintf(base_xpath, sizeof(base_xpath), FRR_BGP_GLOBAL_XPATH, - "frr-bgp:bgp", "bgp", - bgp->name ? bgp->name : VRF_DEFAULT_NAME); nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); @@ -3571,6 +3502,37 @@ DEFUN_YANG (no_bgp_bestpath_aspath_multipath_relax, return nb_cli_apply_changes(vty, NULL); } +/* "bgp bestpath peer-type multipath-relax" configuration. */ +DEFUN(bgp_bestpath_peer_type_multipath_relax, + bgp_bestpath_peer_type_multipath_relax_cmd, + "bgp bestpath peer-type multipath-relax", + BGP_STR + "Change the default bestpath selection\n" + "Peer type\n" + "Allow load sharing across routes learned from different peer types\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + SET_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX); + bgp_recalculate_all_bestpaths(bgp); + + return CMD_SUCCESS; +} + +DEFUN(no_bgp_bestpath_peer_type_multipath_relax, + no_bgp_bestpath_peer_type_multipath_relax_cmd, + "no bgp bestpath peer-type multipath-relax", + NO_STR BGP_STR + "Change the default bestpath selection\n" + "Peer type\n" + "Allow load sharing across routes learned from different peer types\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + UNSET_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX); + bgp_recalculate_all_bestpaths(bgp); + + return CMD_SUCCESS; +} + /* "bgp log-neighbor-changes" configuration. */ DEFUN_YANG(bgp_log_neighbor_changes, bgp_log_neighbor_changes_cmd, @@ -3727,6 +3689,29 @@ DEFPY (no_bgp_bestpath_bw, return CMD_SUCCESS; } +/* "no bgp default ipv6-unicast". */ +DEFUN(no_bgp_default_ipv6_unicast, no_bgp_default_ipv6_unicast_cmd, + "no bgp default ipv6-unicast", NO_STR + "BGP specific commands\n" + "Configure BGP defaults\n" + "Activate ipv6-unicast for a peer by default\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + UNSET_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6); + return CMD_SUCCESS; +} + +DEFUN(bgp_default_ipv6_unicast, bgp_default_ipv6_unicast_cmd, + "bgp default ipv6-unicast", + "BGP specific commands\n" + "Configure BGP defaults\n" + "Activate ipv6-unicast for a peer by default\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + SET_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6); + return CMD_SUCCESS; +} + /* "no bgp default ipv4-unicast". */ DEFUN (no_bgp_default_ipv4_unicast, no_bgp_default_ipv4_unicast_cmd, @@ -4005,7 +3990,7 @@ void cli_show_router_global_neighbor_config(struct vty *vty, DEFUN_YANG(bgp_listen_limit, bgp_listen_limit_cmd, - "bgp listen limit (1-5000)", + "bgp listen limit (1-65535)", "BGP specific commands\n" "BGP Dynamic Neighbors listen commands\n" "Maximum number of BGP Dynamic Neighbors that can be created\n" @@ -4022,7 +4007,7 @@ DEFUN_YANG(bgp_listen_limit, DEFUN_YANG(no_bgp_listen_limit, no_bgp_listen_limit_cmd, - "no bgp listen limit [(1-5000)]", + "no bgp listen limit [(1-65535)]", NO_STR "BGP specific commands\n" "BGP Dynamic Neighbors listen commands\n" @@ -4368,10 +4353,10 @@ DEFUN_YANG(neighbor_remote_as, return nb_cli_apply_changes(vty, base_xpath); } -int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, afi_t afi, - safi_t safi, bool v6only, - const char *peer_group_name, int as_type, - as_t as, char *errmsg, size_t errmsg_len) +int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, + bool v6only, const char *peer_group_name, + int as_type, as_t as, char *errmsg, + size_t errmsg_len) { struct peer *peer; struct peer_group *group; @@ -4388,16 +4373,10 @@ int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, afi_t afi, peer = peer_lookup_by_conf_if(bgp, conf_if); if (peer) { if (as_type != AS_UNSPECIFIED) - ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type, - afi, safi); + ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type); } else { - if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4) - && afi == AFI_IP && safi == SAFI_UNICAST) - peer = peer_create(NULL, conf_if, bgp, bgp->as, as, - as_type, 0, 0, NULL); - else - peer = peer_create(NULL, conf_if, bgp, bgp->as, as, - as_type, afi, safi, NULL); + peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type, + NULL); if (!peer) { snprintf(errmsg, errmsg_len, @@ -6139,10 +6118,28 @@ DEFUN_YANG (neighbor_send_community, "Send Community attribute to this neighbor\n") { int idx_peer = 1; + char *peer_str = argv[idx_peer]->arg; + char base_xpath[XPATH_MAXLEN]; + char af_xpath[XPATH_MAXLEN]; + char std_xpath[XPATH_MAXLEN]; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); - return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty), - bgp_node_safi(vty), - PEER_FLAG_SEND_COMMUNITY); + snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH, + yang_afi_safi_value2identity(afi, safi)); + + if (peer_and_group_lookup_nb(vty, peer_str, base_xpath, + sizeof(base_xpath), af_xpath) + < 0) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(std_xpath, sizeof(std_xpath), + "./%s/send-community/send-community", + bgp_afi_safi_get_container_str(afi, safi)); + + nb_cli_enqueue_change(vty, std_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, base_xpath); } ALIAS_HIDDEN(neighbor_send_community, neighbor_send_community_hidden_cmd, @@ -6159,10 +6156,28 @@ DEFUN_YANG (no_neighbor_send_community, "Send Community attribute to this neighbor\n") { int idx_peer = 2; + char *peer_str = argv[idx_peer]->arg; + char base_xpath[XPATH_MAXLEN]; + char af_xpath[XPATH_MAXLEN]; + char std_xpath[XPATH_MAXLEN]; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); - return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg, - bgp_node_afi(vty), bgp_node_safi(vty), - PEER_FLAG_SEND_COMMUNITY); + snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH, + yang_afi_safi_value2identity(afi, safi)); + + if (peer_and_group_lookup_nb(vty, peer_str, base_xpath, + sizeof(base_xpath), af_xpath) + < 0) + return CMD_WARNING_CONFIG_FAILED; + + snprintf(std_xpath, sizeof(std_xpath), + "./%s/send-community/send-community", + bgp_afi_safi_get_container_str(afi, safi)); + + nb_cli_enqueue_change(vty, std_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, base_xpath); } ALIAS_HIDDEN(no_neighbor_send_community, no_neighbor_send_community_hidden_cmd, @@ -10443,6 +10458,9 @@ static void bgp_show_bestpath_json(struct bgp *bgp, json_object *json) } else json_object_string_add(bestpath, "multiPathRelax", "false"); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) + json_object_boolean_true_add(bestpath, "peerTypeRelax"); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID)) json_object_string_add(bestpath, "compareRouterId", "true"); if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED) @@ -14358,7 +14376,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, "\n"); /* BFD information. */ - bgp_bfd_show_info(vty, p, use_json, json_neigh); + if (p->bfd_config) + bgp_bfd_show_info(vty, p, json_neigh); if (use_json) { if (p->conf_if) /* Configured interface name. */ @@ -16765,11 +16784,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, peer->rtt_expected, peer->rtt_keepalive_conf); /* bfd */ - if (peer->bfd_info) { - if (!peer_group_active(peer) || !g_peer->bfd_info) { - bgp_bfd_peer_config_write(vty, peer, addr); - } - } + if (peer->bfd_config) + bgp_bfd_peer_config_write(vty, peer, addr); /* password */ if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD)) @@ -16966,18 +16982,36 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, } } else { if (peer->afc[afi][safi]) { - if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { - if (CHECK_FLAG(bgp->flags, - BGP_FLAG_NO_DEFAULT_IPV4)) { + if ((afi == AFI_IP || afi == AFI_IP6) + && safi == SAFI_UNICAST) { + if (afi == AFI_IP + && CHECK_FLAG(bgp->flags, + BGP_FLAG_NO_DEFAULT_IPV4)) { + vty_out(vty, " neighbor %s activate\n", + addr); + } else if (afi == AFI_IP6 + && !CHECK_FLAG( + bgp->flags, + BGP_FLAG_DEFAULT_IPV6)) { vty_out(vty, " neighbor %s activate\n", addr); } - } else + } else { vty_out(vty, " neighbor %s activate\n", addr); + } } else { - if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) { - if (!CHECK_FLAG(bgp->flags, - BGP_FLAG_NO_DEFAULT_IPV4)) { + if ((afi == AFI_IP || afi == AFI_IP6) + && safi == SAFI_UNICAST) { + if (afi == AFI_IP + && !CHECK_FLAG(bgp->flags, + BGP_FLAG_NO_DEFAULT_IPV4)) { + vty_out(vty, + " no neighbor %s activate\n", + addr); + } else if (afi == AFI_IP6 + && CHECK_FLAG( + bgp->flags, + BGP_FLAG_DEFAULT_IPV6)) { vty_out(vty, " no neighbor %s activate\n", addr); @@ -17411,6 +17445,10 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4)) vty_out(vty, " no bgp default ipv4-unicast\n"); + /* BGP default ipv6-unicast. */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6)) + vty_out(vty, " bgp default ipv6-unicast\n"); + /* BGP default local-preference. */ if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF) vty_out(vty, " bgp default local-preference %u\n", @@ -17581,6 +17619,10 @@ int bgp_config_write(struct vty *vty) vty_out(vty, "\n"); } + if (CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) + vty_out(vty, + " bgp bestpath peer-type multipath-relax\n"); + /* Link bandwidth handling. */ if (bgp->lb_handling == BGP_LINK_BW_IGNORE_BW) vty_out(vty, " bgp bestpath bandwidth ignore\n"); @@ -18065,6 +18107,11 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_bestpath_aspath_multipath_relax_cmd); install_element(BGP_NODE, &no_bgp_bestpath_aspath_multipath_relax_cmd); + /* "bgp bestpath peer-type multipath-relax" commands */ + install_element(BGP_NODE, &bgp_bestpath_peer_type_multipath_relax_cmd); + install_element(BGP_NODE, + &no_bgp_bestpath_peer_type_multipath_relax_cmd); + /* "bgp log-neighbor-changes" commands */ install_element(BGP_NODE, &bgp_log_neighbor_changes_cmd); install_element(BGP_NODE, &no_bgp_log_neighbor_changes_cmd); @@ -18081,6 +18128,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &no_bgp_default_ipv4_unicast_cmd); install_element(BGP_NODE, &bgp_default_ipv4_unicast_cmd); + /* "no bgp default ipv6-unicast" commands. */ + install_element(BGP_NODE, &no_bgp_default_ipv6_unicast_cmd); + install_element(BGP_NODE, &bgp_default_ipv6_unicast_cmd); + /* "bgp network import-check" commands. */ install_element(BGP_NODE, &bgp_network_import_check_cmd); install_element(BGP_NODE, &bgp_network_import_check_exact_cmd); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 85619dd074..251bdc3fe3 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -205,9 +205,9 @@ extern int peer_local_interface_cfg(struct bgp *bgp, const char *ip_str, const char *str, char *errmsg, size_t errmsg_len); extern int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, - afi_t afi, safi_t safi, bool v6only, - const char *peer_group_name, int as_type, - as_t as, char *errmsg, size_t errmsg_len); + bool v6only, const char *peer_group_name, + int as_type, as_t as, char *errmsg, + size_t errmsg_len); extern int peer_flag_modify_nb(struct bgp *bgp, const char *ip_str, struct peer *peer, uint32_t flag, bool set, char *errmsg, size_t errmsg_len); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index c554332255..d1912db01f 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -69,7 +69,7 @@ struct zclient *zclient = NULL; /* hook to indicate vrf status change for SNMP */ DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp), - (bgp, ifp)) + (bgp, ifp)); /* Can we install into zebra? */ static inline bool bgp_install_info_to_zebra(struct bgp *bgp) @@ -283,20 +283,9 @@ static int bgp_ifp_down(struct interface *ifp) if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) { for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { -#if defined(HAVE_CUMULUS) - /* Take down directly connected EBGP peers as well as - * 1-hop BFD - * tracked (directly connected) IBGP peers. - */ - if ((peer->ttl != BGP_DEFAULT_TTL) - && (peer->gtsm_hops != BGP_GTSM_HOPS_CONNECTED) - && (!peer->bfd_info - || bgp_bfd_is_peer_multihop(peer))) -#else - /* Take down directly connected EBGP peers */ + /* Take down directly connected peers. */ if ((peer->ttl != BGP_DEFAULT_TTL) && (peer->gtsm_hops != BGP_GTSM_HOPS_CONNECTED)) -#endif continue; if (ifp == peer->nexthop.ifp) { @@ -1180,6 +1169,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, int nh_family; unsigned int valid_nh_count = 0; int has_valid_label = 0; + bool allow_recursion = false; uint8_t distance; struct peer *peer; struct bgp_path_info *mpinfo; @@ -1257,7 +1247,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) || CHECK_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + allow_recursion = true; if (info->attr->rmap_table_id) { SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); @@ -1383,6 +1373,15 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, if (!nh_updated) continue; + /* Allow recursion if it is a multipath group with both + * eBGP and iBGP paths. + */ + if (!allow_recursion + && CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX) + && (mpinfo->peer->sort == BGP_PEER_IBGP + || mpinfo->peer->sort == BGP_PEER_CONFED)) + allow_recursion = true; + if (mpinfo->extra && bgp_is_valid_label(&mpinfo->extra->label[0]) && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) { @@ -1411,6 +1410,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, memcpy(api.opaque.data, aspath->str, api.opaque.length); } + if (allow_recursion) + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + /* * When we create an aggregate route we must also * install a Null0 route in the RIB, so overwrite diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d51ce817d1..d37b9fa48c 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -93,10 +93,10 @@ DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)"); DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information"); -DEFINE_QOBJ_TYPE(bgp_master) -DEFINE_QOBJ_TYPE(bgp) -DEFINE_QOBJ_TYPE(peer) -DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)) +DEFINE_QOBJ_TYPE(bgp_master); +DEFINE_QOBJ_TYPE(bgp); +DEFINE_QOBJ_TYPE(peer); +DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)); /* BGP process wide configuration. */ static struct bgp_master bgp_master; @@ -1161,7 +1161,9 @@ static void peer_free(struct peer *peer) XFREE(MTYPE_PEER_CONF_IF, peer->conf_if); - bfd_info_free(&(peer->bfd_info)); + /* Remove BFD configuration. */ + if (peer->bfd_config) + bgp_peer_remove_bfd_config(peer); FOREACH_AFI_SAFI (afi, safi) bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE); @@ -1468,8 +1470,10 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) { paf = peer_src->peer_af_array[afidx]; - if (paf != NULL) - peer_af_create(peer_dst, paf->afi, paf->safi); + if (paf != NULL) { + if (!peer_af_find(peer_dst, paf->afi, paf->safi)) + peer_af_create(peer_dst, paf->afi, paf->safi); + } } /* update-source apply */ @@ -1683,12 +1687,13 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp) */ struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, afi_t afi, safi_t safi, - struct peer_group *group) + int as_type, struct peer_group *group) { int active; struct peer *peer; char buf[SU_ADDRSTRLEN]; + afi_t afi; + safi_t safi; peer = peer_new(bgp); if (conf_if) { @@ -1747,9 +1752,23 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - if (afi && safi) { - peer->afc[afi][safi] = 1; - peer_af_create(peer, afi, safi); + /* If address family is IPv4 and `bgp default ipv4-unicast` (default), + * then activate the neighbor for this AF. + * If address family is IPv6 and `bgp default ipv6-unicast` + * (non-default), then activate the neighbor for this AF. + */ + FOREACH_AFI_SAFI (afi, safi) { + if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) { + if ((afi == AFI_IP + && !CHECK_FLAG(bgp->flags, + BGP_FLAG_NO_DEFAULT_IPV4)) + || (afi == AFI_IP6 + && CHECK_FLAG(bgp->flags, + BGP_FLAG_DEFAULT_IPV6))) { + peer->afc[afi][safi] = 1; + peer_af_create(peer, afi, safi); + } + } } /* auto shutdown if configured */ @@ -1878,7 +1897,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified) /* If peer does not exist, create new one. If peer already exists, set AS number to the peer. */ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, - as_t *as, int as_type, afi_t afi, safi_t safi) + as_t *as, int as_type) { struct peer *peer; as_t local_as; @@ -1946,16 +1965,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, else local_as = bgp->as; - /* If this is IPv4 unicast configuration and "no bgp default - ipv4-unicast" is specified. */ - - if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4) - && afi == AFI_IP && safi == SAFI_UNICAST) - peer_create(su, conf_if, bgp, local_as, *as, as_type, 0, - 0, NULL); - else - peer_create(su, conf_if, bgp, local_as, *as, as_type, - afi, safi, NULL); + peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL); } return 0; @@ -2386,7 +2396,9 @@ int peer_delete(struct peer *peer) SET_FLAG(peer->flags, PEER_FLAG_DELETE); - bgp_bfd_deregister_peer(peer); + /* Remove BFD settings. */ + if (peer->bfd_config) + bgp_peer_remove_bfd_config(peer); /* Delete peer route flap dampening configuration. This needs to happen * before removing the peer from peer groups. @@ -2562,6 +2574,8 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name) group->conf = peer_new(bgp); if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4)) group->conf->afc[AFI_IP][SAFI_UNICAST] = 1; + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6)) + group->conf->afc[AFI_IP6][SAFI_UNICAST] = 1; XFREE(MTYPE_BGP_PEER_HOST, group->conf->host); group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name); group->conf->group = group; @@ -2668,7 +2682,11 @@ static void peer_group2peer_config_copy(struct peer_group *group, /* Update GR flags for the peer. */ bgp_peer_gr_flags_update(peer); - bgp_bfd_peer_group2peer_copy(conf, peer); + /* Apply BFD settings from group to peer if it exists. */ + if (conf->bfd_config) { + bgp_peer_configure_bfd(peer, false); + bgp_peer_config_apply(peer, group); + } } /* Peer group's remote AS configuration. */ @@ -2758,7 +2776,8 @@ int peer_group_delete(struct peer_group *group) XFREE(MTYPE_PEER_GROUP_HOST, group->name); group->name = NULL; - bfd_info_free(&(group->conf->bfd_info)); + if (group->conf->bfd_config) + bgp_peer_remove_bfd_config(group->conf); group->conf->group = NULL; peer_delete(group->conf); @@ -2996,7 +3015,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, } peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as, - group->conf->as_type, 0, 0, group); + group->conf->as_type, group); peer = peer_lock(peer); /* group->peer list reference */ listnode_add(group->peer, peer); @@ -3008,7 +3027,10 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, FOREACH_AFI_SAFI (afi, safi) { if (group->conf->afc[afi][safi]) { peer->afc[afi][safi] = 1; - peer_af_create(peer, afi, safi); + + if (!peer_af_find(peer, afi, safi)) + peer_af_create(peer, afi, safi); + peer_group2peer_config_copy_af(group, peer, afi, safi); } else if (peer->afc[afi][safi]) @@ -3807,7 +3829,7 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp, /* Create peer first; we've already checked group config is valid. */ peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as, - group->conf->as_type, 0, 0, group); + group->conf->as_type, group); if (!peer) return NULL; @@ -7687,7 +7709,7 @@ void bgp_init(unsigned short instance) bgp_clist = community_list_init(); /* BFD init */ - bgp_bfd_init(); + bgp_bfd_init(bm->master); bgp_lp_vty_init(); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 3f5ec07796..51134dc8c5 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -45,6 +45,8 @@ #include "bgp_nexthop.h" #include "bgp_damp.h" +#include "lib/bfd.h" + #define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */ #define BGP_PEER_MAX_HASH_SIZE 16384 @@ -175,9 +177,9 @@ struct bgp_master { #define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1) bool terminating; /* global flag that sigint terminate seen */ - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(bgp_master) +DECLARE_QOBJ_TYPE(bgp_master); /* BGP route-map structure. */ struct bgp_rmap { @@ -477,6 +479,8 @@ struct bgp { #define BGP_FLAG_SHUTDOWN (1 << 27) #define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 28) #define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 29) +#define BGP_FLAG_DEFAULT_IPV6 (1 << 30) +#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1 << 31) enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE] [BGP_GLOBAL_GR_EVENT_CMD]; @@ -661,6 +665,9 @@ struct bgp { /* RB tree of ES-VRFs */ struct bgp_es_vrf_rb_head es_vrf_rb_tree; + /* Hash table of EVPN nexthops maintained per-tenant-VRF */ + struct hash *evpn_nh_table; + /* vrf flags */ uint32_t vrf_flags; #define BGP_VRF_AUTO (1 << 0) @@ -710,14 +717,14 @@ struct bgp { /* BGP route flap dampening configuration */ struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(bgp) +DECLARE_QOBJ_TYPE(bgp); -DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)) +DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)); DECLARE_HOOK(bgp_inst_config_write, (struct bgp *bgp, struct vty *vty), - (bgp, vty)) + (bgp, vty)); /* Thread callback information */ struct afi_safi_info { @@ -1557,8 +1564,29 @@ struct peer { #define PEER_RMAP_TYPE_EXPORT (1U << 7) /* neighbor route-map export */ #define PEER_RMAP_TYPE_AGGREGATE (1U << 8) /* aggregate-address route-map */ - /* peer specific BFD information */ - struct bfd_info *bfd_info; + /** Peer overwrite configuration. */ + struct bfd_session_config { + /** + * Manual configuration bit. + * + * This flag only makes sense for real peers (and not groups), + * it keeps track if the user explicitly configured BFD for a + * peer. + */ + bool manual; + /** Control Plane Independent. */ + bool cbit; + /** Detection multiplier. */ + uint8_t detection_multiplier; + /** Minimum required RX interval. */ + uint32_t min_rx; + /** Minimum required TX interval. */ + uint32_t min_tx; + /** Profile name. */ + char profile[BFD_PROFILE_NAME_LEN]; + /** Peer BFD session */ + struct bfd_session_params *session; + } * bfd_config; /* hostname and domainname advertised by host */ char *hostname; @@ -1574,9 +1602,9 @@ struct peer { bool advmap_config_change[AFI_MAX][SAFI_MAX]; bool advmap_table_change; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(peer) +DECLARE_QOBJ_TYPE(peer); /* Inherit peer attribute from peer-group. */ #define PEER_ATTR_INHERIT(peer, group, attr) \ @@ -1796,7 +1824,7 @@ struct bgp_nlri { /* BGP Dynamic Neighbors feature */ #define BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT 100 #define BGP_DYNAMIC_NEIGHBORS_LIMIT_MIN 1 -#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MAX 5000 +#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MAX 65535 /* Flag for peer_clear_soft(). */ enum bgp_clear_type { @@ -1922,8 +1950,7 @@ extern bool peer_active(struct peer *); extern bool peer_active_nego(struct peer *); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); extern struct peer *peer_create(union sockunion *, const char *, struct bgp *, - as_t, as_t, int, afi_t, safi_t, - struct peer_group *); + as_t, as_t, int, struct peer_group *); extern struct peer *peer_create_accept(struct bgp *); extern void peer_xfer_config(struct peer *dst, struct peer *src); extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, @@ -1991,7 +2018,7 @@ extern bool bgp_update_delay_configured(struct bgp *); extern int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); extern void peer_as_change(struct peer *, as_t, int); extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *, - int, afi_t, safi_t); + int); extern int peer_group_remote_as(struct bgp *, const char *, as_t *, int); extern int peer_delete(struct peer *peer); extern void peer_notify_unconfig(struct peer *peer); @@ -2364,17 +2391,17 @@ extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, /* Hooks */ DECLARE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp), - (bgp, ifp)) -DECLARE_HOOK(peer_status_changed, (struct peer *peer), (peer)) -DECLARE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp)) -DECLARE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp)) + (bgp, ifp)); +DECLARE_HOOK(peer_status_changed, (struct peer *peer), (peer)); +DECLARE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp)); +DECLARE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp)); DECLARE_HOOK(bgp_snmp_update_stats, (struct bgp_node *rn, struct bgp_path_info *pi, bool added), - (rn, pi, added)) + (rn, pi, added)); DECLARE_HOOK(bgp_rpki_prefix_status, (struct peer * peer, struct attr *attr, const struct prefix *prefix), - (peer, attr, prefix)) + (peer, attr, prefix)); void peer_nsf_stop(struct peer *peer); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 88c92f7954..cc64261388 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -52,36 +52,36 @@ #undef BGP_VNC_DEBUG_MATCH_GROUP -DEFINE_MGROUP(RFAPI, "rfapi") -DEFINE_MTYPE(RFAPI, RFAPI_CFG, "NVE Configuration") -DEFINE_MTYPE(RFAPI, RFAPI_GROUP_CFG, "NVE Group Configuration") -DEFINE_MTYPE(RFAPI, RFAPI_L2_CFG, "RFAPI L2 Group Configuration") -DEFINE_MTYPE(RFAPI, RFAPI_RFP_GROUP_CFG, "RFAPI RFP Group Configuration") -DEFINE_MTYPE(RFAPI, RFAPI, "RFAPI Generic") -DEFINE_MTYPE(RFAPI, RFAPI_DESC, "RFAPI Descriptor") -DEFINE_MTYPE(RFAPI, RFAPI_IMPORTTABLE, "RFAPI Import Table") -DEFINE_MTYPE(RFAPI, RFAPI_MONITOR, "RFAPI Monitor VPN") -DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ENCAP, "RFAPI Monitor Encap") -DEFINE_MTYPE(RFAPI, RFAPI_NEXTHOP, "RFAPI Next Hop") -DEFINE_MTYPE(RFAPI, RFAPI_VN_OPTION, "RFAPI VN Option") -DEFINE_MTYPE(RFAPI, RFAPI_UN_OPTION, "RFAPI UN Option") -DEFINE_MTYPE(RFAPI, RFAPI_WITHDRAW, "RFAPI Withdraw") -DEFINE_MTYPE(RFAPI, RFAPI_RFG_NAME, "RFAPI RFGName") -DEFINE_MTYPE(RFAPI, RFAPI_ADB, "RFAPI Advertisement Data") -DEFINE_MTYPE(RFAPI, RFAPI_ETI, "RFAPI Export Table Info") -DEFINE_MTYPE(RFAPI, RFAPI_NVE_ADDR, "RFAPI NVE Address") -DEFINE_MTYPE(RFAPI, RFAPI_PREFIX_BAG, "RFAPI Prefix Bag") -DEFINE_MTYPE(RFAPI, RFAPI_IT_EXTRA, "RFAPI IT Extra") -DEFINE_MTYPE(RFAPI, RFAPI_INFO, "RFAPI Info") -DEFINE_MTYPE(RFAPI, RFAPI_ADDR, "RFAPI Addr") -DEFINE_MTYPE(RFAPI, RFAPI_UPDATED_RESPONSE_QUEUE, "RFAPI Updated Rsp Queue") -DEFINE_MTYPE(RFAPI, RFAPI_RECENT_DELETE, "RFAPI Recently Deleted Route") -DEFINE_MTYPE(RFAPI, RFAPI_L2ADDR_OPT, "RFAPI L2 Address Option") -DEFINE_MTYPE(RFAPI, RFAPI_AP, "RFAPI Advertised Prefix") -DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ETH, "RFAPI Monitor Ethernet") - -DEFINE_QOBJ_TYPE(rfapi_nve_group_cfg) -DEFINE_QOBJ_TYPE(rfapi_l2_group_cfg) +DEFINE_MGROUP(RFAPI, "rfapi"); +DEFINE_MTYPE(RFAPI, RFAPI_CFG, "NVE Configuration"); +DEFINE_MTYPE(RFAPI, RFAPI_GROUP_CFG, "NVE Group Configuration"); +DEFINE_MTYPE(RFAPI, RFAPI_L2_CFG, "RFAPI L2 Group Configuration"); +DEFINE_MTYPE(RFAPI, RFAPI_RFP_GROUP_CFG, "RFAPI RFP Group Configuration"); +DEFINE_MTYPE(RFAPI, RFAPI, "RFAPI Generic"); +DEFINE_MTYPE(RFAPI, RFAPI_DESC, "RFAPI Descriptor"); +DEFINE_MTYPE(RFAPI, RFAPI_IMPORTTABLE, "RFAPI Import Table"); +DEFINE_MTYPE(RFAPI, RFAPI_MONITOR, "RFAPI Monitor VPN"); +DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ENCAP, "RFAPI Monitor Encap"); +DEFINE_MTYPE(RFAPI, RFAPI_NEXTHOP, "RFAPI Next Hop"); +DEFINE_MTYPE(RFAPI, RFAPI_VN_OPTION, "RFAPI VN Option"); +DEFINE_MTYPE(RFAPI, RFAPI_UN_OPTION, "RFAPI UN Option"); +DEFINE_MTYPE(RFAPI, RFAPI_WITHDRAW, "RFAPI Withdraw"); +DEFINE_MTYPE(RFAPI, RFAPI_RFG_NAME, "RFAPI RFGName"); +DEFINE_MTYPE(RFAPI, RFAPI_ADB, "RFAPI Advertisement Data"); +DEFINE_MTYPE(RFAPI, RFAPI_ETI, "RFAPI Export Table Info"); +DEFINE_MTYPE(RFAPI, RFAPI_NVE_ADDR, "RFAPI NVE Address"); +DEFINE_MTYPE(RFAPI, RFAPI_PREFIX_BAG, "RFAPI Prefix Bag"); +DEFINE_MTYPE(RFAPI, RFAPI_IT_EXTRA, "RFAPI IT Extra"); +DEFINE_MTYPE(RFAPI, RFAPI_INFO, "RFAPI Info"); +DEFINE_MTYPE(RFAPI, RFAPI_ADDR, "RFAPI Addr"); +DEFINE_MTYPE(RFAPI, RFAPI_UPDATED_RESPONSE_QUEUE, "RFAPI Updated Rsp Queue"); +DEFINE_MTYPE(RFAPI, RFAPI_RECENT_DELETE, "RFAPI Recently Deleted Route"); +DEFINE_MTYPE(RFAPI, RFAPI_L2ADDR_OPT, "RFAPI L2 Address Option"); +DEFINE_MTYPE(RFAPI, RFAPI_AP, "RFAPI Advertised Prefix"); +DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ETH, "RFAPI Monitor Ethernet"); + +DEFINE_QOBJ_TYPE(rfapi_nve_group_cfg); +DEFINE_QOBJ_TYPE(rfapi_l2_group_cfg); /*********************************************************************** * RFAPI Support ***********************************************************************/ diff --git a/bgpd/rfapi/bgp_rfapi_cfg.h b/bgpd/rfapi/bgp_rfapi_cfg.h index f1548a6173..ef97419c4d 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.h +++ b/bgpd/rfapi/bgp_rfapi_cfg.h @@ -35,9 +35,9 @@ struct rfapi_l2_group_cfg { struct ecommunity *rt_export_list; void *rfp_cfg; /* rfp owned group config */ - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg) +DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg); typedef enum { RFAPI_GROUP_CFG_NVE = 1, @@ -108,9 +108,9 @@ struct rfapi_nve_group_cfg { /* for VRF type groups */ uint32_t label; struct rfapi_descriptor *rfd; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg) +DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg); struct rfapi_rfg_name { struct rfapi_nve_group_cfg *rfg; diff --git a/bgpd/rfapi/rfapi_private.h b/bgpd/rfapi/rfapi_private.h index af56367955..e7825e8bfc 100644 --- a/bgpd/rfapi/rfapi_private.h +++ b/bgpd/rfapi/rfapi_private.h @@ -367,33 +367,33 @@ extern int rfapi_extract_l2o( */ extern time_t rfapi_time(time_t *t); -DECLARE_MGROUP(RFAPI) -DECLARE_MTYPE(RFAPI_CFG) -DECLARE_MTYPE(RFAPI_GROUP_CFG) -DECLARE_MTYPE(RFAPI_L2_CFG) -DECLARE_MTYPE(RFAPI_RFP_GROUP_CFG) -DECLARE_MTYPE(RFAPI) -DECLARE_MTYPE(RFAPI_DESC) -DECLARE_MTYPE(RFAPI_IMPORTTABLE) -DECLARE_MTYPE(RFAPI_MONITOR) -DECLARE_MTYPE(RFAPI_MONITOR_ENCAP) -DECLARE_MTYPE(RFAPI_NEXTHOP) -DECLARE_MTYPE(RFAPI_VN_OPTION) -DECLARE_MTYPE(RFAPI_UN_OPTION) -DECLARE_MTYPE(RFAPI_WITHDRAW) -DECLARE_MTYPE(RFAPI_RFG_NAME) -DECLARE_MTYPE(RFAPI_ADB) -DECLARE_MTYPE(RFAPI_ETI) -DECLARE_MTYPE(RFAPI_NVE_ADDR) -DECLARE_MTYPE(RFAPI_PREFIX_BAG) -DECLARE_MTYPE(RFAPI_IT_EXTRA) -DECLARE_MTYPE(RFAPI_INFO) -DECLARE_MTYPE(RFAPI_ADDR) -DECLARE_MTYPE(RFAPI_UPDATED_RESPONSE_QUEUE) -DECLARE_MTYPE(RFAPI_RECENT_DELETE) -DECLARE_MTYPE(RFAPI_L2ADDR_OPT) -DECLARE_MTYPE(RFAPI_AP) -DECLARE_MTYPE(RFAPI_MONITOR_ETH) +DECLARE_MGROUP(RFAPI); +DECLARE_MTYPE(RFAPI_CFG); +DECLARE_MTYPE(RFAPI_GROUP_CFG); +DECLARE_MTYPE(RFAPI_L2_CFG); +DECLARE_MTYPE(RFAPI_RFP_GROUP_CFG); +DECLARE_MTYPE(RFAPI); +DECLARE_MTYPE(RFAPI_DESC); +DECLARE_MTYPE(RFAPI_IMPORTTABLE); +DECLARE_MTYPE(RFAPI_MONITOR); +DECLARE_MTYPE(RFAPI_MONITOR_ENCAP); +DECLARE_MTYPE(RFAPI_NEXTHOP); +DECLARE_MTYPE(RFAPI_VN_OPTION); +DECLARE_MTYPE(RFAPI_UN_OPTION); +DECLARE_MTYPE(RFAPI_WITHDRAW); +DECLARE_MTYPE(RFAPI_RFG_NAME); +DECLARE_MTYPE(RFAPI_ADB); +DECLARE_MTYPE(RFAPI_ETI); +DECLARE_MTYPE(RFAPI_NVE_ADDR); +DECLARE_MTYPE(RFAPI_PREFIX_BAG); +DECLARE_MTYPE(RFAPI_IT_EXTRA); +DECLARE_MTYPE(RFAPI_INFO); +DECLARE_MTYPE(RFAPI_ADDR); +DECLARE_MTYPE(RFAPI_UPDATED_RESPONSE_QUEUE); +DECLARE_MTYPE(RFAPI_RECENT_DELETE); +DECLARE_MTYPE(RFAPI_L2ADDR_OPT); +DECLARE_MTYPE(RFAPI_AP); +DECLARE_MTYPE(RFAPI_MONITOR_ETH); /* diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 4614363bf0..583d1cd207 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -96,6 +96,8 @@ bgpd_libbgp_a_SOURCES = \ bgpd/bgp_regex.c \ bgpd/bgp_route.c \ bgpd/bgp_routemap.c \ + bgpd/bgp_routemap_nb.c \ + bgpd/bgp_routemap_nb_config.c \ bgpd/bgp_script.c \ bgpd/bgp_table.c \ bgpd/bgp_updgrp.c \ @@ -176,7 +178,9 @@ noinst_HEADERS += \ bgpd/bgp_pbr.h \ bgpd/bgp_rd.h \ bgpd/bgp_regex.h \ + bgpd/bgp_rpki.h \ bgpd/bgp_route.h \ + bgpd/bgp_routemap_nb.h \ bgpd/bgp_script.h \ bgpd/bgp_table.h \ bgpd/bgp_updgrp.h \ @@ -220,7 +224,7 @@ bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(US bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(UST_LIBS) bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c bgpd/bgp_mplsvpn_snmp.c -bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 bgpd_bgpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic bgpd_bgpd_snmp_la_LIBADD = lib/libfrrsnmp.la @@ -254,4 +258,6 @@ nodist_bgpd_bgpd_SOURCES = \ yang/frr-bgp-bmp.yang.c \ yang/frr-bgp-rpki.yang.c \ yang/frr-deviations-bgp-datacenter.yang.c \ + yang/frr-bgp-filter.yang.c \ + yang/frr-bgp-route-map.yang.c \ # end diff --git a/configure.ac b/configure.ac index b034fab50c..f9516e559f 100755 --- a/configure.ac +++ b/configure.ac @@ -288,11 +288,17 @@ if test "$enable_clang_coverage" = "yes"; then fi if test "$enable_scripting" = "yes"; then - AX_PROG_LUA([5.3]) - AX_LUA_HEADERS + AX_PROG_LUA([5.3], [5.4], [], [ + AC_MSG_ERROR([Lua 5.3 is required to build with Lua support. No other version is supported.]) + ]) + AX_LUA_HEADERS([], [ + AC_MSG_ERROR([Lua 5.3 headers are required to build with Lua support. No other version is supported.]) + ]) AX_LUA_LIBS([ - AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting]) - LIBS="$LIBS $LUA_LIB" + AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting]) + LIBS="$LIBS $LUA_LIB" + ], [ + AC_MSG_ERROR([Lua 5.3 libraries are required to build with Lua support. No other version is supported.]) ]) fi @@ -301,6 +307,7 @@ if test "$enable_dev_build" = "yes"; then if test "$orig_cflags" = ""; then AC_C_FLAG([-g3]) AC_C_FLAG([-O0]) + AC_C_FLAG([-ggdb3]) fi else if test "$orig_cflags" = ""; then @@ -308,6 +315,7 @@ else AC_C_FLAG([-O2]) fi fi + AM_CONDITIONAL([DEV_BUILD], [test "$enable_dev_build" = "yes"]) dnl always want these CFLAGS diff --git a/doc/developer/_static/overrides.css b/doc/developer/_static/overrides.css index 1d702bb6e9..302b8d6bd7 100644 --- a/doc/developer/_static/overrides.css +++ b/doc/developer/_static/overrides.css @@ -214,6 +214,22 @@ pre { .highlight .na { color: var(--primary-2); } .highlight .nv { color: var(--complement-0); } +.rst-content code.frrfmtout { + background-color: var(--secondary-1-9); + border-color: var(--secondary-1-1); + font-size:100%; +} +.rst-content code.frrfmtout::before { + content: "⇒ \""; +} +.rst-content code.frrfmtout::after { + content: "\""; +} +.rst-content code.frrfmtout span { + color: var(--secondary-1-4); + font-size:100%; +} + strong { font-weight:500; } diff --git a/doc/developer/building-frr-for-ubuntu2004.rst b/doc/developer/building-frr-for-ubuntu2004.rst index ffc05a6841..58d72e2891 100644 --- a/doc/developer/building-frr-for-ubuntu2004.rst +++ b/doc/developer/building-frr-for-ubuntu2004.rst @@ -27,7 +27,7 @@ ubuntu apt repositories; in order to install it: .. code-block:: shell - curl https://bootstrap.pypa.io/2.7/get-pip.py --output get-pip.py + curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py sudo python2 ./get-pip.py # And verify the installation diff --git a/doc/developer/conf.py b/doc/developer/conf.py index f4bb65ec79..20265f4aad 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -17,6 +17,8 @@ import os import re import pygments from sphinx.highlighting import lexers +from sphinx.util import logging +logger = logging.getLogger(__name__) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -362,11 +364,37 @@ texinfo_documents = [ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() +frrfmt_re = re.compile(r'^\s*%(?P<spec>[^\s]+)\s+\((?P<types>.*)\)\s*$') + +def parse_frrfmt(env, text, node): + from sphinx import addnodes + + m = frrfmt_re.match(text) + if not m: + logger.warning('could not parse frrfmt:: %r' % (text), location=node) + node += addnodes.desc_name(text, text) + return text + + spec, types = m.group('spec'), m.group('types') + + node += addnodes.desc_sig_operator('%', '%') + node += addnodes.desc_name(spec + ' ', spec + ' ') + plist = addnodes.desc_parameterlist() + for typ in types.split(','): + typ = typ.strip() + plist += addnodes.desc_parameter(typ, typ) + node += plist + return '%' + spec + # custom extensions here def setup(app): # object type for FRR CLI commands, can be extended to document parent CLI # node later on app.add_object_type("clicmd", "clicmd") + + # printfrr extensions + app.add_object_type("frrfmt", "frrfmt", parse_node=parse_frrfmt) + # css overrides for HTML theme app.add_stylesheet("overrides.css") # load Pygments lexer for FRR config syntax diff --git a/doc/developer/hooks.rst b/doc/developer/hooks.rst index 10fe6b9c43..b37a4aeea7 100644 --- a/doc/developer/hooks.rst +++ b/doc/developer/hooks.rst @@ -15,13 +15,13 @@ Example: :caption: mydaemon.h #include "hook.h" - DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info)) + DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info)); .. code-block:: c :caption: mydaemon.c #include "mydaemon.h" - DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info)) + DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info)); ... hook_call(some_update_event, info); @@ -110,9 +110,9 @@ Definition .. code-block:: c - DECLARE_HOOK(foo, (), ()) - DECLARE_HOOK(bar, (int arg), (arg)) - DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y)) + DECLARE_HOOK(foo, (), ()); + DECLARE_HOOK(bar, (int arg), (arg)); + DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y)); .. c:macro:: DEFINE_HOOK(name, arglist, passlist) diff --git a/doc/developer/link-state.rst b/doc/developer/link-state.rst index f1fc52966b..1cbaf27ffe 100644 --- a/doc/developer/link-state.rst +++ b/doc/developer/link-state.rst @@ -81,26 +81,47 @@ corresponds to a Link State information conveyed by the routing protocol. Functions ^^^^^^^^^ -A set of functions is provided to create, delete and compare Link State Node: +A set of functions is provided to create, delete and compare Link State +Node, Atribute and Prefix: .. c:function:: struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr router_id, struct in6_addr router6_id) -.. c:function:: voidls_node_del(struct ls_node *node) -.. c:function:: int ls_node_same(struct ls_node *n1, struct ls_node *n2) +.. c:function:: struct ls_attributes *ls_attributes_new(struct ls_node_id adv, struct in_addr local, struct in6_addr local6, uint32_t local_id) +.. c:function:: struct ls_prefix *ls_prefix_new(struct ls_node_id adv, struct prefix p) -and Link State Attributes: + Create respectively a new Link State Node, Attribute or Prefix. + Structure is dynamically allocated. Link State Node ID (adv) is mandatory + and: -.. c:function:: struct ls_attributes *ls_attributes_new(struct ls_node_id adv, struct in_addr local, struct in6_addr local6, uint32_t local_id) + - at least one of IPv4 or IPv6 must be provided for the router ID + (router_id or router6_id) for Node + - at least one of local, local6 or local_id must be provided for Attribute + - prefix is mandatory for Link State Prefix. + +.. c:function:: void ls_node_del(struct ls_node *node) .. c:function:: void ls_attributes_del(struct ls_attributes *attr) +.. c:function:: void ls_prefix_del(struct ls_prefix *pref) + + Remove, respectively Link State Node, Attributes or Prefix. + Data structure is freed. + +.. c:function:: void ls_attributes_srlg_del(struct ls_attributes *attr) + + Remove SRLGs attribute if defined. Data structure is freed. + +.. c:function:: int ls_node_same(struct ls_node *n1, struct ls_node *n2) .. c:function:: int ls_attributes_same(struct ls_attributes *a1, struct ls_attributes *a2) +.. c:function:: int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix*p2) + + Check, respectively if two Link State Nodes, Attributes or Prefix are equal. + Note that these routines have the same return value sense as '==' (which is + different from a comparison). -The low level API doesn't provide any particular functions for the Link State -Prefix structure as this latter is simpler to manipulate. Link State TED -------------- This is the high level API that provides functions to create, update, delete a -Link State Database to from a Traffic Engineering Database (TED). +Link State Database to build a Traffic Engineering Database (TED). Data Structures ^^^^^^^^^^^^^^^ @@ -143,35 +164,143 @@ A unique Key is used to identify both Vertices and Edges within the Graph. .. c:type:: struct ls_prefix .. c:type:: struct ls_ted +TED stores Vertex, Edge and Subnet elements with a RB Tree structure. +The Vertex key corresponds to the Router ID for OSPF and ISO System ID for +IS-IS. The Edge key corresponds to the IPv4 address, the lowest 64 bits of +the IPv6 address or the combination of the local & remote ID of the interface. +The Subnet key corresponds to the Prefix address (v4 or v6). -Functions -^^^^^^^^^ +An additional status for Vertex, Edge and Subnet allows to determine the state +of the element in the TED: UNSET, NEW, UPDATE, DELETE, SYNC, ORPHAN. Normal +state is SYNC. NEW, UPDATE and DELETE are temporary state when element is +processed. UNSET is normally never used and ORPHAN serves to identify elements +that must be remove when TED is cleaning. + +Vertex, Edges and Subnets management functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. c:function:: struct ls_vertex *ls_vertex_add(struct ls_ted *ted, struct ls_node *node) +.. c:function:: struct ls_edge *ls_edge_add(struct ls_ted *ted, struct ls_attributes *attributes) +.. c:function:: struct ls_subnet *ls_subnet_add(struct ls_ted *ted, struct ls_prefix *pref) + + Add, respectively new Vertex, Edge or Subnet to the Link State Datebase. + Vertex, Edge or Subnet are created from, respectively the Link State Node, + Attribute or Prefix structure. Data structure are dynamically allocated. + .. c:function:: struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node) +.. c:function:: struct ls_edge *ls_edge_update(struct ls_ted *ted, struct ls_attributes *attributes) +.. c:function:: struct ls_subnet *ls_subnet_update(struct ls_ted *ted, struct ls_prefix *pref) + + Update, respectively Vertex, Edge or Subnet with, respectively the Link + State Node, Attribute or Prefix. A new data structure is created if no one + corresponds to the Link State Node, Attribute or Prefix. If element already + exists in the TED, its associated Link State information is replaced by the + new one if there are different and the old associated Link State information + is deleted and memory freed. + .. c:function:: void ls_vertex_del(struct ls_ted *ted, struct ls_vertex *vertex) +.. c:function:: void ls_vertex_del_all(struct ls_ted *ted, struct ls_vertex *vertex) +.. c:function:: void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge) +.. c:function:: void ls_edge_del_all(struct ls_ted *ted, struct ls_edge *edge) +.. c:function:: void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet) +.. c:function:: void ls_subnet_del_all(struct ls_ted *ted, struct ls_subnet *subnet) + + Delete, respectively Link State Vertex, Edge or Subnet. Data structure are + freed but not the associated Link State information with the simple `_del()` + form of the function while the `_del_all()` version freed also associated + Link State information. TED is not modified if Vertex, Edge or Subnet is + NULL or not found in the Data Base. Note that references between Vertices, + Edges and Subnets are removed first. + .. c:function:: struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted, const uint64_t key) .. c:function:: struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted, struct ls_node_id id) -.. c:function:: int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2) -.. c:function:: struct ls_edge *ls_edge_add(struct ls_ted *ted, struct ls_attributes *attributes) -.. c:function:: struct ls_edge *ls_edge_update(struct ls_ted *ted, struct ls_attributes *attributes) -.. c:function:: void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge) + Find Vertex in the TED by its unique key or its Link State Node ID. + Return Vertex if found, NULL otherwise. + .. c:function:: struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted, const uint64_t key) .. c:function:: struct ls_edge *ls_find_edge_by_source(struct ls_ted *ted, struct ls_attributes *attributes); .. c:function:: struct ls_edge *ls_find_edge_by_destination(struct ls_ted *ted, struct ls_attributes *attributes); -.. c:function:: struct ls_subnet *ls_subnet_add(struct ls_ted *ted, struct ls_prefix *pref) -.. c:function:: void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet) + Find Edge in the Link State Data Base by its key, source or distination + (local IPv4 or IPv6 address or local ID) informations of the Link State + Attributes. Return Edge if found, NULL otherwise. + .. c:function:: struct ls_subnet *ls_find_subnet(struct ls_ted *ted, const struct prefix prefix) + Find Subnet in the Link State Data Base by its key, i.e. the associated + prefix. Return Subnet if found, NULL otherwise. + +.. c:function:: int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2) +.. c:function:: int ls_edge_same(struct ls_edge *e1, struct ls_edge *e2) +.. c:function:: int ls_subnet_same(struct ls_subnet *s1, struct ls_subnet *s2) + + Check, respectively if two Vertices, Edges or Subnets are equal. + Note that these routines has the same return value sense as '==' + (which is different from a comparison). + + +TED management functions +^^^^^^^^^^^^^^^^^^^^^^^^ + +Some helpers functions have been also provided to ease TED management: + .. c:function:: struct ls_ted *ls_ted_new(const uint32_t key, char *name, uint32_t asn) + + Create a new Link State Data Base. Key must be different from 0. + Name could be NULL and AS number equal to 0 if unknown. + .. c:function:: void ls_ted_del(struct ls_ted *ted) +.. c:function:: void ls_ted_del_all(struct ls_ted *ted) + + Delete existing Link State Data Base. Vertices, Edges, and Subnets are not + removed with ls_ted_del() function while they are with ls_ted_del_all(). + .. c:function:: void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst, struct ls_edge *edge) + + Connect Source and Destination Vertices by given Edge. Only non NULL source + and destination vertices are connected. + .. c:function:: void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge, bool source) .. c:function:: void ls_disconnect(struct ls_vertex *vertex, struct ls_edge *edge, bool source) + + Connect / Disconnect Link State Edge to the Link State Vertex which could be + a Source (source = true) or a Destination (source = false) Vertex. + .. c:function:: void ls_disconnect_edge(struct ls_edge *edge) + Disconnect Link State Edge from both Source and Destination Vertex. + Note that Edge is not removed but its status is marked as ORPHAN. + +.. c:function:: void ls_vertex_clean(struct ls_ted *ted, struct ls_vertex *vertex, struct zclient *zclient) + + Clean Vertex structure by removing all Edges and Subnets marked as ORPHAN + from this vertex. Corresponding Link State Update message is sent if zclient + parameter is not NULL. Note that associated Link State Attribute and Prefix + are also removed and memory freed. + +.. c:function:: void ls_ted_clean(struct ls_ted *ted) + + Clean Link State Data Base by removing all Vertices, Edges and SubNets + marked as ORPHAN. Note that associated Link State Node, Attributes and + Prefix are removed too. + +.. c:function:: void ls_show_vertex(struct ls_vertex *vertex, struct vty *vty, struct json_object *json, bool verbose) +.. c:function:: void ls_show_edge(struct ls_edeg *edge, struct vty *vty, struct json_object *json, bool verbose) +.. c:function:: void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty, struct json_object *json, bool verbose) +.. c:function:: void ls_show_vertices(struct ls_ted *ted, struct vty *vty, struct json_object *json, bool verbose) +.. c:function:: void ls_show_edges(struct ls_ted *ted, struct vty *vty, struct json_object *json, bool verbose) +.. c:function:: void ls_show_subnets(struct ls_ted *ted, struct vty *vty, struct json_object *json, bool verbose) +.. c:function:: void ls_show_ted(struct ls_ted *ted, struct vty *vty, struct json_object *json, bool verbose) + + Respectively, show Vertex, Edge, Subnet provided as parameter, all Vertices, + all Edges, all Subnets and the whole TED if not specified. Output could be + more detailed with verbose parameter for VTY output. If both JSON and VTY + output are specified, JSON takes precedence over VTY. + +.. c:function:: void ls_dump_ted(struct ls_ted *ted) + + Dump TED information to the current logging output. Link State Messages ------------------- @@ -198,8 +327,8 @@ Figure 1 below, illustrates the ZAPI Opaque message exchange between a message sequences are as follows: - First, both *Producer* and *Consumer* must register to their respective ZAPI - Opaque Message. **Link State Sync** for the *Producer* in order to receive - Database synchronisation request from a *Consumer*. **Link State Update** for + Opaque Message: **Link State Sync** for the *Producer* in order to receive + Database synchronisation request from a *Consumer*, **Link State Update** for the *Consumer* in order to received any Link State update from a *Producer*. These register messages are stored by Zebra to determine to which daemon it should redistribute the ZAPI messages it receives. @@ -245,22 +374,22 @@ message sequences are as follows: | | Request LS Sync | v \ | Request LS Sync |<----------------------------| | |<-----------------------------| | Synchronistation - | LS DB Sync | | Phase - |----------------------------->| LS DB Sync | | + | LS DB Update | | Phase + |----------------------------->| LS DB Update | | | |---------------------------->| | - | LS DB Sync (cont'd) | | | - |----------------------------->| LS DB Sync (cont'd) | | + | LS DB Update (cont'd) | | | + |----------------------------->| LS DB Update (cont'd) | | | . |---------------------------->| | | . | . | | | . | . | | - | LS DB Sync (end) | . | | - |----------------------------->| LS DB Sync (end) | | + | LS DB Update (end) | . | | + |----------------------------->| LS DB Update (end) | | | |---------------------------->| | | | | / : : : : : : - | LS Update | | \ - |----------------------------->| LS Update | | + | LS DB Update | | \ + |----------------------------->| LS DB Update | | | |---------------------------->| Update Phase | | | | : : : / @@ -269,7 +398,7 @@ message sequences are as follows: | | Unregister LS Update | | | |<----------------------------| Deregister Phase | | | | - | LS Update | | | + | LS DB Update | | | |----------------------------->| | | | | | / | | | @@ -305,10 +434,65 @@ Opaque Link State type at once. Functions ^^^^^^^^^ +.. c:function:: int ls_register(struct zclient *zclient, bool server) +.. c:function:: int ls_unregister(struct zclient *zclient, bool server) + + Register / Unregister daemon to received ZAPI Link State Opaque messages. + Server must be set to true for *Producer* and to false for *Consumer*. + +.. c:function:: int ls_request_sync(struct zclient *zclient) + + Request initial Synchronisation to collect the whole Link State Database. + .. c:function:: struct ls_message *ls_parse_msg(struct stream *s) + + Parse Link State Message from stream. Used this function once receiving a + new ZAPI Opaque message of type Link State. + +.. c:function:: void ls_delete_msg(struct ls_message *msg) + + Delete existing message. Data structure is freed. + .. c:function:: int ls_send_msg(struct zclient *zclient, struct ls_message *msg, struct zapi_opaque_reg_info *dst) + + Send Link State Message as new ZAPI Opaque message of type Link State. + If destination is not NULL, message is sent as Unicast otherwise it is + broadcast to all registered daemon. + .. c:function:: struct ls_message *ls_vertex2msg(struct ls_message *msg, struct ls_vertex *vertex) .. c:function:: struct ls_message *ls_edge2msg(struct ls_message *msg, struct ls_edge *edge) .. c:function:: struct ls_message *ls_subnet2msg(struct ls_message *msg, struct ls_subnet *subnet) + + Create respectively a new Link State Message from a Link State Vertex, Edge + or Subnet. If Link State Message is NULL, a new data structure is + dynamically allocated. Note that the Vertex, Edge and Subnet status is used + to determine the corresponding Link State Message event: ADD, UPDATE, + DELETE, SYNC. + +.. c:function:: int ls_msg2vertex(struct ls_ted *ted, struct ls_message *msg) +.. c:function:: int ls_msg2edge(struct ls_ted *ted, struct ls_message *msg) +.. c:function:: int ls_msg2subnet(struct ls_ted *ted, struct ls_message *msg) + + Convert Link State Message respectively in Vertex, Edge or Subnet and + update the Link State Database accordingly to the message event: SYNC, ADD, + UPDATE or DELETE. + +.. c:function:: struct ls_element *ls_msg2ted(struct ls_ted *ted, struct ls_message *msg, bool delete) +.. c:function:: struct ls_element *ls_stream2ted(struct ls_ted *ted, struct ls_message *msg, bool delete) + + Convert Link State Message or Stream Buffer in a Link State element (Vertex, + Edge or Subnet) and update the Link State Database accordingly to the + message event: SYNC, ADD, UPDATE or DELETE. The function return the generic + structure ls_element that point to the Vertex, Edge or Subnet which has been + added, updated or synchronous in the database. Note that the delete boolean + parameter governs the action for the DELETE action: true, Link State Element + is removed from the database and NULL is return. If set to false, database + is not updated and the function sets the Link State Element status to + Delete and return the element for futur deletion by the calling function. + .. c:function:: int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient, struct zapi_opaque_reg_info *dst) + Send all the content of the Link State Data Base to the given destination. + Link State content is sent is this order: Vertices, Edges then Subnet. + This function must be used when a daemon request a Link State Data Base + Synchronization. diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst index 28b21533c0..86db788c0e 100644 --- a/doc/developer/lists.rst +++ b/doc/developer/lists.rst @@ -140,7 +140,7 @@ The common setup pattern will look like this: #include <typesafe.h> - PREDECL_XXX(Z) + PREDECL_XXX(Z); struct item { int otherdata; struct Z_item mylistitem; @@ -149,20 +149,20 @@ The common setup pattern will look like this: struct Z_head mylisthead; /* unsorted: */ - DECLARE_XXX(Z, struct item, mylistitem) + DECLARE_XXX(Z, struct item, mylistitem); /* sorted, items that compare as equal cannot be added to list */ int compare_func(const struct item *a, const struct item *b); - DECLARE_XXX_UNIQ(Z, struct item, mylistitem, compare_func) + DECLARE_XXX_UNIQ(Z, struct item, mylistitem, compare_func); /* sorted, items that compare as equal can be added to list */ int compare_func(const struct item *a, const struct item *b); - DECLARE_XXX_NONUNIQ(Z, struct item, mylistitem, compare_func) + DECLARE_XXX_NONUNIQ(Z, struct item, mylistitem, compare_func); /* hash tables: */ int compare_func(const struct item *a, const struct item *b); uint32_t hash_func(const struct item *a); - DECLARE_XXX(Z, struct item, mylistitem, compare_func, hash_func) + DECLARE_XXX(Z, struct item, mylistitem, compare_func, hash_func); ``XXX`` is replaced with the name of the data structure, e.g. ``SKIPLIST`` or ``ATOMLIST``. The ``DECLARE_XXX`` invocation can either occur in a `.h` diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index a35e60619c..b827afd6cc 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -1,5 +1,7 @@ .. _logging: +.. highlight:: c + Logging ======= @@ -52,46 +54,50 @@ are available: if (ret != buf) XFREE(MTYPE_FOO, ret); -Extensions -^^^^^^^^^^ - -``printfrr()`` format strings can be extended with suffixes after `%p` or -`%d`. The following extended format specifiers are available: - -+-----------+--------------------------+----------------------------------------------+ -| Specifier | Argument | Output | -+===========+==========================+==============================================+ -| ``%Lu`` | ``uint64_t`` | ``12345`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%Ld`` | ``int64_t`` | ``-12345`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pI4`` | ``struct in_addr *`` | ``1.2.3.4`` | -| | | | -| | ``in_addr_t *`` | | -+-----------+--------------------------+----------------------------------------------+ -| ``%pI6`` | ``struct in6_addr *`` | ``fe80::1234`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pIA`` | ``struct ipaddr *`` | ``1.2.3.4`` | -| | | | -| | | ``fe80::1234`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pFX`` | ``struct prefix *`` | ``fe80::1234/64`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pSG4`` | ``struct prefix_sg *`` | ``(*,1.2.3.4)`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pRN`` | ``struct route_node *`` | ``192.168.1.0/24`` (dst-only node) | -| | | | -| | | ``2001:db8::/32 from fe80::/64`` (SADR node) | -+-----------+--------------------------+----------------------------------------------+ -| ``%pNHv`` | ``struct nexthop *`` | ``1.2.3.4, via eth0`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pNHs`` | ``struct nexthop *`` | ``1.2.3.4 if 15`` | -+-----------+--------------------------+----------------------------------------------+ -| ``%pFX`` | ``struct bgp_dest *`` | ``fe80::1234/64`` (available in BGP only) | -+-----------+--------------------------+----------------------------------------------+ +.. c:function:: ssize_t bprintfrr(struct fbuf *fb, const char *fmt, ...) +.. c:function:: ssize_t vbprintfrr(struct fbuf *fb, const char *fmt, va_list) + + These are the "lowest level" functions, which the other variants listed + above use to implement their functionality on top. Mainly useful for + implementing printfrr extensions since those get a ``struct fbuf *`` to + write their output to. + +.. c:macro:: FMT_NSTD(expr) + + This macro turns off/on format warnings as needed when non-ISO-C + compatible printfrr extensions are used (e.g. ``%.*p`` or ``%Ld``.):: + + vty_out(vty, "standard compatible %pI4\n", &addr); + FMT_NSTD(vty_out(vty, "non-standard %-47.*pHX\n", (int)len, buf)); + + When the frr-format plugin is in use, this macro is a no-op since the + frr-format plugin supports all printfrr extensions. Since the FRR CI + includes a system with the plugin enabled, this means format errors will + not slip by undetected even with FMT_NSTD. + +.. note:: + ``printfrr()`` does not support the ``%n`` format. + +AS-Safety +^^^^^^^^^ + +``printfrr()`` are AS-Safe under the following conditions: + +* the ``[v]as[n]printfrr`` variants are not AS-Safe (allocating memory) +* floating point specifiers are not AS-Safe (system printf is used for these) +* the positional ``%1$d`` syntax should not be used (8 arguments are supported + while AS-Safe) +* extensions are only AS-Safe if their printer is AS-Safe + +printfrr Extensions +------------------- + +``printfrr()`` format strings can be extended with suffixes after `%p` or `%d`. Printf features like field lengths can be used normally with these extensions, -e.g. ``%-15pI4`` works correctly. +e.g. ``%-15pI4`` works correctly, **except if the extension consumes the +width or precision**. Extensions that do so are listed below as ``%*pXX`` +rather than ``%pXX``. The extension specifier after ``%p`` or ``%d`` is always an uppercase letter; by means of established pattern uppercase letters and numbers form the type @@ -99,10 +105,7 @@ identifier which may be followed by lowercase flags. You can grep the FRR source for ``printfrr_ext_autoreg`` to see all extended printers and what exactly they do. More printers are likely to be added as -needed/useful, so the list above may become outdated. - -``%Ld`` is not an "extension" for printfrr; it's wired directly into the main -printf logic. +needed/useful, so the list here may be outdated. .. note:: @@ -111,16 +114,218 @@ printf logic. **not** available when calling ``snprintf`` directly. You need to call ``snprintfrr`` instead. -AS-Safety -^^^^^^^^^ +Networking data types +^^^^^^^^^^^^^^^^^^^^^ -``printfrr()`` are AS-Safe under the following conditions: +.. role:: frrfmtout(code) -* the ``[v]as[n]printfrr`` variants are not AS-Safe (allocating memory) -* floating point specifiers are not AS-Safe (system printf is used for these) -* the positional ``%1$d`` syntax should not be used (8 arguments are supported - while AS-Safe) -* extensions are only AS-Safe if their printer is AS-Safe +.. frrfmt:: %pI4 (struct in_addr *, in_addr_t *) + + :frrfmtout:`1.2.3.4` + +.. frrfmt:: %pI6 (struct in6_addr *) + + :frrfmtout:`fe80::1234` + +.. frrfmt:: %pEA (struct ethaddr *) + + :frrfmtout:`01:23:45:67:89:ab` + +.. frrfmt:: %pIA (struct ipaddr *) + + :frrfmtout:`1.2.3.4` / :frrfmtout:`fe80::1234` + +.. frrfmt:: %pFX (struct prefix *) + + :frrfmtout:`1.2.3.0/24` / :frrfmtout:`fe80::1234/64` + + This accepts the following types: + + - :c:struct:`prefix` + - :c:struct:`prefix_ipv4` + - :c:struct:`prefix_ipv6` + - :c:struct:`prefix_eth` + - :c:struct:`prefix_evpn` + - :c:struct:`prefix_fs` + + It does **not** accept the following types: + + - :c:struct:`prefix_ls` + - :c:struct:`prefix_rd` + - :c:struct:`prefix_ptr` + - :c:struct:`prefix_sg` (use :frrfmt:`%pSG4`) + - :c:union:`prefixptr` (dereference to get :c:struct:`prefix`) + - :c:union:`prefixconstptr` (dereference to get :c:struct:`prefix`) + +.. frrfmt:: %pSG4 (struct prefix_sg *) + + :frrfmtout:`(*,1.2.3.4)` + + This is *(S,G)* output for use in pimd. (Note prefix_sg is not a prefix + "subclass" like the other prefix_* structs.) + +.. frrfmt:: %pSU (union sockunion *) + + ``%pSU``: :frrfmtout:`1.2.3.4` / :frrfmtout:`fe80::1234` + + ``%pSUs``: :frrfmtout:`1.2.3.4` / :frrfmtout:`fe80::1234%89` + (adds IPv6 scope ID as integer) + + ``%pSUp``: :frrfmtout:`1.2.3.4:567` / :frrfmtout:`[fe80::1234]:567` + (adds port) + + ``%pSUps``: :frrfmtout:`1.2.3.4:567` / :frrfmtout:`[fe80::1234%89]:567` + (adds port and scope ID) + +.. frrfmt:: %pRN (struct route_node *, struct bgp_node *, struct agg_node *) + + :frrfmtout:`192.168.1.0/24` (dst-only node) + + :frrfmtout:`2001:db8::/32 from fe80::/64` (SADR node) + +.. frrfmt:: %pNH (struct nexthop *) + + ``%pNHvv``: :frrfmtout:`via 1.2.3.4, eth0` — verbose zebra format + + ``%pNHv``: :frrfmtout:`1.2.3.4, via eth0` — slightly less verbose zebra format + + ``%pNHs``: :frrfmtout:`1.2.3.4 if 15` — same as :c:func:`nexthop2str()` + +.. frrfmt:: %pBD (struct bgp_dest *) + + :frrfmtout:`fe80::1234/64` + + (only available in bgpd.) + +.. frrfmt:: %dPF (int) + + :frrfmtout:`AF_INET` + + Prints an `AF_*` / `PF_*` constant. ``PF`` is used here to avoid confusion + with `AFI` constants, even though the FRR codebase prefers `AF_INET` over + `PF_INET` & co. + +.. frrfmt:: %dSO (int) + + :frrfmtout:`SOCK_STREAM` + +General utility formats +^^^^^^^^^^^^^^^^^^^^^^^ + +.. frrfmt:: %m (no argument) + + :frrfmtout:`Permission denied` + + Prints ``strerror(errno)``. Does **not** consume any input argument, don't + pass ``errno``! + + (This is a GNU extension not specific to FRR. FRR guarantees it is + available on all systems in printfrr, though BSDs support it in printf too.) + +.. frrfmt:: %pSQ (char *) + + ([S]tring [Q]uote.) Like ``%s``, but produce a quoted string. Options: + + ``n`` - treat ``NULL`` as empty string instead. + + ``q`` - include ``""`` quotation marks. Note: ``NULL`` is printed as + ``(null)``, not ``"(null)"`` unless ``n`` is used too. This is + intentional. + + ``s`` - use escaping suitable for RFC5424 syslog. This means ``]`` is + escaped too. + + If a length is specified (``%*pSQ`` or ``%.*pSQ``), null bytes in the input + string do not end the string and are just printed as ``\x00``. + +.. frrfmt:: %pSE (char *) + + ([S]tring [E]scape.) Like ``%s``, but escape special characters. + Options: + + ``n`` - treat ``NULL`` as empty string instead. + + Unlike :frrfmt:`%pSQ`, this escapes many more characters that are fine for + a quoted string but not on their own. + + If a length is specified (``%*pSE`` or ``%.*pSE``), null bytes in the input + string do not end the string and are just printed as ``\x00``. + +.. frrfmt:: %pVA (struct va_format *) + + Recursively invoke printfrr, with arguments passed in through: + + .. c:struct:: va_format + + .. c:member:: const char *fmt + + Format string to use for the recursive printfrr call. + + .. c:member:: va_list *va + + Formatting arguments. Note this is passed as a pointer, not - as in + most other places - a direct struct reference. Internally uses + ``va_copy()`` so repeated calls can be made (e.g. for determining + output length.) + +.. frrfmt:: %pFB (struct fbuf *) + + Insert text from a ``struct fbuf *``, i.e. the output of a call to + :c:func:`bprintfrr()`. + +.. frrfmt:: %*pHX (void *, char *, unsigned char *) + + ``%pHX``: :frrfmtout:`12 34 56 78` + + ``%pHXc``: :frrfmtout:`12:34:56:78` (separate with [c]olon) + + ``%pHXn``: :frrfmtout:`12345678` (separate with [n]othing) + + Insert hexdump. This specifier requires a precision or width to be + specified. A precision (``%.*pHX``) takes precedence, but generates a + compiler warning since precisions are undefined for ``%p`` in ISO C. If + no precision is given, the width is used instead (and normal handling of + the width is suppressed). + + Note that width and precision are ``int`` arguments, not ``size_t``. Use + like:: + + char *buf; + size_t len; + + snprintfrr(out, sizeof(out), "... %*pHX ...", (int)len, buf); + + /* with padding to width - would generate a warning due to %.*p */ + FMT_NSTD(snprintfrr(out, sizeof(out), "... %-47.*pHX ...", (int)len, buf)); + +.. frrfmt:: %*pHS (void *, char *, unsigned char *) + + ``%pHS``: :frrfmtout:`hex.dump` + + This is a complementary format for :frrfmt:`%*pHX` to print the text + representation for a hexdump. Non-printable characters are replaced with + a dot. + +Integer formats +^^^^^^^^^^^^^^^ + +.. note:: + + These formats currently only exist for advanced type checking with the + ``frr-format`` GCC plugin. They should not be used directly since they will + cause compiler warnings when used without the plugin. Use with + :c:macro:`FMT_NSTD` if necessary. + + It is possible ISO C23 may introduce another format for these, possibly + ``%w64d`` discussed in `JTC 1/SC 22/WG 14/N2680 <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2680.pdf>`_. + +.. frrfmt:: %Lu (uint64_t) + + :frrfmtout:`12345` + +.. frrfmt:: %Ld (int64_t) + + :frrfmtout:`-12345` Log levels ---------- diff --git a/doc/developer/memtypes.rst b/doc/developer/memtypes.rst index 952b316ea0..08dad7fb68 100644 --- a/doc/developer/memtypes.rst +++ b/doc/developer/memtypes.rst @@ -15,15 +15,15 @@ Example: .. code-block:: c :caption: mydaemon.h - DECLARE_MGROUP(MYDAEMON) - DECLARE_MTYPE(MYNEIGHBOR) + DECLARE_MGROUP(MYDAEMON); + DECLARE_MTYPE(MYNEIGHBOR); .. code-block:: c :caption: mydaemon.c - DEFINE_MGROUP( MYDAEMON, "My daemon's memory") - DEFINE_MTYPE( MYDAEMON, MYNEIGHBOR, "Neighbor entry") - DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name") + DEFINE_MGROUP( MYDAEMON, "My daemon's memory"); + DEFINE_MTYPE( MYDAEMON, MYNEIGHBOR, "Neighbor entry"); + DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name"); struct neigh *neighbor_new(const char *name) { diff --git a/doc/developer/modules.rst b/doc/developer/modules.rst index 02330ddfe4..e95f8a1b4a 100644 --- a/doc/developer/modules.rst +++ b/doc/developer/modules.rst @@ -76,7 +76,7 @@ Basic boilerplate: .version = "0.0", .description = "my module", .init = module_init, - ) + ); The ``frr_late_init`` hook will be called after the daemon has finished its other startup and is about to enter the main event loop; this is the diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index 7976a206f7..2a6d2dda34 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -60,6 +60,7 @@ following steps will get you there on Ubuntu 20.04. .. code:: shell + apt install libsnmp-dev apt install snmpd snmp apt install snmp-mibs-downloader download-mibs @@ -232,6 +233,85 @@ for ``master`` branch: and create ``frr`` user and ``frrvty`` group as shown above. +Debugging Topotest Failures +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For the below debugging options which launch programs, if the topotest is run +within screen_ or tmux_, ``gdb``, the shell or ``vtysh`` will be launched using +that windowing program, otherwise mininet's ``xterm`` functionality will be used +to launch the given program. + +If you wish to force the use of ``xterm`` rather than ``tmux`` or ``screen``, or +wish to use ``gnome-terminal`` instead of ``xterm``, set the environment +variable ``FRR_TOPO_TERMINAL`` to either ``xterm`` or ``gnome-terminal``. + +.. _screen: https://www.gnu.org/software/screen/ +.. _tmux: https://github.com/tmux/tmux/wiki + +Spawning ``vtysh`` or Shells on Routers +""""""""""""""""""""""""""""""""""""""" + +Topotest can automatically launch a shell or ``vtysh`` for any or all routers in +a test. This is enabled by specifying 1 of 2 CLI arguments ``--shell`` or +``--vtysh``. Both of these options can be set to a single router value, multiple +comma-seperated values, or ``all``. + +When either of these options are specified topotest will pause after each test +to allow for inspection of the router state. + +Here's an example of launching ``vtysh`` on routers ``rt1`` and ``rt2``. + +.. code:: shell + + pytest --vtysh=rt1,rt2 all-protocol-startup + +Spawning Mininet CLI, ``vtysh`` or Shells on Routers on Test Failure +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Similar to the previous section one can have ``vtysh`` or a shell launched on +routers, but in this case only when a test fails. To launch the given process on +each router after a test failure specify one of ``--shell-on-error`` or +``--vtysh-on-error``. + + +Here's an example of having ``vtysh`` launched on test failure. + +.. code:: shell + + pytest --vtysh-on-error all-protocol-startup + + +Additionally, one can have the mininet CLI invoked on test failures by +specifying the ``--mininet-on-error`` CLI option as shown in the example below. + +.. code:: shell + + pytest --mininet-on-error all-protocol-startup + +Debugging with GDB +"""""""""""""""""" + +Topotest can automatically launch any daemon with ``gdb``, possibly setting +breakpoints for any test run. This is enabled by specifying 1 or 2 CLI arguments +``--gdb-routers`` and ``--gdb-daemons``. Additionally ``--gdb-breakpoints`` can +be used to automatically set breakpoints in the launched ``gdb`` processes. + +Each of these options can be set to a single value, multiple comma-seperated +values, or ``all``. If ``--gdb-routers`` is empty but ``--gdb_daemons`` is set +then the given daemons will be launched in ``gdb`` on all routers in the test. +Likewise if ``--gdb_routers`` is set, but ``--gdb_daemons`` is empty then all +daemons on the given routers will be launched in ``gdb``. + +Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router +``r1`` with a breakpoint set on ``nb_config_diff`` + +.. code:: shell + + pytest --gdb-routers=r1 \ + --gdb-daemons=bgpd,zebra \ + --gdb-breakpoints=nb_config_diff \ + all-protocol-startup + .. _topotests_docker: Running Tests with Docker diff --git a/doc/developer/tracing.rst b/doc/developer/tracing.rst index ae4d621a8e..63b04585f1 100644 --- a/doc/developer/tracing.rst +++ b/doc/developer/tracing.rst @@ -396,7 +396,7 @@ modifying ``frr.service`` like so: --- a/frr.service +++ b/frr.service @@ -7,6 +7,7 @@ Before=network.target - OnFailure=heartbeat-failed@%n.service + OnFailure=heartbeat-failed@%n [Service] +Environment="LD_PRELOAD=liblttng-ust-fork.so" diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 7d136b183e..6f797f7cc1 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -313,6 +313,11 @@ The following commands are available inside the interface configuration node. a new neighbor is found a BFD peer is created to monitor the link status for fast convergence. +.. clicmd:: ip ospf bfd profile BFDPROF + + Same as command ``ip ospf bfd``, but applies the BFD profile to the sessions + it creates or that already exist. + .. _bfd-ospf6-peer-config: diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 3f8dafa09d..5118c12843 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -394,6 +394,13 @@ Route Selection other measures were taken to avoid these. The exact behaviour will be sensitive to the iBGP and reflection topology. +.. clicmd:: bgp bestpath peer-type multipath-relax + + This command specifies that BGP decision process should consider paths + from all peers for multipath computation. If this option is enabled, + paths learned from any of eBGP, iBGP, or confederation neighbors will + be multipath if they are otherwise considered equal cost. + .. _bgp-distance: Administrative Distance Metrics @@ -1087,6 +1094,9 @@ IPv6 Support be used in a setup with two upstreams where each of the upstreams should only receive either IPv4 or IPv6 annocuments. + Using the ``bgp default ipv6-unicast`` configuration, IPv6 unicast + address family is enabled by default for all new neighbors. + .. _bgp-route-aggregation: @@ -1353,6 +1363,15 @@ Defining Peers ``net.core.optmem_max`` to allow the kernel to allocate the necessary option memory. +.. clicmd:: bgp listen limit <1-65535> + + Define the maximum number of peers accepted for one BGP instance. This + limit is set to 100 by default. Increasing this value will really be + possible if more file descriptors are available in the BGP process. This + value is defined by the underlying system (ulimit value), and can be + overriden by `--limit-fds`. More information is available in chapter + (:ref:`common-invocation-options`). + .. clicmd:: coalesce-time (0-4294967295) The time in milliseconds that BGP will delay before deciding what peers @@ -1417,6 +1436,12 @@ Configuring Peers This command is deprecated and may be removed in a future release. Its use should be avoided. +.. clicmd:: neighbor PEER interface remote-as <internal|external|ASN> + + Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The + session will be established via IPv6 link locals. Use ``internal`` for iBGP + and ``external`` for eBGP sessions, or specify an ASN if you wish. + .. clicmd:: neighbor PEER next-hop-self [all] This command specifies an announced route's nexthop as being equivalent to @@ -1576,6 +1601,12 @@ Configuring Peers on by default or not. This command defaults to on and is not displayed. The `no bgp default ipv4-unicast` form of the command is displayed. +.. clicmd:: bgp default ipv6-unicast + + This command allows the user to specify that v6 peering is turned + on by default or not. This command defaults to off and is not displayed. + The `bgp default ipv6-unicast` form of the command is displayed. + .. clicmd:: bgp default show-hostname This command shows the hostname of the peer in certain BGP commands @@ -2907,6 +2938,12 @@ Debugging Display Listen sockets and the vrf that created them. Useful for debugging of when listen is not working and this is considered a developer debug statement. +.. clicmd:: debug bgp bfd + + Enable or disable debugging for BFD events. This will show BFD integration + library messages and BGP BFD integration messages that are mostly state + transitions and validation problems. + .. clicmd:: debug bgp neighbor-events Enable or disable debugging for neighbor events. This provides general @@ -3138,17 +3175,15 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. .. clicmd:: show bgp [afi] [safi] [all] [wide|json] -.. clicmd:: show bgp <ipv4|ipv6> <unicast|multicast|vpn|labeled-unicast> +.. clicmd:: show bgp [<ipv4|ipv6> <unicast|multicast|vpn|labeled-unicast|flowspec> | l2vpn evpn] These commands display BGP routes for the specific routing table indicated by the selected afi and the selected safi. If no afi and no safi value is given, the command falls back to the default IPv6 routing table. - For EVPN prefixes, you can display the full BGP table for this AFI/SAFI - using the standard `show bgp [afi] [safi]` syntax. .. clicmd:: show bgp l2vpn evpn route [type <macip|2|multicast|3|es|4|prefix|5>] - Additionally, you can also filter this output by route type. + EVPN prefixes can also be filtered by EVPN route type. .. clicmd:: show bgp [afi] [safi] [all] summary [json] @@ -3165,11 +3200,21 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. Show a bgp peer summary for peers that are succesfully exchanging routes for the specified address family, and subsequent address-family. -.. clicmd:: show bgp [afi] [safi] neighbor [PEER] +.. clicmd:: show bgp [afi] [safi] [neighbor [PEER] [routes|advertised-routes|received-routes] [json] This command shows information on a specific BGP peer of the relevant afi and safi selected. + The ``routes`` keyword displays only routes in this address-family's BGP + table that were received by this peer and accepted by inbound policy. + + The ``advertised-routes`` keyword displays only the routes in this + address-family's BGP table that were permitted by outbound policy and + advertised to to this peer. + + The ``received-routes`` keyword displays all routes belonging to this + address-family (prior to inbound policy) that were received by this peer. + .. clicmd:: show bgp [afi] [safi] [all] dampening dampened-paths [wide|json] Display paths suppressed due to dampening of the selected afi and safi @@ -3331,6 +3376,25 @@ Displaying Routes by AS Path Print a summary of neighbor connections for the specified AFI/SAFI combination. +Displaying Routes by Route Distinguisher +---------------------------------------- + +.. clicmd:: show bgp [<ipv4|ipv6> vpn | l2vpn evpn [route]] rd <all|RD> + + For L3VPN and EVPN address-families, routes can be displayed on a per-RD + (Route Distinguisher) basis or for all RD's. + +.. clicmd:: show bgp l2vpn evpn rd <all|RD> [overlay | tags] + + Use the ``overlay`` or ``tags`` keywords to display the overlay/tag + information about the EVPN prefixes in the selected Route Distinguisher. + +.. clicmd:: show bgp l2vpn evpn route rd <all|RD> mac <MAC> [ip <MAC>] [json] + + For EVPN Type 2 (macip) routes, a MAC address (and optionally an IP address) + can be supplied to the command to only display matching prefixes in the + specified RD. + Displaying Update Group Information ----------------------------------- diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 00571487d7..17251e11ac 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -139,6 +139,12 @@ Redistribute routes to OSPF6 Redistribute routes from other protocols into OSPFv3. +.. index:: default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}] +.. clicmd:: default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}] + + The command injects default route in the connected areas. The always + argument injects the default route regardless of it being present in the + router. Metric values and route-map can also be specified optionally. .. _showing-ospf6-information: @@ -229,7 +235,6 @@ Showing OSPF6 information Interface name can also be given. JSON output can be obtained by appending 'json' to the end of command. -.. index:: show ipv6 ospf6 spf tree [json] .. clicmd:: show ipv6 ospf6 spf tree [json] This commands shows the spf tree from the recent spf calculation with the @@ -237,7 +242,7 @@ Showing OSPF6 information tree in JSON format. Each area that the router belongs to has it's own JSON object, with each router having "cost", "isLeafNode" and "children" as arguments. - + OSPF6 Configuration Examples ============================ diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 8689bc4ccb..85b6007f36 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -299,6 +299,16 @@ To start OSPF process you have to specify the OSPF router. command can be used when the neighbor state get stuck at some state and this can be used to recover it from that state. +.. index:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) +.. clicmd:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) + +.. index:: maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM) +.. clicmd:: no maximum-paths + + CLI to control maximum number of equal cost paths to reach a specific + destination.(ECMP) + Reset CLI, resets the maximum supported multi path to the default value. + .. _ospf-area: Areas @@ -390,6 +400,27 @@ Areas Prevents an *ospfd* ABR from injecting inter-area summaries into the specified stub area. +.. clicmd:: area A.B.C.D nssa + +.. clicmd:: area (0-4294967295) nssa + + Configure the area to be a NSSA (Not-So-Stubby Area). This is an area that + allows OSPF to import external routes into a stub area via a new LSA type + (type 7). An NSSA autonomous system boundary router (ASBR) will generate this + type of LSA. The area border router (ABR) translates the LSA type 7 into LSA + type 5, which is propagated into the OSPF domain. NSSA areas are defined in + RFC 3101. + +.. clicmd:: area A.B.C.D nssa suppress-fa + +.. clicmd:: area (0-4294967295) nssa suppress-fa + + Configure the router to set the forwarding address to 0.0.0.0 in all LSA type 5 + translated from LSA type 7. The router needs to be elected the translator of the + area for this command to take effect. This feature causes routers that are + configured not to advertise forwarding addresses into the backbone to direct + forwarded traffic to the NSSA ABR translator. + .. clicmd:: area A.B.C.D default-cost (0-16777215) @@ -733,23 +764,25 @@ Showing Information Json o/p of this command covers base route information i.e all LSAs except opaque lsa info. -.. clicmd:: show ip ospf database [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database [json] + +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) self-originate [json] -.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) self-originate [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database max-age [json] -.. clicmd:: show ip ospf database max-age [json] +.. clicmd:: show ip ospf [vrf <NAME|all>] database self-originate [json] -.. clicmd:: show ip ospf database self-originate [json] + Show the OSPF database summary. .. clicmd:: show ip ospf route [json] @@ -780,17 +813,17 @@ Opaque LSA extensions that are used with MPLS-TE; it does not support a complete RSVP-TE solution. -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate -.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate +.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) self-originate Show Opaque LSA from the database. @@ -823,6 +856,13 @@ Traffic Engineering flood in AREA <area-id> with Opaque Type-10, respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6. +.. index:: mpls-te export +.. clicmd:: no mpls-te export + + Export Traffic Engineering Data Base to other daemons through the ZAPI + Opaque Link State messages. + +.. index:: show ip ospf mpls-te interface .. clicmd:: show ip ospf mpls-te interface .. clicmd:: show ip ospf mpls-te interface INTERFACE @@ -833,6 +873,20 @@ Traffic Engineering Show Traffic Engineering router parameters. +.. index:: show ip ospf mpls-te database [verbose|json] +.. clicmd:: show ip ospf mpls-te database [verbose|json] + +.. index:: show ip ospf mpls-te database vertex [self-originate|adv-router ADV-ROUTER] [verbose|json] +.. clicmd:: show ip ospf mpls-te database vertex [self-originate|adv-router ADV-ROUTER] [verbose|json] + +.. index:: show ip ospf mpls-te database edge [A.B.C.D] [verbose|json] +.. clicmd:: show ip ospf mpls-te database edge [A.B.C.D] [verbose|json] + +.. index:: show ip ospf mpls-te database subnet [A.B.C.D/M] [verbose|json] +.. clicmd:: show ip ospf mpls-te database subnet [A.B.C.D/M] [verbose|json] + + Show Traffic Engineering Database + .. _router-information: Router Information @@ -966,6 +1020,12 @@ TI-LFA requires a proper Segment Routing configuration. Debugging OSPF ============== +.. clicmd:: debug ospf bfd + + Enable or disable debugging for BFD events. This will show BFD integration + library messages and OSPF BFD integration messages that are mostly state + transitions and validation problems. + .. clicmd:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index 01705f607c..d496d437d3 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -206,6 +206,14 @@ Displaying RPKI Display all configured cache servers, whether active or not. +.. clicmd:: show bgp [afi] [safi] <A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> rpki <valid|invalid|notfound> + + Display for the specified prefix or address the bgp paths that match the given rpki state. + +.. clicmd:: show bgp [afi] [safi] rpki <valid|invalid|notfound> + + Display all prefixes that match the given rpki state. + RPKI Configuration Example -------------------------- diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 9e83e44222..bef2748afa 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -131,3 +131,15 @@ keyword. At present, no sharp commands will be preserved in the config. Send an ARP/NDP request to trigger the addition of a neighbor in the ARP table. + +.. clicmd:: sharp import-te + + Import Traffic Engineering Database produce by OSPF or IS-IS. + +.. clicmd:: show sharp ted [verbose|json] + +.. clicmd:: show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json] + + Show imported Traffic Engineering Data Base + + diff --git a/eigrpd/eigrp_filter.c b/eigrpd/eigrp_filter.c index c77a6fc1b1..8f80b78d20 100644 --- a/eigrpd/eigrp_filter.c +++ b/eigrpd/eigrp_filter.c @@ -57,7 +57,6 @@ #include "eigrpd/eigrp_const.h" #include "eigrpd/eigrp_filter.h" #include "eigrpd/eigrp_packet.h" -#include "eigrpd/eigrp_memory.h" /* * Distribute-list update functions. diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index bb7a930e6d..02e943043f 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -52,12 +52,14 @@ #include "eigrpd/eigrp_vty.h" #include "eigrpd/eigrp_network.h" #include "eigrpd/eigrp_topology.h" -#include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_fsm.h" #include "eigrpd/eigrp_dump.h" #include "eigrpd/eigrp_types.h" #include "eigrpd/eigrp_metric.h" +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF, "EIGRP interface"); +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information"); + struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp, struct prefix *p) { diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index b1a6498cbc..0ed7e94968 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -155,7 +155,8 @@ FRR_DAEMON_INFO(eigrpd, EIGRP, .vty_port = EIGRP_VTY_PORT, .n_signals = array_size(eigrp_signals), .privs = &eigrpd_privs, .yang_modules = eigrpd_yang_modules, - .n_yang_modules = array_size(eigrpd_yang_modules), ) + .n_yang_modules = array_size(eigrpd_yang_modules), +); /* EIGRPd main routine. */ int main(int argc, char **argv, char **envp) diff --git a/eigrpd/eigrp_memory.c b/eigrpd/eigrp_memory.c deleted file mode 100644 index 57ca785340..0000000000 --- a/eigrpd/eigrp_memory.c +++ /dev/null @@ -1,42 +0,0 @@ -/* eigrpd memory type definitions - * - * Copyright (C) 2017 Donald Sharp - * - * This file is part of FRR - * - * FRR 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, or (at your option) any - * later version. - * - * FRR 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 - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "eigrp_memory.h" - -DEFINE_MGROUP(EIGRPD, "eigrpd") -DEFINE_MTYPE(EIGRPD, EIGRP_TOP, "EIGRP structure") -DEFINE_MTYPE(EIGRPD, EIGRP_IF, "EIGRP interface") -DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor") -DEFINE_MTYPE(EIGRPD, EIGRP_IF_PARAMS, "EIGRP Interface Parameters") -DEFINE_MTYPE(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information") -DEFINE_MTYPE(EIGRPD, EIGRP_FIFO, "EIGRP FIFO") -DEFINE_MTYPE(EIGRPD, EIGRP_PACKET, "EIGRP Packet") -DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV") -DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV") -DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV") -DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV") -DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix") -DEFINE_MTYPE(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry") -DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message") diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c index 1da2f7a108..f2d5217eb0 100644 --- a/eigrpd/eigrp_neighbor.c +++ b/eigrpd/eigrp_neighbor.c @@ -52,9 +52,10 @@ #include "eigrpd/eigrp_vty.h" #include "eigrpd/eigrp_network.h" #include "eigrpd/eigrp_topology.h" -#include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_errors.h" +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor"); + struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *ei) { struct eigrp_neighbor *nbr; diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c index 7eee254627..0b37733990 100644 --- a/eigrpd/eigrp_packet.c +++ b/eigrpd/eigrp_packet.c @@ -56,9 +56,15 @@ #include "eigrpd/eigrp_network.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" -#include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_errors.h" +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_FIFO, "EIGRP FIFO"); +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_PACKET, "EIGRP Packet"); +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV"); +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV"); +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV"); +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV"); + /* Packet Type String. */ const struct message eigrp_packet_type_str[] = { {EIGRP_OPC_UPDATE, "Update"}, diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c index 0ab7b59dbb..c8769fb11f 100644 --- a/eigrpd/eigrp_query.c +++ b/eigrpd/eigrp_query.c @@ -52,7 +52,6 @@ #include "eigrpd/eigrp_macros.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" -#include "eigrpd/eigrp_memory.h" uint32_t eigrp_query_send_all(struct eigrp *eigrp) { diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c index d16482173c..015daa768f 100644 --- a/eigrpd/eigrp_reply.c +++ b/eigrpd/eigrp_reply.c @@ -58,7 +58,6 @@ #include "eigrpd/eigrp_macros.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" -#include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_errors.h" void eigrp_send_reply(struct eigrp_neighbor *nbr, diff --git a/eigrpd/eigrp_siaquery.c b/eigrpd/eigrp_siaquery.c index 027700fe11..9c2a8c9d84 100644 --- a/eigrpd/eigrp_siaquery.c +++ b/eigrpd/eigrp_siaquery.c @@ -52,7 +52,6 @@ #include "eigrpd/eigrp_macros.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" -#include "eigrpd/eigrp_memory.h" /*EIGRP SIA-QUERY read function*/ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph, diff --git a/eigrpd/eigrp_siareply.c b/eigrpd/eigrp_siareply.c index 590b224d68..2d298c20bf 100644 --- a/eigrpd/eigrp_siareply.c +++ b/eigrpd/eigrp_siareply.c @@ -51,7 +51,6 @@ #include "eigrpd/eigrp_macros.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" -#include "eigrpd/eigrp_memory.h" /*EIGRP SIA-REPLY read function*/ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph, diff --git a/eigrpd/eigrp_snmp.c b/eigrpd/eigrp_snmp.c index 3b232be386..9ada292feb 100644 --- a/eigrpd/eigrp_snmp.c +++ b/eigrpd/eigrp_snmp.c @@ -588,8 +588,7 @@ static struct eigrp_neighbor *eigrpNbrLookup(struct variable *v, oid *name, if (nbr) { *length = v->namelen + IN_ADDR_SIZE + 1; - oid_copy_addr(name + v->namelen, nbr_addr, - IN_ADDR_SIZE); + oid_copy_in_addr(name + v->namelen, nbr_addr); name[v->namelen + IN_ADDR_SIZE] = *ifindex; return nbr; } diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index 0d8bb29964..eb4a91cb64 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -126,9 +126,9 @@ struct eigrp { /* distribute_ctx */ struct distribute_ctx *distribute_ctx; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(eigrp) +DECLARE_QOBJ_TYPE(eigrp); struct eigrp_if_params { uint8_t passive_interface; diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index 6da7756f84..846e211622 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -51,9 +51,11 @@ #include "eigrpd/eigrp_dump.h" #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" -#include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_metric.h" +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry"); +DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix"); + static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *rd1, struct eigrp_route_descriptor *rd2); diff --git a/eigrpd/eigrp_topology.h b/eigrpd/eigrp_topology.h index 26fa1a11b0..d7f79057ab 100644 --- a/eigrpd/eigrp_topology.h +++ b/eigrpd/eigrp_topology.h @@ -32,6 +32,10 @@ #ifndef _ZEBRA_EIGRP_TOPOLOGY_H #define _ZEBRA_EIGRP_TOPOLOGY_H +#include "memory.h" + +DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR); + /* EIGRP Topology table related functions. */ extern struct route_table *eigrp_topology_new(void); extern void eigrp_topology_init(struct route_table *table); diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c index 91f3b3218b..0dc509706c 100644 --- a/eigrpd/eigrp_update.c +++ b/eigrpd/eigrp_update.c @@ -62,7 +62,6 @@ #include "eigrpd/eigrp_topology.h" #include "eigrpd/eigrp_fsm.h" #include "eigrpd/eigrp_network.h" -#include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_metric.h" bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei, diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c index 5002630796..1030154907 100644 --- a/eigrpd/eigrpd.c +++ b/eigrpd/eigrpd.c @@ -55,10 +55,13 @@ #include "eigrpd/eigrp_packet.h" #include "eigrpd/eigrp_network.h" #include "eigrpd/eigrp_topology.h" -#include "eigrpd/eigrp_memory.h" #include "eigrpd/eigrp_filter.h" -DEFINE_QOBJ_TYPE(eigrp) +DEFINE_MGROUP(EIGRPD, "eigrpd"); + +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_TOP, "EIGRP structure"); + +DEFINE_QOBJ_TYPE(eigrp); static struct eigrp_master eigrp_master; diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h index 01173768ba..949fe682c7 100644 --- a/eigrpd/eigrpd.h +++ b/eigrpd/eigrpd.h @@ -32,6 +32,9 @@ #include "filter.h" #include "log.h" +#include "memory.h" + +DECLARE_MGROUP(EIGRPD); /* Set EIGRP version is "classic" - wide metrics comes next */ #define EIGRP_MAJOR_VERSION 1 diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index 13c9f7f8ae..ba9445acb9 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -24,7 +24,6 @@ eigrpd_libeigrp_a_SOURCES = \ eigrpd/eigrp_fsm.c \ eigrpd/eigrp_hello.c \ eigrpd/eigrp_interface.c \ - eigrpd/eigrp_memory.c \ eigrpd/eigrp_metric.c \ eigrpd/eigrp_neighbor.c \ eigrpd/eigrp_network.c \ @@ -63,7 +62,6 @@ noinst_HEADERS += \ eigrpd/eigrp_fsm.h \ eigrpd/eigrp_interface.h \ eigrpd/eigrp_macros.h \ - eigrpd/eigrp_memory.h \ eigrpd/eigrp_metric.h \ eigrpd/eigrp_neighbor.h \ eigrpd/eigrp_network.h \ diff --git a/isisd/fabricd.c b/isisd/fabricd.c index 57e9e91c15..20651706d3 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -22,7 +22,6 @@ #include <zebra.h> #include "isisd/fabricd.h" #include "isisd/isisd.h" -#include "isisd/isis_memory.h" #include "isisd/isis_circuit.h" #include "isisd/isis_misc.h" #include "isisd/isis_adjacency.h" @@ -33,9 +32,9 @@ #include "isisd/isis_tx_queue.h" #include "isisd/isis_csm.h" -DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric") -DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry") -DEFINE_MTYPE_STATIC(ISISD, FABRICD_FLOODING_INFO, "ISIS OpenFabric Flooding Log") +DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric"); +DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry"); +DEFINE_MTYPE_STATIC(ISISD, FABRICD_FLOODING_INFO, "ISIS OpenFabric Flooding Log"); /* Tracks initial synchronization as per section 2.4 * diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index 3c3a68764e..c1f5e49eca 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -49,6 +49,9 @@ #include "isisd/fabricd.h" #include "isisd/isis_nb.h" +DEFINE_MTYPE_STATIC(ISISD, ISIS_ADJACENCY, "ISIS adjacency"); +DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info"); + static struct isis_adjacency *adj_alloc(struct isis_circuit *circuit, const uint8_t *id) { @@ -146,7 +149,7 @@ struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level, return NULL; } -DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)) +DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)); void isis_delete_adj(void *arg) { @@ -260,22 +263,26 @@ void isis_adj_process_threeway(struct isis_adjacency *adj, adj->threeway_state = next_tw_state; } -void isis_log_adj_change(struct isis_adjacency *adj, - enum isis_adj_state old_state, - enum isis_adj_state new_state, const char *reason) +const char *isis_adj_name(const struct isis_adjacency *adj) { - const char *adj_name; + if (!adj) + return "NONE"; + struct isis_dynhn *dyn; dyn = dynhn_find_by_id(adj->sysid); if (dyn) - adj_name = dyn->hostname; + return dyn->hostname; else - adj_name = sysid_print(adj->sysid); - + return sysid_print(adj->sysid); +} +void isis_log_adj_change(struct isis_adjacency *adj, + enum isis_adj_state old_state, + enum isis_adj_state new_state, const char *reason) +{ zlog_info( "%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s", - adj_name, adj->circuit->interface->name, + isis_adj_name(adj), adj->circuit->interface->name, adj_level2string(adj->level), adj_state2string(old_state), adj_state2string(new_state), reason ? reason : "unspecified"); } @@ -462,11 +469,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, struct isis_dynhn *dyn; int level; - dyn = dynhn_find_by_id(adj->sysid); - if (dyn) - vty_out(vty, " %-20s", dyn->hostname); - else - vty_out(vty, " %-20s", sysid_print(adj->sysid)); + vty_out(vty, " %-20s", isis_adj_name(adj)); if (detail == ISIS_UI_LEVEL_BRIEF) { if (adj->circuit) diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index 3afb7209f3..754345c008 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -27,6 +27,8 @@ #include "isisd/isis_tlvs.h" +DECLARE_MTYPE(ISIS_ADJACENCY_INFO); + enum isis_adj_usage { ISIS_ADJ_NONE, ISIS_ADJ_LEVEL1, @@ -123,11 +125,11 @@ void isis_delete_adj(void *adj); void isis_adj_process_threeway(struct isis_adjacency *adj, struct isis_threeway_adj *tw_adj, enum isis_adj_usage adj_usage); -DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)) +DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj)); DECLARE_HOOK(isis_adj_ip_enabled_hook, - (struct isis_adjacency *adj, int family), (adj, family)) + (struct isis_adjacency *adj, int family), (adj, family)); DECLARE_HOOK(isis_adj_ip_disabled_hook, - (struct isis_adjacency *adj, int family), (adj, family)) + (struct isis_adjacency *adj, int family), (adj, family)); void isis_log_adj_change(struct isis_adjacency *adj, enum isis_adj_state old_state, enum isis_adj_state new_state, const char *reason); @@ -142,5 +144,6 @@ void isis_adj_build_neigh_list(struct list *adjdb, struct list *list); void isis_adj_build_up_list(struct list *adjdb, struct list *list); int isis_adj_usage2levels(enum isis_adj_usage usage); int isis_bfd_startup_timer(struct thread *thread); +const char *isis_adj_name(const struct isis_adjacency *adj); #endif /* ISIS_ADJACENCY_H */ diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index 4fac73511b..89f1ed0ba3 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -32,7 +32,7 @@ #include "isisd/isisd.h" #include "isisd/fabricd.h" -DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session") +DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session"); struct bfd_session { int family; @@ -92,22 +92,42 @@ static bool bfd_session_same(const struct bfd_session *session, int family, static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst, int new_status) { - if (!adj->bfd_session) + if (!adj->bfd_session) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: Ignoring update for adjacency with %s, could not find bfd session on the adjacency", + isis_adj_name(adj)); return; + } - if (adj->bfd_session->family != dst->family) + if (adj->bfd_session->family != dst->family) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: Ignoring update for adjacency with %s, address family does not match the family on the adjacency", + isis_adj_name(adj)); return; + } switch (adj->bfd_session->family) { case AF_INET: if (!IPV4_ADDR_SAME(&adj->bfd_session->dst_ip.ipv4, - &dst->u.prefix4)) + &dst->u.prefix4)) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: Ignoring update for adjacency with %s, IPv4 address does not match", + isis_adj_name(adj)); return; + } break; case AF_INET6: if (!IPV6_ADDR_SAME(&adj->bfd_session->dst_ip.ipv6, - &dst->u.prefix6)) + &dst->u.prefix6)) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: Ignoring update for adjacency with %s, IPv6 address does not match", + isis_adj_name(adj)); return; + } break; default: flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u", @@ -119,8 +139,13 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst, BFD_SET_CLIENT_STATUS(adj->bfd_session->status, new_status); - if (old_status == new_status) + if (old_status == new_status) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: Ignoring update for adjacency with %s, new status matches current known status", + isis_adj_name(adj)); return; + } if (IS_DEBUG_BFD) { char dst_str[INET6_ADDRSTRLEN]; @@ -166,8 +191,12 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) struct isis_circuit *circuit = circuit_scan_by_ifp(ifp); - if (!circuit) + if (!circuit) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: Ignoring update, could not find circuit"); return 0; + } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { @@ -326,15 +355,26 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) struct list *local_ips; struct prefix *local_ip; - if (!circuit->bfd_info) + if (!circuit->bfd_info) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: skipping BFD initialization on adjacency with %s because there is no bfd_info in the circuit", + isis_adj_name(adj)); goto out; + } /* If IS-IS IPv6 is configured wait for IPv6 address to be programmed * before starting up BFD */ - if ((circuit->ipv6_router && listcount(circuit->ipv6_link) == 0) - || adj->ipv6_address_count == 0) + if (circuit->ipv6_router + && (listcount(circuit->ipv6_link) == 0 + || adj->ipv6_address_count == 0)) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready", + isis_adj_name(adj)); return; + } /* * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer @@ -344,16 +384,24 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) family = AF_INET6; dst_ip.ipv6 = adj->ipv6_addresses[0]; local_ips = circuit->ipv6_link; - if (!local_ips || list_isempty(local_ips)) + if (!local_ips || list_isempty(local_ips)) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses"); goto out; + } local_ip = listgetdata(listhead(local_ips)); src_ip.ipv6 = local_ip->u.prefix6; } else if (circuit->ip_router && adj->ipv4_address_count) { family = AF_INET; dst_ip.ipv4 = adj->ipv4_addresses[0]; local_ips = fabricd_ip_addrs(adj->circuit); - if (!local_ips || list_isempty(local_ips)) + if (!local_ips || list_isempty(local_ips)) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: skipping BFD initialization: IPv4 enabled and no local IPv4 addresses"); goto out; + } local_ip = listgetdata(listhead(local_ips)); src_ip.ipv4 = local_ip->u.prefix4; } else @@ -365,8 +413,13 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command) bfd_handle_adj_down(adj); } - if (!adj->bfd_session) + if (!adj->bfd_session) { + if (IS_DEBUG_BFD) + zlog_debug( + "ISIS-BFD: creating BFD session for adjacency with %s", + isis_adj_name(adj)); adj->bfd_session = bfd_session_new(family, &dst_ip, &src_ip); + } bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip, &adj->bfd_session->src_ip, circuit->interface->name, command); diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 62822cbf89..a637429e84 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -61,9 +61,11 @@ #include "isisd/isis_nb.h" #include "isisd/isis_ldp_sync.h" -DEFINE_QOBJ_TYPE(isis_circuit) +DEFINE_MTYPE_STATIC(ISISD, ISIS_CIRCUIT, "ISIS circuit"); -DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)) +DEFINE_QOBJ_TYPE(isis_circuit); + +DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)); /* * Prototypes. @@ -308,7 +310,7 @@ struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp) } DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit), - (circuit)) + (circuit)); void isis_circuit_add_addr(struct isis_circuit *circuit, struct connected *connected) @@ -1085,7 +1087,7 @@ void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty, #ifdef FABRICD DEFINE_HOOK(isis_circuit_config_write, (struct isis_circuit *circuit, struct vty *vty), - (circuit, vty)) + (circuit, vty)); static int isis_interface_config_write(struct vty *vty) { diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index 15d58bd736..cbe4040b64 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -174,9 +174,9 @@ struct isis_circuit { */ struct list *snmp_adj_list; /* List in id order */ - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(isis_circuit) +DECLARE_QOBJ_TYPE(isis_circuit); void isis_circuit_init(void); struct isis_circuit *isis_circuit_new(struct isis *isis); @@ -231,10 +231,10 @@ int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid, #ifdef FABRICD DECLARE_HOOK(isis_circuit_config_write, (struct isis_circuit *circuit, struct vty *vty), - (circuit, vty)) + (circuit, vty)); #endif DECLARE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit), - (circuit)) + (circuit)); #endif /* _ZEBRA_ISIS_CIRCUIT_H */ diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index fb9721e8b3..b108210686 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -136,10 +136,10 @@ void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode, vrf = yang_dnode_get_string(dnode, "./vrf"); vty_out(vty, "!\n"); - vty_out(vty, "router isis %s ", + vty_out(vty, "router isis %s", yang_dnode_get_string(dnode, "./area-tag")); if (!strmatch(vrf, VRF_DEFAULT_NAME)) - vty_out(vty, "vrf %s", yang_dnode_get_string(dnode, "./vrf")); + vty_out(vty, " vrf %s", yang_dnode_get_string(dnode, "./vrf")); vty_out(vty, "\n"); } @@ -392,10 +392,10 @@ void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode, if (!yang_dnode_get_bool(dnode, NULL)) vty_out(vty, " no"); - vty_out(vty, " ip router isis %s ", + vty_out(vty, " ip router isis %s", yang_dnode_get_string(dnode, "../area-tag")); if (!strmatch(vrf, VRF_DEFAULT_NAME)) - vty_out(vty, "vrf %s", vrf); + vty_out(vty, " vrf %s", vrf); vty_out(vty, "\n"); } @@ -408,10 +408,10 @@ void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode, if (!yang_dnode_get_bool(dnode, NULL)) vty_out(vty, " no"); - vty_out(vty, " ipv6 router isis %s ", + vty_out(vty, " ipv6 router isis %s", yang_dnode_get_string(dnode, "../area-tag")); if (!strmatch(vrf, VRF_DEFAULT_NAME)) - vty_out(vty, "vrf %s", vrf); + vty_out(vty, " vrf %s", vrf); vty_out(vty, "\n"); } diff --git a/isisd/isis_dynhn.c b/isisd/isis_dynhn.c index d2c5d93e25..decd3e8922 100644 --- a/isisd/isis_dynhn.c +++ b/isisd/isis_dynhn.c @@ -40,6 +40,8 @@ #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" +DEFINE_MTYPE_STATIC(ISISD, ISIS_DYNHN, "ISIS dyn hostname"); + extern struct host host; struct list *dyn_cache = NULL; diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index 3ebac8aaa9..085177b943 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -46,6 +46,7 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_NODE, "ISIS SPF Node"); DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_TIEBREAKER, "ISIS LFA Tiebreaker"); DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_EXCL_IFACE, "ISIS LFA Excluded Interface"); DEFINE_MTYPE_STATIC(ISISD, ISIS_RLFA, "ISIS Remote LFA"); +DEFINE_MTYPE(ISISD, ISIS_NEXTHOP_LABELS, "ISIS nexthop MPLS labels"); static inline int isis_spf_node_compare(const struct isis_spf_node *a, const struct isis_spf_node *b) diff --git a/isisd/isis_lfa.h b/isisd/isis_lfa.h index 65891cae44..9db03a3a19 100644 --- a/isisd/isis_lfa.h +++ b/isisd/isis_lfa.h @@ -22,9 +22,12 @@ #include "lib/typesafe.h" #include "lib/zclient.h" +#include "lib/memory.h" -PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree) -PREDECL_RBTREE_UNIQ(rlfa_tree) +DECLARE_MTYPE(ISIS_NEXTHOP_LABELS); + +PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree); +PREDECL_RBTREE_UNIQ(rlfa_tree); enum lfa_tiebreaker_type { LFA_TIEBREAKER_DOWNSTREAM = 0, @@ -41,7 +44,7 @@ struct lfa_tiebreaker { int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a, const struct lfa_tiebreaker *b); DECLARE_RBTREE_UNIQ(lfa_tiebreaker_tree, struct lfa_tiebreaker, entry, - lfa_tiebreaker_cmp) + lfa_tiebreaker_cmp); struct rlfa { struct rlfa_tree_item entry; @@ -50,7 +53,7 @@ struct rlfa { struct in_addr pq_address; }; int rlfa_cmp(const struct rlfa *a, const struct rlfa *b); -DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp) +DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp); enum isis_tilfa_sid_type { TILFA_SID_PREFIX = 1, diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 06a5a69e3f..056e29e8de 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -60,6 +60,8 @@ #include "isisd/isis_tx_queue.h" #include "isisd/isis_nb.h" +DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP"); + static int lsp_refresh(struct thread *thread); static int lsp_l1_refresh_pseudo(struct thread *thread); static int lsp_l2_refresh_pseudo(struct thread *thread); @@ -1561,18 +1563,28 @@ int _lsp_regenerate_schedule(struct isis_area *area, int level, /* * Schedule LSP refresh ASAP */ - timeout = 0; - if (area->bfd_signalled_down) { sched_debug( - "ISIS (%s): Scheduling immediately due to BDF 'down' message.", + "ISIS (%s): Scheduling immediately due to BFD 'down' message.", area->area_tag); area->bfd_signalled_down = false; area->bfd_force_spf_refresh = true; + timeout = 0; } else { - sched_debug( - "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.", - area->area_tag); + int64_t time_since_last = monotime_since( + &area->last_lsp_refresh_event[lvl - 1], + NULL); + timeout = time_since_last < 100000L + ? (100000L - time_since_last)/1000 + : 0; + if (timeout > 0) + sched_debug( + "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.", + area->area_tag, timeout); + else + sched_debug( + "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.", + area->area_tag); } } diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 896d957607..f3d9f61bcf 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -27,7 +27,7 @@ #include "lib/typesafe.h" #include "isisd/isis_pdu.h" -PREDECL_RBTREE_UNIQ(lspdb) +PREDECL_RBTREE_UNIQ(lspdb); struct isis; /* Structure for isis_lsp, this structure will only support the fixed @@ -61,7 +61,7 @@ struct isis_lsp { }; extern int lspdb_compare(const struct isis_lsp *a, const struct isis_lsp *b); -DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare) +DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare); void lsp_db_init(struct lspdb_head *head); void lsp_db_fini(struct lspdb_head *head); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 1b04f4f7a0..c03cedb187 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -193,7 +193,8 @@ FRR_DAEMON_INFO(isisd, ISIS, .vty_port = ISISD_VTY_PORT, .n_signals = array_size(isisd_signals), .privs = &isisd_privs, .yang_modules = isisd_yang_modules, - .n_yang_modules = array_size(isisd_yang_modules), ) + .n_yang_modules = array_size(isisd_yang_modules), +); /* * Main routine of isisd. Parse arguments and handle IS-IS state machine. diff --git a/isisd/isis_memory.c b/isisd/isis_memory.c deleted file mode 100644 index f716e060cd..0000000000 --- a/isisd/isis_memory.c +++ /dev/null @@ -1,49 +0,0 @@ -/* isisd memory type definitions - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga 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, or (at your option) any - * later version. - * - * Quagga 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 - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "isis_memory.h" - -DEFINE_MGROUP(ISISD, "isisd") -DEFINE_MTYPE(ISISD, ISIS, "ISIS") -DEFINE_MTYPE(ISISD, ISIS_TMP, "ISIS TMP") -DEFINE_MTYPE(ISISD, ISIS_CIRCUIT, "ISIS circuit") -DEFINE_MTYPE(ISISD, ISIS_LSP, "ISIS LSP") -DEFINE_MTYPE(ISISD, ISIS_ADJACENCY, "ISIS adjacency") -DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info") -DEFINE_MTYPE(ISISD, ISIS_AREA, "ISIS area") -DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address") -DEFINE_MTYPE(ISISD, ISIS_DYNHN, "ISIS dyn hostname") -DEFINE_MTYPE(ISISD, ISIS_SPFTREE, "ISIS SPFtree") -DEFINE_MTYPE(ISISD, ISIS_VERTEX, "ISIS vertex") -DEFINE_MTYPE(ISISD, ISIS_ROUTE_INFO, "ISIS route info") -DEFINE_MTYPE(ISISD, ISIS_NEXTHOP, "ISIS nexthop") -DEFINE_MTYPE(ISISD, ISIS_NEXTHOP_LABELS, "ISIS nexthop MPLS labels") -DEFINE_MTYPE(ISISD, ISIS_DICT, "ISIS dictionary") -DEFINE_MTYPE(ISISD, ISIS_DICT_NODE, "ISIS dictionary node") -DEFINE_MTYPE(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route") -DEFINE_MTYPE(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info") -DEFINE_MTYPE(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters") -DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name") -DEFINE_MTYPE(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name") diff --git a/isisd/isis_memory.h b/isisd/isis_memory.h deleted file mode 100644 index 5bcd2a3983..0000000000 --- a/isisd/isis_memory.h +++ /dev/null @@ -1,50 +0,0 @@ -/* isisd memory type declarations - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga 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, or (at your option) any - * later version. - * - * Quagga 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 _QUAGGA_ISIS_MEMORY_H -#define _QUAGGA_ISIS_MEMORY_H - -#include "memory.h" - -DECLARE_MGROUP(ISISD) -DECLARE_MTYPE(ISIS) -DECLARE_MTYPE(ISIS_TMP) -DECLARE_MTYPE(ISIS_CIRCUIT) -DECLARE_MTYPE(ISIS_LSP) -DECLARE_MTYPE(ISIS_ADJACENCY) -DECLARE_MTYPE(ISIS_ADJACENCY_INFO) -DECLARE_MTYPE(ISIS_AREA) -DECLARE_MTYPE(ISIS_AREA_ADDR) -DECLARE_MTYPE(ISIS_DYNHN) -DECLARE_MTYPE(ISIS_SPFTREE) -DECLARE_MTYPE(ISIS_VERTEX) -DECLARE_MTYPE(ISIS_ROUTE_INFO) -DECLARE_MTYPE(ISIS_NEXTHOP) -DECLARE_MTYPE(ISIS_NEXTHOP_LABELS) -DECLARE_MTYPE(ISIS_DICT) -DECLARE_MTYPE(ISIS_DICT_NODE) -DECLARE_MTYPE(ISIS_EXT_ROUTE) -DECLARE_MTYPE(ISIS_EXT_INFO) -DECLARE_MTYPE(ISIS_MPLS_TE) -DECLARE_MTYPE(ISIS_ACL_NAME) -DECLARE_MTYPE(ISIS_PLIST_NAME) - -#endif /* _QUAGGA_ISIS_MEMORY_H */ diff --git a/isisd/isis_mt.c b/isisd/isis_mt.c index 9465c5e75c..c024549fcc 100644 --- a/isisd/isis_mt.c +++ b/isisd/isis_mt.c @@ -21,7 +21,6 @@ */ #include <zebra.h> #include "isisd/isisd.h" -#include "isisd/isis_memory.h" #include "isisd/isis_circuit.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_misc.h" @@ -29,9 +28,9 @@ #include "isisd/isis_mt.h" #include "isisd/isis_tlvs.h" -DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting") -DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting") -DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info") +DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting"); +DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting"); +DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info"); bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area) { diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index f0663c691c..c8ad816b58 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -48,12 +48,14 @@ #include "isisd/isis_spf.h" #include "isisd/isis_spf_private.h" #include "isisd/isis_te.h" -#include "isisd/isis_memory.h" #include "isisd/isis_mt.h" #include "isisd/isis_redist.h" #include "isisd/isis_ldp_sync.h" #include "isisd/isis_dr.h" +DEFINE_MTYPE_STATIC(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name"); + extern struct zclient *zclient; /* @@ -131,7 +133,7 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args) switch (args->event) { case NB_EV_VALIDATE: - area = nb_running_get_entry(args->dnode, NULL, true); + area = nb_running_get_entry(args->dnode, NULL, false); if (area == NULL) return NB_ERR_VALIDATION; addr.addr_len = dotformat2buff(buff, net_title); diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c index 856c47b9b7..c33d56e625 100644 --- a/isisd/isis_redist.c +++ b/isisd/isis_redist.c @@ -24,7 +24,6 @@ #include "if.h" #include "linklist.h" #include "memory.h" -#include "isis_memory.h" #include "prefix.h" #include "routemap.h" #include "stream.h" @@ -42,6 +41,10 @@ #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" +DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_RMAP_NAME, "ISIS redistribute route-map name"); + static int redist_protocol(int family) { if (family == AF_INET) @@ -327,13 +330,13 @@ static void isis_redist_routemap_set(struct isis_redist *redist, const char *routemap) { if (redist->map_name) { - XFREE(MTYPE_ISIS, redist->map_name); + XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name); route_map_counter_decrement(redist->map); redist->map = NULL; } if (routemap && strlen(routemap)) { - redist->map_name = XSTRDUP(MTYPE_ISIS, routemap); + redist->map_name = XSTRDUP(MTYPE_ISIS_RMAP_NAME, routemap); redist->map = route_map_lookup_by_name(routemap); route_map_counter_increment(redist->map); } @@ -507,7 +510,7 @@ void isis_redist_area_finish(struct isis_area *area) redist = &area->redist_settings[protocol][type] [level]; redist->redist = 0; - XFREE(MTYPE_ISIS, redist->map_name); + XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name); } route_table_finish(area->ext_reach[protocol][level]); } diff --git a/isisd/isis_route.c b/isisd/isis_route.c index e1baf351f4..eb534a543a 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -50,10 +50,13 @@ #include "isis_route.h" #include "isis_zebra.h" +DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP, "ISIS nexthop"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_INFO, "ISIS route info"); + DEFINE_HOOK(isis_route_update_hook, (struct isis_area * area, struct prefix *prefix, struct isis_route_info *route_info), - (area, prefix, route_info)) + (area, prefix, route_info)); static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family, union g_addr *ip, ifindex_t ifindex); diff --git a/isisd/isis_route.h b/isisd/isis_route.h index d6763ec76c..0e206d08f4 100644 --- a/isisd/isis_route.h +++ b/isisd/isis_route.h @@ -52,7 +52,7 @@ struct isis_route_info { DECLARE_HOOK(isis_route_update_hook, (struct isis_area * area, struct prefix *prefix, struct isis_route_info *route_info), - (area, prefix, route_info)) + (area, prefix, route_info)); void isis_nexthop_delete(struct isis_nexthop *nexthop); void adjinfo2nexthop(int family, struct list *nexthops, diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c index 50dc0f2a1c..fe6a2f4052 100644 --- a/isisd/isis_snmp.c +++ b/isisd/isis_snmp.c @@ -1037,6 +1037,8 @@ static int isis_snmp_circuit_level_lookup_next( break; } + assert(oid_idx != NULL); + /* We have to check level specified by index */ if (oid_idx[1] < IS_LEVEL_1) { level = IS_LEVEL_1; @@ -3452,6 +3454,9 @@ static int isis_snmp_module_init(void) return 0; } -FRR_MODULE_SETUP(.name = "isis_snmp", .version = FRR_VERSION, - .description = "isis AgentX SNMP module", - .init = isis_snmp_module_init, ) +FRR_MODULE_SETUP( + .name = "isis_snmp", + .version = FRR_VERSION, + .description = "isis AgentX SNMP module", + .init = isis_snmp_module_init, +); diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 7bcc6fea90..3e8ec8817e 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -60,8 +60,10 @@ #include "fabricd.h" #include "isis_spf_private.h" -DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info"); -DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_SPFTREE, "ISIS SPFtree"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX, "ISIS vertex"); DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX_ADJ, "ISIS SPF Vertex Adjacency"); static void spf_adj_list_parse_lsp(struct isis_spftree *spftree, @@ -248,6 +250,20 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree, return vertex; } +void isis_vertex_del(struct isis_vertex *vertex) +{ + list_delete(&vertex->Adj_N); + list_delete(&vertex->parents); + if (vertex->firsthops) { + hash_clean(vertex->firsthops, NULL); + hash_free(vertex->firsthops); + vertex->firsthops = NULL; + } + + memset(vertex, 0, sizeof(struct isis_vertex)); + XFREE(MTYPE_ISIS_VERTEX, vertex); +} + struct isis_vertex_adj * isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex, struct list *vadj_list, struct isis_spf_adj *sadj, diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h index 79dfa3e164..07d4ff5a0e 100644 --- a/isisd/isis_spf_private.h +++ b/isisd/isis_spf_private.h @@ -179,20 +179,7 @@ static void isis_vertex_queue_init(struct isis_vertex_queue *queue, isis_vertex_queue_hash_cmp, name); } -__attribute__((__unused__)) -static void isis_vertex_del(struct isis_vertex *vertex) -{ - list_delete(&vertex->Adj_N); - list_delete(&vertex->parents); - if (vertex->firsthops) { - hash_clean(vertex->firsthops, NULL); - hash_free(vertex->firsthops); - vertex->firsthops = NULL; - } - - memset(vertex, 0, sizeof(struct isis_vertex)); - XFREE(MTYPE_ISIS_VERTEX, vertex); -} +void isis_vertex_del(struct isis_vertex *vertex); bool isis_vertex_adj_exists(const struct isis_spftree *spftree, const struct isis_vertex *vertex, diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index 21f534641c..c4024772f5 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -49,7 +49,7 @@ #include "isisd/isis_errors.h" /* Local variables and functions */ -DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information") +DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information"); static void sr_local_block_delete(struct isis_area *area); static int sr_local_block_init(struct isis_area *area); @@ -73,7 +73,7 @@ static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg *a, return prefix_cmp(&a->prefix, &b->prefix); } DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry, - sr_prefix_sid_cfg_compare) + sr_prefix_sid_cfg_compare); /** * Find SRGB associated to a System ID. diff --git a/isisd/isis_sr.h b/isisd/isis_sr.h index b012dfb00a..a933f366eb 100644 --- a/isisd/isis_sr.h +++ b/isisd/isis_sr.h @@ -57,7 +57,7 @@ #define SRLB_UPPER_BOUND 15999 /* Segment Routing Data Base (SRDB) RB-Tree structure */ -PREDECL_RBTREE_UNIQ(srdb_prefix_cfg) +PREDECL_RBTREE_UNIQ(srdb_prefix_cfg); /* * Segment Routing Prefix-SID information. diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index a97c19a8bc..2bac8e7fd5 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -33,7 +33,6 @@ #include "network.h" #include "isisd/isisd.h" -#include "isisd/isis_memory.h" #include "isisd/isis_tlvs.h" #include "isisd/isis_common.h" #include "isisd/isis_mt.h" @@ -45,14 +44,15 @@ #include "isisd/isis_te.h" #include "isisd/isis_sr.h" -DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs") -DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs") -DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists") +DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs"); +DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists"); typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type, uint8_t tlv_len, struct stream *s, struct sbuf *log, void *dest, int indent); -typedef int (*pack_item_func)(struct isis_item *item, struct stream *s); +typedef int (*pack_item_func)(struct isis_item *item, struct stream *s, + size_t *min_length); typedef void (*free_item_func)(struct isis_item *i); typedef int (*unpack_item_func)(uint16_t mtid, uint8_t len, struct stream *s, struct sbuf *log, void *dest, int indent); @@ -368,12 +368,14 @@ static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts) } static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts, - struct stream *s) + struct stream *s, size_t *min_len) { uint8_t size; - if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE) + if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE) { + *min_len = ISIS_SUBTLV_MAX_SIZE; return 1; + } if (IS_SUBTLV(exts, EXT_ADM_GRP)) { stream_putc(s, ISIS_SUBTLV_ADMIN_GRP); @@ -829,14 +831,17 @@ static void free_item_prefix_sid(struct isis_item *i) XFREE(MTYPE_ISIS_SUBTLV, i); } -static int pack_item_prefix_sid(struct isis_item *i, struct stream *s) +static int pack_item_prefix_sid(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i; uint8_t size = (sid->flags & ISIS_PREFIX_SID_VALUE) ? 5 : 6; - if (STREAM_WRITEABLE(s) < size) + if (STREAM_WRITEABLE(s) < size) { + *min_len = size; return 1; + } stream_putc(s, sid->flags); stream_putc(s, sid->algorithm); @@ -1121,12 +1126,15 @@ static void free_item_area_address(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_area_address(struct isis_item *i, struct stream *s) +static int pack_item_area_address(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_area_address *addr = (struct isis_area_address *)i; - if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len) + if (STREAM_WRITEABLE(s) < (unsigned)1 + addr->len) { + *min_len = (unsigned)1 + addr->len; return 1; + } stream_putc(s, addr->len); stream_put(s, addr->addr, addr->len); return 0; @@ -1200,12 +1208,15 @@ static void free_item_oldstyle_reach(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s) +static int pack_item_oldstyle_reach(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_oldstyle_reach *r = (struct isis_oldstyle_reach *)i; - if (STREAM_WRITEABLE(s) < 11) + if (STREAM_WRITEABLE(s) < 11) { + *min_len = 11; return 1; + } stream_putc(s, r->metric); stream_putc(s, 0x80); /* delay metric - unsupported */ @@ -1269,12 +1280,15 @@ static void free_item_lan_neighbor(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s) +static int pack_item_lan_neighbor(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_lan_neighbor *n = (struct isis_lan_neighbor *)i; - if (STREAM_WRITEABLE(s) < 6) + if (STREAM_WRITEABLE(s) < 6) { + *min_len = 6; return 1; + } stream_put(s, n->mac, 6); @@ -1334,12 +1348,15 @@ static void free_item_lsp_entry(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_lsp_entry(struct isis_item *i, struct stream *s) +static int pack_item_lsp_entry(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_lsp_entry *e = (struct isis_lsp_entry *)i; - if (STREAM_WRITEABLE(s) < 16) + if (STREAM_WRITEABLE(s) < 16) { + *min_len = 16; return 1; + } stream_putw(s, e->rem_lifetime); stream_put(s, e->id, 8); @@ -1414,14 +1431,17 @@ static void free_item_extended_reach(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, item); } -static int pack_item_extended_reach(struct isis_item *i, struct stream *s) +static int pack_item_extended_reach(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_extended_reach *r = (struct isis_extended_reach *)i; size_t len; size_t len_pos; - if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE) + if (STREAM_WRITEABLE(s) < 11 + ISIS_SUBTLV_MAX_SIZE) { + *min_len = 11 + ISIS_SUBTLV_MAX_SIZE; return 1; + } stream_put(s, r->id, sizeof(r->id)); stream_put3(s, r->metric); @@ -1429,7 +1449,7 @@ static int pack_item_extended_reach(struct isis_item *i, struct stream *s) /* Real length will be adjust after adding subTLVs */ stream_putc(s, 11); if (r->subtlvs) - pack_item_ext_subtlvs(r->subtlvs, s); + pack_item_ext_subtlvs(r->subtlvs, s, min_len); /* Adjust length */ len = stream_get_endp(s) - len_pos - 1; stream_putc_at(s, len_pos, len); @@ -1522,12 +1542,15 @@ static void free_item_oldstyle_ip_reach(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s) +static int pack_item_oldstyle_ip_reach(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_oldstyle_ip_reach *r = (struct isis_oldstyle_ip_reach *)i; - if (STREAM_WRITEABLE(s) < 12) + if (STREAM_WRITEABLE(s) < 12) { + *min_len = 12; return 1; + } stream_putc(s, r->metric); stream_putc(s, 0x80); /* delay metric - unsupported */ @@ -1677,12 +1700,15 @@ static void free_item_ipv4_address(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_ipv4_address(struct isis_item *i, struct stream *s) +static int pack_item_ipv4_address(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_ipv4_address *a = (struct isis_ipv4_address *)i; - if (STREAM_WRITEABLE(s) < 4) + if (STREAM_WRITEABLE(s) < 4) { + *min_len = 4; return 1; + } stream_put(s, &a->addr, 4); @@ -1738,12 +1764,15 @@ static void free_item_ipv6_address(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_ipv6_address(struct isis_item *i, struct stream *s) +static int pack_item_ipv6_address(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_ipv6_address *a = (struct isis_ipv6_address *)i; - if (STREAM_WRITEABLE(s) < 16) + if (STREAM_WRITEABLE(s) < 16) { + *min_len = 16; return 1; + } stream_put(s, &a->addr, 16); @@ -1802,12 +1831,15 @@ static void free_item_mt_router_info(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_mt_router_info(struct isis_item *i, struct stream *s) +static int pack_item_mt_router_info(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_mt_router_info *info = (struct isis_mt_router_info *)i; - if (STREAM_WRITEABLE(s) < 2) + if (STREAM_WRITEABLE(s) < 2) { + *min_len = 2; return 1; + } uint16_t entry = info->mtid; @@ -1962,13 +1994,16 @@ static void free_item_extended_ip_reach(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, item); } -static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s) +static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_extended_ip_reach *r = (struct isis_extended_ip_reach *)i; uint8_t control; - if (STREAM_WRITEABLE(s) < 5) + if (STREAM_WRITEABLE(s) < 5) { + *min_len = 5; return 1; + } stream_putl(s, r->metric); control = r->down ? ISIS_EXTENDED_IP_REACH_DOWN : 0; @@ -1977,8 +2012,10 @@ static int pack_item_extended_ip_reach(struct isis_item *i, struct stream *s) stream_putc(s, control); - if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen)) + if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen)) { + *min_len = 5 + (unsigned)PSIZE(r->prefix.prefixlen); return 1; + } stream_put(s, &r->prefix.prefix.s_addr, PSIZE(r->prefix.prefixlen)); if (r->subtlvs) @@ -2444,13 +2481,16 @@ static void free_item_ipv6_reach(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, item); } -static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s) +static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_ipv6_reach *r = (struct isis_ipv6_reach *)i; uint8_t control; - if (STREAM_WRITEABLE(s) < 6) + if (STREAM_WRITEABLE(s) < 6 + (unsigned)PSIZE(r->prefix.prefixlen)) { + *min_len = 6 + (unsigned)PSIZE(r->prefix.prefixlen); return 1; + } stream_putl(s, r->metric); control = r->down ? ISIS_IPV6_REACH_DOWN : 0; @@ -2460,8 +2500,6 @@ static int pack_item_ipv6_reach(struct isis_item *i, struct stream *s) stream_putc(s, control); stream_putc(s, r->prefix.prefixlen); - if (STREAM_WRITEABLE(s) < (unsigned)PSIZE(r->prefix.prefixlen)) - return 1; stream_put(s, &r->prefix.prefix.s6_addr, PSIZE(r->prefix.prefixlen)); if (r->subtlvs) @@ -2909,23 +2947,30 @@ static void free_item_auth(struct isis_item *i) XFREE(MTYPE_ISIS_TLV, i); } -static int pack_item_auth(struct isis_item *i, struct stream *s) +static int pack_item_auth(struct isis_item *i, struct stream *s, + size_t *min_len) { struct isis_auth *auth = (struct isis_auth *)i; - if (STREAM_WRITEABLE(s) < 1) + if (STREAM_WRITEABLE(s) < 1) { + *min_len = 1; return 1; + } stream_putc(s, auth->type); switch (auth->type) { case ISIS_PASSWD_TYPE_CLEARTXT: - if (STREAM_WRITEABLE(s) < auth->length) + if (STREAM_WRITEABLE(s) < auth->length) { + *min_len = 1 + auth->length; return 1; + } stream_put(s, auth->passwd, auth->length); break; case ISIS_PASSWD_TYPE_HMAC_MD5: - if (STREAM_WRITEABLE(s) < 16) + if (STREAM_WRITEABLE(s) < 16) { + *min_len = 1 + 16; return 1; + } auth->offset = stream_get_endp(s); stream_put(s, NULL, 16); break; @@ -3160,14 +3205,14 @@ static void free_items(enum isis_tlv_context context, enum isis_tlv_type type, } static int pack_item(enum isis_tlv_context context, enum isis_tlv_type type, - struct isis_item *i, struct stream *s, + struct isis_item *i, struct stream *s, size_t *min_len, struct isis_tlvs **fragment_tlvs, const struct pack_order_entry *pe, uint16_t mtid) { const struct tlv_ops *ops = tlv_table[context][type]; if (ops && ops->pack_item) { - return ops->pack_item(i, s); + return ops->pack_item(i, s, min_len); } assert(!"Unknown item tlv type!"); @@ -3201,6 +3246,7 @@ static int pack_items_(uint16_t mtid, enum isis_tlv_context context, size_t len_pos, last_len, len; struct isis_item *item = NULL; int rv; + size_t min_len = 0; if (!items->head) return 0; @@ -3228,7 +3274,8 @@ top: last_len = len = 0; for (item = item ? item : items->head; item; item = item->next) { - rv = pack_item(context, type, item, s, fragment_tlvs, pe, mtid); + rv = pack_item(context, type, item, s, &min_len, fragment_tlvs, + pe, mtid); if (rv) goto too_long; @@ -3272,6 +3319,8 @@ too_long: if (!fragment_tlvs) return 1; stream_reset(s); + if (STREAM_WRITEABLE(s) < min_len) + return 1; *fragment_tlvs = new_fragment(new_fragment_arg); goto top; } @@ -4488,9 +4537,9 @@ static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs, } DEFINE_HOOK(isis_adj_ip_enabled_hook, (struct isis_adjacency *adj, int family), - (adj, family)) + (adj, family)); DEFINE_HOOK(isis_adj_ip_disabled_hook, - (struct isis_adjacency *adj, int family), (adj, family)) + (struct isis_adjacency *adj, int family), (adj, family)); static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj, diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h index 037f91f0b8..0438d13ae0 100644 --- a/isisd/isis_tlvs.h +++ b/isisd/isis_tlvs.h @@ -28,7 +28,7 @@ #include "openbsd-tree.h" #include "prefix.h" -DECLARE_MTYPE(ISIS_SUBTLV) +DECLARE_MTYPE(ISIS_SUBTLV); struct lspdb_head; struct isis_subtlvs; diff --git a/isisd/isis_tx_queue.c b/isisd/isis_tx_queue.c index 5c87e39157..c7266152b7 100644 --- a/isisd/isis_tx_queue.c +++ b/isisd/isis_tx_queue.c @@ -25,15 +25,14 @@ #include "jhash.h" #include "isisd/isisd.h" -#include "isisd/isis_memory.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_lsp.h" #include "isisd/isis_misc.h" #include "isisd/isis_tx_queue.h" -DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue") -DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry") +DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue"); +DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry"); struct isis_tx_queue { struct isis_circuit *circuit; diff --git a/isisd/isisd.c b/isisd/isisd.c index 487a902c06..714961c177 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -81,7 +81,15 @@ unsigned long debug_sr; unsigned long debug_ldp_sync; unsigned long debug_lfa; -DEFINE_QOBJ_TYPE(isis_area) +DEFINE_MGROUP(ISISD, "isisd"); + +DEFINE_MTYPE_STATIC(ISISD, ISIS, "ISIS process"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_NAME, "ISIS process name"); +DEFINE_MTYPE_STATIC(ISISD, ISIS_AREA, "ISIS area"); +DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address"); +DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name"); + +DEFINE_QOBJ_TYPE(isis_area); /* ISIS process wide configuration. */ static struct isis_master isis_master; @@ -198,10 +206,10 @@ struct isis *isis_new(const char *vrf_name) if (vrf) { isis->vrf_id = vrf->vrf_id; isis_vrf_link(isis, vrf); - isis->name = XSTRDUP(MTYPE_ISIS, vrf->name); + isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf->name); } else { isis->vrf_id = VRF_UNKNOWN; - isis->name = XSTRDUP(MTYPE_ISIS, vrf_name); + isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf_name); } if (IS_DEBUG_EVENTS) @@ -565,7 +573,7 @@ static int isis_vrf_enable(struct vrf *vrf) isis = isis_lookup_by_vrfname(vrf->name); if (isis) { if (isis->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) { - XFREE(MTYPE_ISIS, isis->name); + XFREE(MTYPE_ISIS_NAME, isis->name); isis->name = NULL; } old_vrf_id = isis->vrf_id; @@ -631,7 +639,7 @@ void isis_finish(struct isis *isis) vrf = vrf_lookup_by_name(isis->name); if (vrf) isis_vrf_unlink(isis, vrf); - XFREE(MTYPE_ISIS, isis->name); + XFREE(MTYPE_ISIS_NAME, isis->name); } else { vrf = vrf_lookup_by_id(VRF_DEFAULT); if (vrf) diff --git a/isisd/isisd.h b/isisd/isisd.h index 1b0ec2b4f0..a2e821ad2f 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -24,6 +24,7 @@ #define ISISD_H #include "vty.h" +#include "memory.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" @@ -34,10 +35,11 @@ #include "isis_flags.h" #include "isis_lsp.h" #include "isis_lfa.h" -#include "isis_memory.h" #include "qobj.h" #include "ldp_sync.h" +DECLARE_MGROUP(ISISD); + #ifdef FABRICD static const bool fabricd = true; #define PROTO_TYPE ZEBRA_ROUTE_OPENFABRIC @@ -236,11 +238,14 @@ struct isis_area { uint64_t id_len_mismatches[2]; uint64_t lsp_error_counter[2]; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(isis_area) +DECLARE_QOBJ_TYPE(isis_area); + +DECLARE_MTYPE(ISIS_ACL_NAME); /* isis_area->spf_prefix_prioritites */ +DECLARE_MTYPE(ISIS_AREA_ADDR); /* isis_area->area_addrs */ -DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area)) +DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area)); void isis_terminate(void); void isis_finish(struct isis *isis); diff --git a/isisd/subdir.am b/isisd/subdir.am index 98674a6881..4cefe6e10b 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -57,7 +57,6 @@ noinst_HEADERS += \ isisd/isis_ldp_sync.h \ isisd/isis_lfa.h \ isisd/isis_lsp.h \ - isisd/isis_memory.h \ isisd/isis_misc.h \ isisd/isis_mt.h \ isisd/isis_nb.h \ @@ -92,7 +91,6 @@ LIBISIS_SOURCES = \ isisd/isis_ldp_sync.c \ isisd/isis_lfa.c \ isisd/isis_lsp.c \ - isisd/isis_memory.c \ isisd/isis_misc.c \ isisd/isis_mt.c \ isisd/isis_pdu.c \ @@ -142,7 +140,7 @@ nodist_isisd_isisd_SOURCES = \ # end isisd_isisd_snmp_la_SOURCES = isisd/isis_snmp.c -isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 isisd_isisd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic isisd_isisd_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/ldpd/ldp_snmp.c b/ldpd/ldp_snmp.c index 97dde616a7..9fb4e46515 100644 --- a/ldpd/ldp_snmp.c +++ b/ldpd/ldp_snmp.c @@ -301,8 +301,7 @@ static uint8_t *ldpEntityTable(struct variable *v, oid name[], size_t *length, /* Append index */ *length = LDP_ENTITY_TOTAL_LEN; - oid_copy_addr(name + v->namelen, &entityLdpId, - IN_ADDR_SIZE); + oid_copy_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX; @@ -402,8 +401,7 @@ static uint8_t *ldpEntityStatsTable(struct variable *v, oid name[], /* Append index */ *length = LDP_ENTITY_TOTAL_LEN; - oid_copy_addr(name + v->namelen, &entityLdpId, - IN_ADDR_SIZE); + oid_copy_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX; @@ -640,13 +638,11 @@ static uint8_t *ldpHelloAdjacencyTable(struct variable *v, oid name[], size_t *l struct in_addr peerLdpId = ctl_adj->id; - oid_copy_addr(name + v->namelen, &entityLdpId, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX; - oid_copy_addr(name + v->namelen + 7, &peerLdpId, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen + 7, &peerLdpId); name[v->namelen + 11] = 0; name[v->namelen + 12] = 0; name[v->namelen + 13] = adjacencyIndex; @@ -804,14 +800,12 @@ static uint8_t *ldpPeerTable(struct variable *v, oid name[], size_t *length, memcpy(name, v->name, v->namelen * sizeof(oid)); /* Append index */ - oid_copy_addr(name + v->namelen, &entityLdpId, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = entityIndex; - oid_copy_addr(name + v->namelen + 7, &peerLdpId, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen + 7, &peerLdpId); name[v->namelen + 11] = 0; name[v->namelen + 12] = 0; @@ -875,14 +869,12 @@ static uint8_t *ldpSessionTable(struct variable *v, oid name[], size_t *length, memcpy(name, v->name, v->namelen * sizeof(oid)); /* Append index */ - oid_copy_addr(name + v->namelen, &entityLdpId, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = entityIndex; - oid_copy_addr(name + v->namelen + 7, &peerLdpId, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen + 7, &peerLdpId); name[v->namelen + 11] = 0; name[v->namelen + 12] = 0; @@ -961,13 +953,11 @@ static uint8_t *ldpSessionStatsTable(struct variable *v, oid name[], memcpy(name, v->name, v->namelen * sizeof(oid)); /* Append index */ - oid_copy_addr(name + v->namelen, &entityLdpId, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, &entityLdpId); name[v->namelen + 4] = 0; name[v->namelen + 5] = 0; name[v->namelen + 6] = entityIndex; - oid_copy_addr(name + v->namelen + 7, &peerLdpId, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen + 7, &peerLdpId); name[v->namelen + 11] = 0; name[v->namelen + 12] = 0; @@ -1147,15 +1137,15 @@ ldpTrapSession(struct nbr * nbr, unsigned int sptrap) entityIndex = LDP_DEFAULT_ENTITY_INDEX; peerLdpId = ctl_nbr->id; - oid_copy_addr(index, &entityLdpId, sizeof(struct in_addr)); - index[4] = 0; - index[5] = 0; - index[6] = entityIndex; - oid_copy_addr(&index[7], &peerLdpId, sizeof(struct in_addr)); - index[11] = 0; - index[12] = 0; + oid_copy_in_addr(index, &entityLdpId); + index[4] = 0; + index[5] = 0; + index[6] = entityIndex; + oid_copy_in_addr(&index[7], &peerLdpId); + index[11] = 0; + index[12] = 0; - index[LDP_PEER_ENTRY_MAX_IDX_LEN] = 0; + index[LDP_PEER_ENTRY_MAX_IDX_LEN] = 0; smux_trap(ldpe_variables, array_size(ldpe_variables), ldp_trap_oid, array_size(ldp_trap_oid), ldp_oid, @@ -1239,6 +1229,9 @@ static int ldp_snmp_module_init(void) return 0; } -FRR_MODULE_SETUP(.name = "ldp_snmp", .version = FRR_VERSION, - .description = "ldp AgentX SNMP module", - .init = ldp_snmp_module_init, ) +FRR_MODULE_SETUP( + .name = "ldp_snmp", + .version = FRR_VERSION, + .description = "ldp AgentX SNMP module", + .init = ldp_snmp_module_init, +); diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 14235a0f1f..d69a4dcd3c 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -69,13 +69,13 @@ static void merge_l2vpns(struct ldpd_conf *, struct ldpd_conf *); static void merge_l2vpn(struct ldpd_conf *, struct l2vpn *, struct l2vpn *); -DEFINE_QOBJ_TYPE(iface) -DEFINE_QOBJ_TYPE(tnbr) -DEFINE_QOBJ_TYPE(nbr_params) -DEFINE_QOBJ_TYPE(l2vpn_if) -DEFINE_QOBJ_TYPE(l2vpn_pw) -DEFINE_QOBJ_TYPE(l2vpn) -DEFINE_QOBJ_TYPE(ldpd_conf) +DEFINE_QOBJ_TYPE(iface); +DEFINE_QOBJ_TYPE(tnbr); +DEFINE_QOBJ_TYPE(nbr_params); +DEFINE_QOBJ_TYPE(l2vpn_if); +DEFINE_QOBJ_TYPE(l2vpn_pw); +DEFINE_QOBJ_TYPE(l2vpn); +DEFINE_QOBJ_TYPE(ldpd_conf); struct ldpd_global global; struct ldpd_init init; @@ -88,7 +88,7 @@ static pid_t lde_pid; static struct frr_daemon_info ldpd_di; -DEFINE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm)) +DEFINE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm)); static void ldp_load_module(const char *name) { @@ -218,7 +218,7 @@ FRR_DAEMON_INFO(ldpd, LDP, .yang_modules = ldpd_yang_modules, .n_yang_modules = array_size(ldpd_yang_modules), -) +); static int ldp_config_fork_apply(struct thread *t) { diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 73c81349ce..8fdc16fc7b 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -362,11 +362,11 @@ struct iface { struct iface_af ipv4; struct iface_af ipv6; struct iface_ldp_sync ldp_sync; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(iface_head, iface); RB_PROTOTYPE(iface_head, iface, entry, iface_compare); -DECLARE_QOBJ_TYPE(iface) +DECLARE_QOBJ_TYPE(iface); /* source of targeted hellos */ struct tnbr { @@ -379,11 +379,11 @@ struct tnbr { uint16_t pw_count; uint32_t rlfa_count; uint8_t flags; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(tnbr_head, tnbr); RB_PROTOTYPE(tnbr_head, tnbr, entry, tnbr_compare); -DECLARE_QOBJ_TYPE(tnbr) +DECLARE_QOBJ_TYPE(tnbr); #define F_TNBR_CONFIGURED 0x01 #define F_TNBR_DYNAMIC 0x02 @@ -405,11 +405,11 @@ struct nbr_params { uint8_t md5key_len; } auth; uint8_t flags; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(nbrp_head, nbr_params); RB_PROTOTYPE(nbrp_head, nbr_params, entry, nbr_params_compare); -DECLARE_QOBJ_TYPE(nbr_params) +DECLARE_QOBJ_TYPE(nbr_params); #define F_NBRP_KEEPALIVE 0x01 #define F_NBRP_GTSM 0x02 #define F_NBRP_GTSM_HOPS 0x04 @@ -463,11 +463,11 @@ struct l2vpn_if { ifindex_t ifindex; int operative; uint8_t mac[ETH_ALEN]; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(l2vpn_if_head, l2vpn_if); RB_PROTOTYPE(l2vpn_if_head, l2vpn_if, entry, l2vpn_if_compare); -DECLARE_QOBJ_TYPE(l2vpn_if) +DECLARE_QOBJ_TYPE(l2vpn_if); struct l2vpn_pw { RB_ENTRY(l2vpn_pw) entry; @@ -485,11 +485,11 @@ struct l2vpn_pw { uint32_t remote_status; uint8_t flags; uint8_t reason; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(l2vpn_pw_head, l2vpn_pw); RB_PROTOTYPE(l2vpn_pw_head, l2vpn_pw, entry, l2vpn_pw_compare); -DECLARE_QOBJ_TYPE(l2vpn_pw) +DECLARE_QOBJ_TYPE(l2vpn_pw); #define F_PW_STATUSTLV_CONF 0x01 /* status tlv configured */ #define F_PW_STATUSTLV 0x02 /* status tlv negotiated */ #define F_PW_CWORD_CONF 0x04 /* control word configured */ @@ -513,11 +513,11 @@ struct l2vpn { struct l2vpn_if_head if_tree; struct l2vpn_pw_head pw_tree; struct l2vpn_pw_head pw_inactive_tree; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(l2vpn_head, l2vpn); RB_PROTOTYPE(l2vpn_head, l2vpn, entry, l2vpn_compare); -DECLARE_QOBJ_TYPE(l2vpn) +DECLARE_QOBJ_TYPE(l2vpn); #define L2VPN_TYPE_VPWS 1 #define L2VPN_TYPE_VPLS 2 @@ -584,9 +584,9 @@ struct ldpd_conf { int flags; time_t config_change_time; struct ldp_entity_stats stats; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(ldpd_conf) +DECLARE_QOBJ_TYPE(ldpd_conf); #define F_LDPD_NO_FIB_UPDATE 0x0001 #define F_LDPD_DS_CISCO_INTEROP 0x0002 #define F_LDPD_ENABLED 0x0004 @@ -915,7 +915,7 @@ int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response * (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_INTFACELOCAL)) #endif -DECLARE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm)) +DECLARE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm)); extern void ldp_agentx_enabled(void); diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 9572f1ac12..880722424e 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -321,6 +321,7 @@ void ldpe_l2vpn_exit(struct l2vpn *); void ldpe_l2vpn_pw_init(struct l2vpn_pw *); void ldpe_l2vpn_pw_exit(struct l2vpn_pw *); -DECLARE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state)) +DECLARE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), + (nbr, old_state)); #endif /* _LDPE_H_ */ diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index 23c67ec1ca..e884b3ebfc 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -26,7 +26,8 @@ #include "lde.h" #include "log.h" -DEFINE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state)) +DEFINE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), + (nbr, old_state)); static __inline int nbr_id_compare(const struct nbr *, const struct nbr *); static __inline int nbr_addr_compare(const struct nbr *, diff --git a/ldpd/subdir.am b/ldpd/subdir.am index b01d414de8..aa9b751bcc 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -65,6 +65,6 @@ ldpd_ldpd_SOURCES = ldpd/ldpd.c ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP) ldpd_ldpd_snmp_la_SOURCES = ldpd/ldp_snmp.c -ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 ldpd_ldpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic ldpd_ldpd_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/lib/agentx.c b/lib/agentx.c index c1ff7a61b1..b5a035ee2b 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -34,9 +34,9 @@ #include "lib_errors.h" #include "xref.h" -XREF_SETUP() +XREF_SETUP(); -DEFINE_HOOK(agentx_enabled, (), ()) +DEFINE_HOOK(agentx_enabled, (), ()); static int agentx_enabled = 0; diff --git a/lib/atomlist.h b/lib/atomlist.h index 5ca19cbcd4..c795128a34 100644 --- a/lib/atomlist.h +++ b/lib/atomlist.h @@ -123,15 +123,16 @@ struct atomlist_head { /* use as: * - * PREDECL_ATOMLIST(namelist) + * PREDECL_ATOMLIST(namelist); * struct name { * struct namelist_item nlitem; * } - * DECLARE_ATOMLIST(namelist, struct name, nlitem) + * DECLARE_ATOMLIST(namelist, struct name, nlitem); */ #define PREDECL_ATOMLIST(prefix) \ struct prefix ## _head { struct atomlist_head ah; }; \ -struct prefix ## _item { struct atomlist_item ai; }; +struct prefix ## _item { struct atomlist_item ai; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_ATOMLIST(var) { } @@ -171,7 +172,7 @@ macro_inline void prefix ## _fini(struct prefix##_head *h) \ assert(prefix ## _count(h) == 0); \ memset(h, 0, sizeof(*h)); \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ /* add_head: * - contention on ->first pointer @@ -221,7 +222,8 @@ struct atomsort_head { #define _PREDECL_ATOMSORT(prefix) \ struct prefix ## _head { struct atomsort_head ah; }; \ -struct prefix ## _item { struct atomsort_item ai; }; +struct prefix ## _item { struct atomsort_item ai; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_ATOMSORT_UNIQ(var) { } #define INIT_ATOMSORT_NONUNIQ(var) { } @@ -298,7 +300,7 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ struct atomsort_item *p = atomsort_pop(&h->ah); \ return p ? container_of(p, type, field.ai) : NULL; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ #define PREDECL_ATOMSORT_UNIQ(prefix) \ _PREDECL_ATOMSORT(prefix) @@ -312,7 +314,7 @@ macro_inline int prefix ## __cmp(const struct atomsort_item *a, \ } \ \ _DECLARE_ATOMSORT(prefix, type, field, \ - prefix ## __cmp, prefix ## __cmp) \ + prefix ## __cmp, prefix ## __cmp); \ \ atomic_find_warn \ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \ @@ -325,7 +327,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \ return NULL; \ return p; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ #define PREDECL_ATOMSORT_NONUNIQ(prefix) \ _PREDECL_ATOMSORT(prefix) @@ -352,8 +354,8 @@ macro_inline int prefix ## __cmp_uq(const struct atomsort_item *a, \ } \ \ _DECLARE_ATOMSORT(prefix, type, field, \ - prefix ## __cmp, prefix ## __cmp_uq) \ -/* ... */ + prefix ## __cmp, prefix ## __cmp_uq); \ +MACRO_REQUIRE_SEMICOLON() /* end */ struct atomsort_item *atomsort_add(struct atomsort_head *h, struct atomsort_item *item, int (*cmpfn)( @@ -27,12 +27,13 @@ #include "prefix.h" #include "thread.h" #include "stream.h" +#include "vrf.h" #include "zclient.h" #include "table.h" #include "vty.h" #include "bfd.h" -DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info") +DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info"); static int bfd_debug = 0; static struct bfd_gbl bfd_gbl; @@ -568,3 +569,640 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) return 0; } + +/** + * BFD protocol integration configuration. + */ + +/** Events definitions. */ +enum bfd_session_event { + /** Remove the BFD session configuration. */ + BSE_UNINSTALL, + /** Install the BFD session configuration. */ + BSE_INSTALL, +}; + +/** + * Data structure to do the necessary tricks to hide the BFD protocol + * integration internals. + */ +struct bfd_session_params { + /** Contains the session parameters and more. */ + struct bfd_session_arg args; + /** Contains the session state. */ + struct bfd_session_status bss; + /** Protocol implementation status update callback. */ + bsp_status_update updatecb; + /** Protocol implementation custom data pointer. */ + void *arg; + + /** + * Next event. + * + * This variable controls what action to execute when the command batch + * finishes. Normally we'd use `thread_add_event` value, however since + * that function is going to be called multiple times and the value + * might be different we'll use this variable to keep track of it. + */ + enum bfd_session_event lastev; + /** + * BFD session configuration event. + * + * Multiple actions might be asked during a command batch (either via + * configuration load or northbound batch), so we'll use this to + * install/uninstall the BFD session parameters only once. + */ + struct thread *installev; + + /** BFD session installation state. */ + bool installed; + /** BFD session enabled. */ + bool enabled; + + /** Global BFD paramaters list. */ + TAILQ_ENTRY(bfd_session_params) entry; +}; + +struct bfd_sessions_global { + /** + * Global BFD session parameters list for (re)installation and update + * without code duplication among daemons. + */ + TAILQ_HEAD(bsplist, bfd_session_params) bsplist; + + /** Pointer to FRR's event manager. */ + struct thread_master *tm; + /** Pointer to zebra client data structure. */ + struct zclient *zc; + + /** Debugging state. */ + bool debugging; + /** Is shutting down? */ + bool shutting_down; +}; + +/** Global configuration variable. */ +static struct bfd_sessions_global bsglobal; + +/** Global empty address for IPv4/IPv6. */ +static const struct in6_addr i6a_zero; + +struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *arg) +{ + struct bfd_session_params *bsp; + + bsp = XCALLOC(MTYPE_BFD_INFO, sizeof(*bsp)); + + /* Save application data. */ + bsp->updatecb = updatecb; + bsp->arg = arg; + + /* Set defaults. */ + bsp->args.detection_multiplier = BFD_DEF_DETECT_MULT; + bsp->args.ttl = BFD_SINGLE_HOP_TTL; + bsp->args.min_rx = BFD_DEF_MIN_RX; + bsp->args.min_tx = BFD_DEF_MIN_TX; + bsp->args.vrf_id = VRF_DEFAULT; + + /* Register in global list. */ + TAILQ_INSERT_TAIL(&bsglobal.bsplist, bsp, entry); + + return bsp; +} + +static bool _bfd_sess_valid(const struct bfd_session_params *bsp) +{ + /* Peer/local address not configured. */ + if (bsp->args.family == 0) + return false; + + /* Address configured but invalid. */ + if (bsp->args.family != AF_INET && bsp->args.family != AF_INET6) { + if (bsglobal.debugging) + zlog_debug("%s: invalid session family: %d", __func__, + bsp->args.family); + return false; + } + + /* Invalid address. */ + if (memcmp(&bsp->args.dst, &i6a_zero, sizeof(i6a_zero)) == 0) { + if (bsglobal.debugging) { + if (bsp->args.family == AF_INET) + zlog_debug("%s: invalid address: %pI4", + __func__, + (struct in_addr *)&bsp->args.dst); + else + zlog_debug("%s: invalid address: %pI6", + __func__, &bsp->args.dst); + } + return false; + } + + /* Multi hop requires local address. */ + if (bsp->args.mhop + && memcmp(&i6a_zero, &bsp->args.src, sizeof(i6a_zero)) == 0) { + if (bsglobal.debugging) + zlog_debug( + "%s: multi hop but no local address provided", + __func__); + return false; + } + + /* Check VRF ID. */ + if (bsp->args.vrf_id == VRF_UNKNOWN) { + if (bsglobal.debugging) + zlog_debug("%s: asked for unknown VRF", __func__); + return false; + } + + return true; +} + +static int _bfd_sess_send(struct thread *t) +{ + struct bfd_session_params *bsp = THREAD_ARG(t); + int rv; + + /* Validate configuration before trying to send bogus data. */ + if (!_bfd_sess_valid(bsp)) + return 0; + + if (bsp->lastev == BSE_INSTALL) { + bsp->args.command = bsp->installed ? ZEBRA_BFD_DEST_UPDATE + : ZEBRA_BFD_DEST_REGISTER; + } else + bsp->args.command = ZEBRA_BFD_DEST_DEREGISTER; + + /* If not installed and asked for uninstall, do nothing. */ + if (!bsp->installed && bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER) + return 0; + + rv = zclient_bfd_command(bsglobal.zc, &bsp->args); + /* Command was sent successfully. */ + if (rv == 0) { + /* Update installation status. */ + if (bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER) + bsp->installed = false; + else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER) + bsp->installed = true; + } + + return 0; +} + +static void _bfd_sess_remove(struct bfd_session_params *bsp) +{ + /* Not installed, nothing to do. */ + if (!bsp->installed) + return; + + /* Cancel any pending installation request. */ + THREAD_OFF(bsp->installev); + + /* Send request to remove any session. */ + bsp->lastev = BSE_UNINSTALL; + thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0); +} + +void bfd_sess_free(struct bfd_session_params **bsp) +{ + if (*bsp == NULL) + return; + + /* Remove any installed session. */ + _bfd_sess_remove(*bsp); + + /* Remove from global list. */ + TAILQ_REMOVE(&bsglobal.bsplist, (*bsp), entry); + + /* Free the memory and point to NULL. */ + XFREE(MTYPE_BFD_INFO, (*bsp)); +} + +void bfd_sess_enable(struct bfd_session_params *bsp, bool enable) +{ + /* Remove the session when disabling. */ + if (!enable) + _bfd_sess_remove(bsp); + + bsp->enabled = enable; +} + +void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, + struct in_addr *src, struct in_addr *dst) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + bsp->args.family = AF_INET; + + /* Clean memory, set zero value and avoid static analyser warnings. */ + memset(&bsp->args.src, 0, sizeof(bsp->args.src)); + memset(&bsp->args.dst, 0, sizeof(bsp->args.dst)); + + /* Copy the equivalent of IPv4 to arguments structure. */ + if (src) + memcpy(&bsp->args.src, src, sizeof(struct in_addr)); + + assert(dst); + memcpy(&bsp->args.dst, dst, sizeof(struct in_addr)); +} + +void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, + struct in6_addr *src, struct in6_addr *dst) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + bsp->args.family = AF_INET6; + + /* Clean memory, set zero value and avoid static analyser warnings. */ + memset(&bsp->args.src, 0, sizeof(bsp->args.src)); + + if (src) + bsp->args.src = *src; + + assert(dst); + bsp->args.dst = *dst; +} + +void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + if (ifname == NULL) { + bsp->args.ifname[0] = 0; + bsp->args.ifnamelen = 0; + return; + } + + if (strlcpy(bsp->args.ifname, ifname, sizeof(bsp->args.ifname)) + > sizeof(bsp->args.ifname)) + zlog_warn("%s: interface name truncated: %s", __func__, ifname); + + bsp->args.ifnamelen = strlen(bsp->args.ifname); +} + +void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile) +{ + if (profile == NULL) { + bsp->args.profile[0] = 0; + bsp->args.profilelen = 0; + return; + } + + if (strlcpy(bsp->args.profile, profile, sizeof(bsp->args.profile)) + > sizeof(bsp->args.profile)) + zlog_warn("%s: profile name truncated: %s", __func__, profile); + + bsp->args.profilelen = strlen(bsp->args.profile); +} + +void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + bsp->args.vrf_id = vrf_id; +} + +void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl) +{ + assert(min_ttl != 0); + + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + /* Invert TTL value: protocol expects number of hops. */ + min_ttl = (BFD_SINGLE_HOP_TTL + 1) - min_ttl; + bsp->args.ttl = min_ttl; + bsp->args.mhop = (min_ttl > 1); +} + +void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl) +{ + /* If already installed, remove the old setting. */ + _bfd_sess_remove(bsp); + + bsp->args.ttl = min_ttl; + bsp->args.mhop = (min_ttl > 1); +} + + +void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable) +{ + bsp->args.cbit = enable; +} + +void bfd_sess_set_timers(struct bfd_session_params *bsp, + uint8_t detection_multiplier, uint32_t min_rx, + uint32_t min_tx) +{ + bsp->args.detection_multiplier = detection_multiplier; + bsp->args.min_rx = min_rx; + bsp->args.min_tx = min_tx; +} + +void bfd_sess_install(struct bfd_session_params *bsp) +{ + /* Don't attempt to install/update when disabled. */ + if (!bsp->enabled) + return; + + bsp->lastev = BSE_INSTALL; + thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev); +} + +void bfd_sess_uninstall(struct bfd_session_params *bsp) +{ + bsp->lastev = BSE_UNINSTALL; + thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev); +} + +enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp) +{ + return bsp->bss.state; +} + +uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp) +{ + return ((BFD_SINGLE_HOP_TTL + 1) - bsp->args.ttl); +} + +uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp) +{ + return bsp->args.ttl; +} + +const char *bfd_sess_profile(const struct bfd_session_params *bsp) +{ + return bsp->args.profilelen ? bsp->args.profile : NULL; +} + +void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family, + struct in6_addr *src, struct in6_addr *dst) +{ + *family = bsp->args.family; + if (src) + *src = bsp->args.src; + if (dst) + *dst = bsp->args.dst; +} + +const char *bfd_sess_interface(const struct bfd_session_params *bsp) +{ + if (bsp->args.ifnamelen) + return bsp->args.ifname; + + return NULL; +} + +const char *bfd_sess_vrf(const struct bfd_session_params *bsp) +{ + return vrf_id_to_name(bsp->args.vrf_id); +} + +vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp) +{ + return bsp->args.vrf_id; +} + +bool bfd_sess_cbit(const struct bfd_session_params *bsp) +{ + return bsp->args.cbit; +} + +void bfd_sess_timers(const struct bfd_session_params *bsp, + uint8_t *detection_multiplier, uint32_t *min_rx, + uint32_t *min_tx) +{ + *detection_multiplier = bsp->args.detection_multiplier; + *min_rx = bsp->args.min_rx; + *min_tx = bsp->args.min_tx; +} + +void bfd_sess_show(struct vty *vty, struct json_object *json, + struct bfd_session_params *bsp) +{ + json_object *json_bfd = NULL; + char time_buf[64]; + + /* Show type. */ + if (json) { + json_bfd = json_object_new_object(); + if (bsp->args.mhop) + json_object_string_add(json_bfd, "type", "multi hop"); + else + json_object_string_add(json_bfd, "type", "single hop"); + } else + vty_out(vty, " BFD: Type: %s\n", + bsp->args.mhop ? "multi hop" : "single hop"); + + /* Show configuration. */ + if (json) { + json_object_int_add(json_bfd, "detectMultiplier", + bsp->args.detection_multiplier); + json_object_int_add(json_bfd, "rxMinInterval", + bsp->args.min_rx); + json_object_int_add(json_bfd, "txMinInterval", + bsp->args.min_tx); + } else { + vty_out(vty, + " Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", + bsp->args.detection_multiplier, bsp->args.min_rx, + bsp->args.min_tx); + } + + bfd_last_update(bsp->bss.last_event, time_buf, sizeof(time_buf)); + if (json) { + json_object_string_add(json_bfd, "status", + bfd_get_status_str(bsp->bss.state)); + json_object_string_add(json_bfd, "lastUpdate", time_buf); + } else + vty_out(vty, " Status: %s, Last update: %s\n", + bfd_get_status_str(bsp->bss.state), time_buf); + + if (json) + json_object_object_add(json, "peerBfdInfo", json_bfd); + else + vty_out(vty, "\n"); +} + +/* + * Zebra communication related. + */ + +/** + * Callback for reinstallation of all registered BFD sessions. + * + * Use this as `zclient` `bfd_dest_replay` callback. + */ +static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS) +{ + struct bfd_session_params *bsp; + + /* Do nothing when shutting down. */ + if (bsglobal.shutting_down) + return 0; + + if (bsglobal.debugging) + zlog_debug("%s: sending all sessions registered", __func__); + + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); + + /* Replay all activated peers. */ + TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { + /* Skip disabled sessions. */ + if (!bsp->enabled) + continue; + + /* We are reconnecting, so we must send installation. */ + bsp->installed = false; + + /* Cancel any pending installation request. */ + THREAD_OFF(bsp->installev); + + /* Ask for installation. */ + bsp->lastev = BSE_INSTALL; + thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0); + } + + return 0; +} + +static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) +{ + struct bfd_session_params *bsp; + size_t sessions_updated = 0; + struct interface *ifp; + int remote_cbit = false; + int state = BFD_STATUS_UNKNOWN; + time_t now; + size_t addrlen; + struct prefix dp; + struct prefix sp; + char ifstr[128], cbitstr[32]; + + /* Do nothing when shutting down. */ + if (bsglobal.shutting_down) + return 0; + + ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit, + vrf_id); + + if (bsglobal.debugging) { + ifstr[0] = 0; + if (ifp) + snprintf(ifstr, sizeof(ifstr), " (interface %s)", + ifp->name); + + snprintf(cbitstr, sizeof(cbitstr), " (CPI bit %s)", + remote_cbit ? "yes" : "no"); + + zlog_debug("%s: %pFX -> %pFX%s VRF %s(%u)%s: %s", __func__, &sp, + &dp, ifstr, vrf_id_to_name(vrf_id), vrf_id, cbitstr, + bfd_get_status_str(state)); + } + + switch (dp.family) { + case AF_INET: + addrlen = sizeof(struct in_addr); + break; + case AF_INET6: + addrlen = sizeof(struct in6_addr); + break; + + default: + /* Unexpected value. */ + assert(0); + break; + } + + /* Cache current time to avoid multiple monotime clock calls. */ + now = monotime(NULL); + + /* Notify all matching sessions about update. */ + TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) { + /* Skip disabled or not installed entries. */ + if (!bsp->enabled || !bsp->installed) + continue; + /* Skip different VRFs. */ + if (bsp->args.vrf_id != vrf_id) + continue; + /* Skip different families. */ + if (bsp->args.family != dp.family) + continue; + /* Skip different interface. */ + if (bsp->args.ifnamelen && ifp + && strcmp(bsp->args.ifname, ifp->name) != 0) + continue; + /* Skip non matching destination addresses. */ + if (memcmp(&bsp->args.dst, &dp.u, addrlen) != 0) + continue; + /* + * Source comparison test: + * We will only compare source if BFD daemon provided the + * source address and the protocol set a source address in + * the configuration otherwise we'll just skip it. + */ + if (sp.family && memcmp(&bsp->args.src, &i6a_zero, addrlen) != 0 + && memcmp(&sp.u, &i6a_zero, addrlen) != 0 + && memcmp(&bsp->args.src, &sp.u, addrlen) != 0) + continue; + /* No session state change. */ + if ((int)bsp->bss.state == state) + continue; + + bsp->bss.last_event = now; + bsp->bss.previous_state = bsp->bss.state; + bsp->bss.state = state; + bsp->bss.remote_cbit = remote_cbit; + bsp->updatecb(bsp, &bsp->bss, bsp->arg); + sessions_updated++; + } + + if (bsglobal.debugging) + zlog_debug("%s: sessions updated: %zu", __func__, + sessions_updated); + + return 0; +} + +void bfd_protocol_integration_init(struct zclient *zc, struct thread_master *tm) +{ + /* Initialize data structure. */ + TAILQ_INIT(&bsglobal.bsplist); + + /* Copy pointers. */ + bsglobal.zc = zc; + bsglobal.tm = tm; + + /* Install our callbacks. */ + zc->interface_bfd_dest_update = zclient_bfd_session_update; + zc->bfd_dest_replay = zclient_bfd_session_reply; + + /* Send the client registration */ + bfd_client_sendmsg(zc, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); +} + +void bfd_protocol_integration_set_debug(bool enable) +{ + bsglobal.debugging = enable; +} + +void bfd_protocol_integration_set_shutdown(bool enable) +{ + bsglobal.shutting_down = enable; +} + +bool bfd_protocol_integration_debug(void) +{ + return bsglobal.debugging; +} + +bool bfd_protocol_integration_shutting_down(void) +{ + return bsglobal.shutting_down; +} @@ -128,6 +128,305 @@ extern void bfd_gbl_exit(void); * BFD new API. */ +/* Forward declaration of argument struct. */ +struct bfd_session_params; + +/** Session state definitions. */ +enum bfd_session_state { + /** Session state is unknown or not initialized. */ + BSS_UNKNOWN = BFD_STATUS_UNKNOWN, + /** Local or remote peer administratively shutdown the session. */ + BSS_ADMIN_DOWN = BFD_STATUS_ADMIN_DOWN, + /** Session is down. */ + BSS_DOWN = BFD_STATUS_DOWN, + /** Session is up and working correctly. */ + BSS_UP = BFD_STATUS_UP, +}; + +/** BFD session status information */ +struct bfd_session_status { + /** Current session state. */ + enum bfd_session_state state; + /** Previous session state. */ + enum bfd_session_state previous_state; + /** Remote Control Plane Independent bit state. */ + bool remote_cbit; + /** Last event occurrence. */ + time_t last_event; +}; + +/** + * Session status update callback. + * + * \param bsp BFD session parameters. + * \param bss BFD session status. + * \param arg application independent data. + */ +typedef void (*bsp_status_update)(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, + void *arg); + +/** + * Allocates and initializes the session parameters. + * + * \param updatedb status update notification callback. + * \param args application independent data. + * + * \returns pointer to configuration storage. + */ +struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *args); + +/** + * Uninstall session if installed and free resources allocated by the + * parameters. Already sets pointer to `NULL` to avoid dangling references. + * + * \param bsp session parameters. + */ +void bfd_sess_free(struct bfd_session_params **bsp); + +/** + * Enable/disable session installation. + * + * \param bsp session parameters. + * \param enable knob variable. + */ +void bfd_sess_enable(struct bfd_session_params *bsp, bool enable); + +/** + * Set the local and peer address of the BFD session. + * + * \param bsp BFD session parameters. + * \param src local address (optional, can be `NULL`). + * \param dst remote address (mandatory). + */ +void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, + struct in_addr *src, struct in_addr *dst); + +/** + * Set the local and peer address of the BFD session. + * + * \param bsp BFD session parameters. + * \param src local address (optional, can be `NULL`). + * \param dst remote address (mandatory). + */ +void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, + struct in6_addr *src, struct in6_addr *dst); + +/** + * Configure the BFD session interface. + * + * \param bsp BFD session parameters. + * \param ifname interface name (or `NULL` to remove it). + */ +void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname); + +/** + * Configure the BFD session profile name. + * + * \param bsp BFD session parameters. + * \param profile profile name (or `NULL` to remove it). + */ +void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile); + +/** + * Configure the BFD session VRF. + * + * \param bsp BFD session parameters. + * \param vrf_id the VRF identification number. + */ +void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id); + +/** + * Configure the BFD session single/multi hop setting. + * + * \param bsp BFD session parameters. + * \param min_ttl minimum TTL value expected (255 for single hop, 254 for + * multi hop with single hop, 253 for multi hop with two hops + * and so on). See `BFD_SINGLE_HOP_TTL` and + * `BFD_MULTI_HOP_MIN_TTL` for defaults. + * + * To simplify things if your protocol only knows the amount of hops it is + * better to use `bfd_sess_set_hops` instead. + */ +void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl); + +/** To use single hop the minimum TTL must be set to this. */ +#define BFD_SINGLE_HOP_TTL 255 +/** To use multi hop the minimum TTL must be set to this or less. */ +#define BFD_MULTI_HOP_MIN_TTL 254 + +/** + * This function is the inverted version of `bfd_sess_set_minimum_ttl`. + * Instead of receiving the minimum expected TTL, it receives the amount of + * hops the protocol will jump. + * + * \param bsp BFD session parameters. + * \param min_ttl minimum amount of hops expected (1 for single hop, 2 or + * more for multi hop). + */ +void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl); + +/** + * Configure the BFD session to set the Control Plane Independent bit. + * + * \param bsp BFD session parameters. + * \param enable BFD Control Plane Independent state. + */ +void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable); + +/** + * DEPRECATED: please avoid using timers directly and use profiles instead. + * + * Configures the BFD session timers to use. This is specially useful with + * `ptm-bfd` which does not support timers. + * + * \param bsp BFD session parameters. + * \param detection_multiplier the detection multiplier value. + * \param min_rx minimum required receive period. + * \param min_tx minimum required transmission period. + */ +void bfd_sess_set_timers(struct bfd_session_params *bsp, + uint8_t detection_multiplier, uint32_t min_rx, + uint32_t min_tx); + +/** + * Installs or updates the BFD session based on the saved session arguments. + * + * \param bsp session parameters. + */ +void bfd_sess_install(struct bfd_session_params *bsp); + +/** + * Uninstall the BFD session based on the saved session arguments. + * + * \param bsp session parameters. + */ +void bfd_sess_uninstall(struct bfd_session_params *bsp); + +/** + * Get BFD session current status. + * + * \param bsp session parameters. + * + * \returns BFD session status data structure. + */ +enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp); + +/** + * Get BFD session minimum TTL configured value. + * + * \param bsp session parameters. + * + * \returns configured minimum TTL. + */ +uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp); + +/** + * Inverted version of `bfd_sess_minimum_ttl`. Gets the amount of hops in the + * way to the peer. + * + * \param bsp session parameters. + * + * \returns configured amount of hops. + */ +uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp); + +/** + * Get BFD session profile configured value. + * + * \param bsp session parameters. + * + * \returns configured profile name (or `NULL` if empty). + */ +const char *bfd_sess_profile(const struct bfd_session_params *bsp); + +/** + * Get BFD session addresses. + * + * \param bsp session parameters. + * \param family the address family being used (AF_INET or AF_INET6). + * \param src source address (optional, may be `NULL`). + * \param dst peer address (optional, may be `NULL`). + */ +void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family, + struct in6_addr *src, struct in6_addr *dst); +/** + * Get BFD session interface name. + * + * \param bsp session parameters. + * + * \returns `NULL` if not set otherwise the interface name. + */ +const char *bfd_sess_interface(const struct bfd_session_params *bsp); + +/** + * Get BFD session VRF name. + * + * \param bsp session parameters. + * + * \returns the VRF name. + */ +const char *bfd_sess_vrf(const struct bfd_session_params *bsp); + +/** + * Get BFD session VRF ID. + * + * \param bsp session parameters. + * + * \returns the VRF name. + */ +vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp); + +/** + * Get BFD session control plane independent bit configuration state. + * + * \param bsp session parameters. + * + * \returns `true` if enabled otherwise `false`. + */ +bool bfd_sess_cbit(const struct bfd_session_params *bsp); + +/** + * DEPRECATED: please avoid using timers directly and use profiles instead. + * + * Gets the configured timers. + * + * \param bsp BFD session parameters. + * \param detection_multiplier the detection multiplier value. + * \param min_rx minimum required receive period. + * \param min_tx minimum required transmission period. + */ +void bfd_sess_timers(const struct bfd_session_params *bsp, + uint8_t *detection_multiplier, uint32_t *min_rx, + uint32_t *min_tx); + +/** + * Show BFD session configuration and status. If `json` is provided (e.g. not + * `NULL`) then information will be inserted in object, otherwise printed to + * `vty`. + * + * \param vty Pointer to `vty` for outputting text. + * \param json (optional) JSON object pointer. + * \param bsp session parameters. + */ +void bfd_sess_show(struct vty *vty, struct json_object *json, + struct bfd_session_params *bsp); + +/** + * Initializes the BFD integration library. This function executes the + * following actions: + * + * - Copy the `struct thread_master` pointer to use as "thread" to execute + * the BFD session parameters installation. + * - Copy the `struct zclient` pointer to install its callbacks. + * - Initializes internal data structures. + * + * \param tm normally the daemon main thread event manager. + * \param zc the zebra client of the daemon. + */ +void bfd_protocol_integration_init(struct zclient *zc, + struct thread_master *tm); + /** * BFD session registration arguments. */ @@ -205,6 +504,34 @@ struct bfd_session_arg { */ extern int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *arg); +/** + * Enables or disables BFD protocol integration API debugging. + * + * \param enable new API debug state. + */ +extern void bfd_protocol_integration_set_debug(bool enable); + +/** + * Sets shutdown mode so no more events are processed. + * + * This is useful to avoid the event storm that happens caused by network, + * interfaces or VRFs removal. It should also avoid some crashes due hanging + * pointers left overs by protocol. + * + * \param enable new API shutdown state. + */ +extern void bfd_protocol_integration_set_shutdown(bool enable); + +/** + * Get API debugging state. + */ +extern bool bfd_protocol_integration_debug(void); + +/** + * Get API shutdown state. + */ +extern bool bfd_protocol_integration_shutting_down(void); + #ifdef __cplusplus } #endif diff --git a/lib/buffer.c b/lib/buffer.c index 42796faae8..7929b3709d 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -29,8 +29,8 @@ #include <stddef.h> -DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer") -DEFINE_MTYPE_STATIC(LIB, BUFFER_DATA, "Buffer data") +DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer"); +DEFINE_MTYPE_STATIC(LIB, BUFFER_DATA, "Buffer data"); /* Buffer master. */ struct buffer { diff --git a/lib/command.c b/lib/command.c index 6a4d504b2f..770e2fc5ac 100644 --- a/lib/command.c +++ b/lib/command.c @@ -51,8 +51,8 @@ #include "frrscript.h" -DEFINE_MTYPE_STATIC(LIB, HOST, "Host config") -DEFINE_MTYPE(LIB, COMPLETION, "Completion item") +DEFINE_MTYPE_STATIC(LIB, HOST, "Host config"); +DEFINE_MTYPE(LIB, COMPLETION, "Completion item"); #define item(x) \ { \ diff --git a/lib/command.h b/lib/command.h index 71abb20b05..14e51486ea 100644 --- a/lib/command.h +++ b/lib/command.h @@ -34,7 +34,7 @@ extern "C" { #endif -DECLARE_MTYPE(COMPLETION) +DECLARE_MTYPE(COMPLETION); /* * From RFC 1123 (Requirements for Internet Hosts), Section 2.1 on hostnames: diff --git a/lib/command_graph.c b/lib/command_graph.c index d30d9ab702..c6c3840455 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -26,11 +26,11 @@ #include "command_graph.h" -DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens") -DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text") -DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help") -DEFINE_MTYPE(LIB, CMD_ARG, "Command Argument") -DEFINE_MTYPE_STATIC(LIB, CMD_VAR, "Command Argument Name") +DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens"); +DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text"); +DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help"); +DEFINE_MTYPE(LIB, CMD_ARG, "Command Argument"); +DEFINE_MTYPE_STATIC(LIB, CMD_VAR, "Command Argument Name"); struct cmd_token *cmd_token_new(enum cmd_token_type type, uint8_t attr, const char *text, const char *desc) diff --git a/lib/command_graph.h b/lib/command_graph.h index 86715410ce..2754dca67d 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -37,7 +37,7 @@ extern "C" { #endif -DECLARE_MTYPE(CMD_ARG) +DECLARE_MTYPE(CMD_ARG); struct vty; diff --git a/lib/command_match.c b/lib/command_match.c index 801b05f157..e9e8466ffd 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -26,7 +26,7 @@ #include "command_match.h" #include "memory.h" -DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack") +DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack"); #ifdef TRACE_MATCHER #define TM 1 diff --git a/lib/command_parse.y b/lib/command_parse.y index 8135d02b4b..5ebc19b278 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -54,7 +54,7 @@ #include "command_graph.h" #include "log.h" - DECLARE_MTYPE(LEX) + DECLARE_MTYPE(LEX); #define YYSTYPE CMD_YYSTYPE #define YYLTYPE CMD_YYLTYPE @@ -376,7 +376,7 @@ selector: '[' selector_seq_seq ']' varname_token #undef scanner -DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)") +DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)"); void cmd_graph_parse (struct graph *graph, const struct cmd_element *cmd) diff --git a/lib/compiler.h b/lib/compiler.h index 70ef8e9bc8..b7a142bdee 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -21,6 +21,21 @@ extern "C" { #endif +#ifdef __cplusplus +# if __cplusplus < 201103L +# error FRRouting headers must be compiled in C++11 mode or newer +# endif +/* C++ defines static_assert(), but not _Static_assert(). C defines + * _Static_assert() and has static_assert() in <assert.h>. However, we mess + * with assert() in zassert.h so let's not include <assert.h> here. + */ +# define _Static_assert static_assert +#else +# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L +# error FRRouting must be compiled with min. -std=gnu11 (GNU ISO C11 dialect) +# endif +#endif + /* function attributes, use like * void prototype(void) __attribute__((_CONSTRUCTOR(100))); */ @@ -121,6 +136,24 @@ extern "C" { #define macro_inline static inline __attribute__((unused)) #define macro_pure static inline __attribute__((unused, pure)) +/* if the macro ends with a function definition */ +#define MACRO_REQUIRE_SEMICOLON() \ + _Static_assert(1, "please add a semicolon after this macro") + +#if CONFDATE < 20210601 +#ifdef ENABLE_BGP_VNC +/* temporarily disabled for transition for LabN CI + * NB: it's not possible to generate a deprecation warning for this, hence + * the shortened transition period (since otherwise new uses of the old syntax + * may creep in without errors) + */ +#undef MACRO_REQUIRE_SEMICOLON +#define MACRO_REQUIRE_SEMICOLON() \ + /* nothing */ +#endif /* ENABLE_BGP_VNC */ +#else /* CONFDATE >= 20210601 */ +CPP_NOTICE("time to remove this CONFDATE block") +#endif /* variadic macros, use like: * #define V_0() ... @@ -357,10 +390,8 @@ typedef signed long long _int64_t; /* if this breaks, 128-bit machines may have entered reality (or <long long> * is something weird) */ -#if __STDC_VERSION__ >= 201112L _Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8, "nobody expects the spanish intquisition"); -#endif /* since we redefined int64_t, we also need to redefine PRI*64 */ #undef PRIu64 diff --git a/lib/debug.c b/lib/debug.c index 3248ceb13b..e2ba4cd4ef 100644 --- a/lib/debug.c +++ b/lib/debug.c @@ -24,7 +24,7 @@ static struct debug_cb_list_head cb_head; -DECLARE_LIST(debug_cb_list, struct debug_callbacks, item) +DECLARE_LIST(debug_cb_list, struct debug_callbacks, item); /* All code in this section should be reentrant and MT-safe */ diff --git a/lib/debug.h b/lib/debug.h index f25cd42691..a72657bdaf 100644 --- a/lib/debug.h +++ b/lib/debug.h @@ -84,7 +84,7 @@ struct debug { const char *desc; }; -PREDECL_LIST(debug_cb_list) +PREDECL_LIST(debug_cb_list); /* * Callback set for debugging code. * diff --git a/lib/defaults.h b/lib/defaults.h index 20ef28db31..55250f0f81 100644 --- a/lib/defaults.h +++ b/lib/defaults.h @@ -98,7 +98,8 @@ struct frr_default { static void _dfltinit_##varname(void) \ { \ frr_default_add(&_dflt_##varname); \ - } + } \ + MACRO_REQUIRE_SEMICOLON() /* end */ /* use: * FRR_CFG_DEFAULT_LONG(SHARP_BLUNTNESS, diff --git a/lib/distribute.c b/lib/distribute.c index 3ea60c8772..60bd0a47bb 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -27,10 +27,10 @@ #include "distribute.h" #include "memory.h" -DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx") -DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list") -DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname") -DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name") +DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx"); +DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list"); +DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname"); +DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name"); static struct list *dist_ctx_list; diff --git a/lib/elf_py.c b/lib/elf_py.c index 0d8ad76e1c..d26e443b82 100644 --- a/lib/elf_py.c +++ b/lib/elf_py.c @@ -100,7 +100,7 @@ static PyObject *refuse_new(PyTypeObject *type, PyObject *args, PyObject *kwds) struct elfreloc; struct elfsect; -PREDECL_HASH(elfrelocs) +PREDECL_HASH(elfrelocs); /* ELFFile and ELFSection intentionally share some behaviour, particularly * subscript[123:456] access to file data. This is because relocatables @@ -200,7 +200,7 @@ static int elfreloc_cmp(const struct elfreloc *a, const struct elfreloc *b); static uint32_t elfreloc_hash(const struct elfreloc *reloc); DECLARE_HASH(elfrelocs, struct elfreloc, elfrelocs_item, - elfreloc_cmp, elfreloc_hash) + elfreloc_cmp, elfreloc_hash); static Elf_Scn *elf_find_addr(struct elffile *ef, uint64_t addr, size_t *idx); static PyObject *elffile_secbyidx(struct elffile *w, Elf_Scn *scn, size_t idx); diff --git a/lib/ferr.c b/lib/ferr.c index 691da495cf..513ef5ebec 100644 --- a/lib/ferr.c +++ b/lib/ferr.c @@ -35,7 +35,7 @@ #include "linklist.h" #include "frr_pthread.h" -DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information") +DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information"); /* * Thread-specific key for temporary storage of allocated ferr. diff --git a/lib/filter.c b/lib/filter.c index f5ae9ee2b7..83423ba321 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -31,9 +31,9 @@ #include "libfrr.h" #include "northbound_cli.h" -DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List") -DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str") -DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter") +DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List"); +DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str"); +DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter"); /* Static structure for mac access_list's master. */ static struct access_master access_master_mac = { diff --git a/lib/filter.h b/lib/filter.h index 091a5197f6..28f5202022 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -182,6 +182,9 @@ struct acl_dup_args { /** Access list name. */ const char *ada_name; + /** Entry action. */ + const char *ada_action; + #define ADA_MAX_VALUES 4 /** Entry XPath for value. */ const char *ada_xpath[ADA_MAX_VALUES]; @@ -209,6 +212,9 @@ struct plist_dup_args { /** Access list name. */ const char *pda_name; + /** Entry action. */ + const char *pda_action; + #define PDA_MAX_VALUES 4 /** Entry XPath for value. */ const char *pda_xpath[PDA_MAX_VALUES]; @@ -234,10 +240,12 @@ bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda); struct lyd_node; struct vty; +extern int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); extern void access_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); +extern int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); extern void prefix_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); extern void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode, diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 5d66a9fc73..96444ac970 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -173,6 +173,7 @@ DEFPY_YANG( if (seq_str == NULL) { ada.ada_type = "ipv4"; ada.ada_name = name; + ada.ada_action = action; if (host_str && mask_str == NULL) { ada.ada_xpath[0] = "./host"; ada.ada_value[0] = host_str; @@ -309,6 +310,7 @@ DEFPY_YANG( if (seq_str == NULL) { ada.ada_type = "ipv4"; ada.ada_name = name; + ada.ada_action = action; if (src_str && src_mask_str == NULL) { ada.ada_xpath[idx] = "./host"; ada.ada_value[idx] = src_str; @@ -504,6 +506,7 @@ DEFPY_YANG( if (seq_str == NULL) { ada.ada_type = "ipv4"; ada.ada_name = name; + ada.ada_action = action; if (prefix_str) { ada.ada_xpath[0] = "./ipv4-prefix"; @@ -701,6 +704,7 @@ DEFPY_YANG( if (seq_str == NULL) { ada.ada_type = "ipv6"; ada.ada_name = name; + ada.ada_action = action; if (prefix_str) { ada.ada_xpath[0] = "./ipv6-prefix"; @@ -902,6 +906,7 @@ DEFPY_YANG( if (seq_str == NULL) { ada.ada_type = "mac"; ada.ada_name = name; + ada.ada_action = action; if (mac_str) { ada.ada_xpath[0] = "./mac"; @@ -1072,6 +1077,14 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) +int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +{ + uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence"); + uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence"); + + return seq1 - seq2; +} + void access_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { @@ -1331,6 +1344,7 @@ DEFPY_YANG( if (seq_str == NULL) { pda.pda_type = "ipv4"; pda.pda_name = name; + pda.pda_action = action; if (prefix_str) { pda.pda_xpath[arg_idx] = "./ipv4-prefix"; pda.pda_value[arg_idx] = prefix_str; @@ -1526,6 +1540,7 @@ DEFPY_YANG( if (seq_str == NULL) { pda.pda_type = "ipv6"; pda.pda_name = name; + pda.pda_action = action; if (prefix_str) { pda.pda_xpath[arg_idx] = "./ipv6-prefix"; pda.pda_value[arg_idx] = prefix_str; @@ -1693,6 +1708,14 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) +int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +{ + uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence"); + uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence"); + + return seq1 - seq2; +} + void prefix_list_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { diff --git a/lib/filter_nb.c b/lib/filter_nb.c index c83738e729..3aa362ad63 100644 --- a/lib/filter_nb.c +++ b/lib/filter_nb.c @@ -152,6 +152,27 @@ prefix_list_nb_validate_v6_af_type(const struct lyd_node *plist_dnode, return NB_OK; } +static int lib_prefix_list_entry_prefix_length_greater_or_equal_modify( + struct nb_cb_modify_args *args) +{ + struct prefix_list_entry *ple; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + ple = nb_running_get_entry(args->dnode, NULL, true); + + /* Start prefix entry update procedure. */ + prefix_list_entry_update_start(ple); + + ple->ge = yang_dnode_get_uint8(args->dnode, NULL); + + /* Finish prefix entry update procedure. */ + prefix_list_entry_update_finish(ple); + + return NB_OK; +} + static int lib_prefix_list_entry_prefix_length_lesser_or_equal_modify( struct nb_cb_modify_args *args) { @@ -238,6 +259,9 @@ static int _acl_is_dup(const struct lyd_node *dnode, void *arg) && ada->ada_entry_dnode == dnode) return YANG_ITER_CONTINUE; + if (strcmp(yang_dnode_get_string(dnode, "action"), ada->ada_action)) + return YANG_ITER_CONTINUE; + /* Check if all values match. */ for (idx = 0; idx < ADA_MAX_VALUES; idx++) { /* No more values. */ @@ -292,6 +316,7 @@ static bool acl_cisco_is_dup(const struct lyd_node *dnode) /* Initialize. */ ada.ada_type = "ipv4"; ada.ada_name = yang_dnode_get_string(entry_dnode, "../name"); + ada.ada_action = yang_dnode_get_string(entry_dnode, "action"); ada.ada_entry_dnode = entry_dnode; /* Load all values/XPaths. */ @@ -341,6 +366,7 @@ static bool acl_zebra_is_dup(const struct lyd_node *dnode, break; } ada.ada_name = yang_dnode_get_string(entry_dnode, "../name"); + ada.ada_action = yang_dnode_get_string(entry_dnode, "action"); ada.ada_entry_dnode = entry_dnode; /* Load all values/XPaths. */ @@ -370,6 +396,9 @@ static int _plist_is_dup(const struct lyd_node *dnode, void *arg) && pda->pda_entry_dnode == dnode) return YANG_ITER_CONTINUE; + if (strcmp(yang_dnode_get_string(dnode, "action"), pda->pda_action)) + return YANG_ITER_CONTINUE; + /* Check if all values match. */ for (idx = 0; idx < PDA_MAX_VALUES; idx++) { /* No more values. */ @@ -403,6 +432,46 @@ bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda) return pda->pda_found; } +static bool plist_is_dup_nb(const struct lyd_node *dnode) +{ + const struct lyd_node *entry_dnode = + yang_dnode_get_parent(dnode, "entry"); + struct plist_dup_args pda = {}; + int idx = 0, arg_idx = 0; + static const char *entries[] = { + "./ipv4-prefix", + "./ipv4-prefix-length-greater-or-equal", + "./ipv4-prefix-length-lesser-or-equal", + "./ipv6-prefix", + "./ipv6-prefix-length-greater-or-equal", + "./ipv6-prefix-length-lesser-or-equal", + "./any", + NULL + }; + + /* Initialize. */ + pda.pda_type = yang_dnode_get_string(entry_dnode, "../type"); + pda.pda_name = yang_dnode_get_string(entry_dnode, "../name"); + pda.pda_action = yang_dnode_get_string(entry_dnode, "action"); + pda.pda_entry_dnode = entry_dnode; + + /* Load all values/XPaths. */ + while (entries[idx] != NULL) { + if (!yang_dnode_exists(entry_dnode, entries[idx])) { + idx++; + continue; + } + + pda.pda_xpath[arg_idx] = entries[idx]; + pda.pda_value[arg_idx] = + yang_dnode_get_string(entry_dnode, entries[idx]); + arg_idx++; + idx++; + } + + return plist_is_dup(entry_dnode, &pda); +} + /* * XPath: /frr-filter:lib/access-list */ @@ -1265,6 +1334,13 @@ lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args) const struct lyd_node *plist_dnode = yang_dnode_get_parent(args->dnode, "prefix-list"); + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return prefix_list_nb_validate_v4_af_type( plist_dnode, args->errmsg, args->errmsg_len); } @@ -1293,6 +1369,13 @@ lib_prefix_list_entry_ipv6_prefix_modify(struct nb_cb_modify_args *args) const struct lyd_node *plist_dnode = yang_dnode_get_parent(args->dnode, "prefix-list"); + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return prefix_list_nb_validate_v6_af_type( plist_dnode, args->errmsg, args->errmsg_len); } @@ -1316,26 +1399,27 @@ lib_prefix_list_entry_ipv6_prefix_destroy(struct nb_cb_destroy_args *args) static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify( struct nb_cb_modify_args *args) { - struct prefix_list_entry *ple; - - if (args->event == NB_EV_VALIDATE && - prefix_list_length_validate(args) != NB_OK) + if (args->event == NB_EV_VALIDATE + && prefix_list_length_validate(args) != NB_OK) return NB_ERR_VALIDATION; - if (args->event != NB_EV_APPLY) - return NB_OK; - - ple = nb_running_get_entry(args->dnode, NULL, true); - - /* Start prefix entry update procedure. */ - prefix_list_entry_update_start(ple); + if (args->event == NB_EV_VALIDATE) { + const struct lyd_node *plist_dnode = + yang_dnode_get_parent(args->dnode, "prefix-list"); - ple->ge = yang_dnode_get_uint8(args->dnode, NULL); + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); + return prefix_list_nb_validate_v4_af_type( + plist_dnode, args->errmsg, args->errmsg_len); + } - return NB_OK; + return lib_prefix_list_entry_prefix_length_greater_or_equal_modify( + args); } static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy( @@ -1367,11 +1451,19 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify( const struct lyd_node *plist_dnode = yang_dnode_get_parent(args->dnode, "prefix-list"); + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return prefix_list_nb_validate_v4_af_type( plist_dnode, args->errmsg, args->errmsg_len); } - return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args); + return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify( + args); } static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy( @@ -1395,8 +1487,6 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy( static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify( struct nb_cb_modify_args *args) { - struct prefix_list_entry *ple; - if (args->event == NB_EV_VALIDATE && prefix_list_length_validate(args) != NB_OK) return NB_ERR_VALIDATION; @@ -1405,24 +1495,19 @@ static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify( const struct lyd_node *plist_dnode = yang_dnode_get_parent(args->dnode, "prefix-list"); + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return prefix_list_nb_validate_v6_af_type( plist_dnode, args->errmsg, args->errmsg_len); } - if (args->event != NB_EV_APPLY) - return NB_OK; - - ple = nb_running_get_entry(args->dnode, NULL, true); - - /* Start prefix entry update procedure. */ - prefix_list_entry_update_start(ple); - - ple->ge = yang_dnode_get_uint8(args->dnode, NULL); - - /* Finish prefix entry update procedure. */ - prefix_list_entry_update_finish(ple); - - return NB_OK; + return lib_prefix_list_entry_prefix_length_greater_or_equal_modify( + args); } static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy( @@ -1454,28 +1539,30 @@ static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify( const struct lyd_node *plist_dnode = yang_dnode_get_parent(args->dnode, "prefix-list"); + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return prefix_list_nb_validate_v6_af_type( plist_dnode, args->errmsg, args->errmsg_len); } - return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args); + return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify( + args); } static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy( struct nb_cb_destroy_args *args) { - int af_type; - if (args->event == NB_EV_VALIDATE) { const struct lyd_node *plist_dnode = yang_dnode_get_parent(args->dnode, "prefix-list"); - af_type = yang_dnode_get_enum(plist_dnode, "./type"); - if (af_type != YPLT_IPV6) { - snprintf(args->errmsg, args->errmsg_len, - "prefix-list type %u is mismatched.", af_type); - return NB_ERR_VALIDATION; - } - return NB_OK; + + return prefix_list_nb_validate_v6_af_type( + plist_dnode, args->errmsg, args->errmsg_len); } return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy( @@ -1490,6 +1577,17 @@ static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args) struct prefix_list_entry *ple; int type; + if (args->event == NB_EV_VALIDATE) { + if (plist_is_dup_nb(args->dnode)) { + snprintf(args->errmsg, args->errmsg_len, + "duplicated prefix list value: %s", + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + + return NB_OK; + } + if (args->event != NB_EV_APPLY) return NB_OK; @@ -1567,6 +1665,7 @@ const struct frr_yang_module_info frr_filter_info = { .cbs = { .create = lib_access_list_entry_create, .destroy = lib_access_list_entry_destroy, + .cli_cmp = access_list_cmp, .cli_show = access_list_show, } }, @@ -1690,6 +1789,7 @@ const struct frr_yang_module_info frr_filter_info = { .cbs = { .create = lib_prefix_list_entry_create, .destroy = lib_prefix_list_entry_destroy, + .cli_cmp = prefix_list_cmp, .cli_show = prefix_list_show, } }, diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 3f0179fbc1..03359f4d18 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -30,8 +30,8 @@ #include "zlog.h" #include "libfrr_trace.h" -DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread") -DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives") +DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread"); +DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives"); /* default frr_pthread start/stop routine prototypes */ static void *fpt_run(void *arg); diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c index 33adcd7b80..05f0fce5fc 100644 --- a/lib/frr_zmq.c +++ b/lib/frr_zmq.c @@ -26,7 +26,7 @@ #include "log.h" #include "lib_errors.h" -DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback") +DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback"); /* libzmq's context */ void *frrzmq_context = NULL; diff --git a/lib/frrcu.c b/lib/frrcu.c index 7e6475b648..0e717a98a5 100644 --- a/lib/frrcu.c +++ b/lib/frrcu.c @@ -54,12 +54,12 @@ #include "seqlock.h" #include "atomlist.h" -DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread") -DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier") +DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread"); +DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier"); -DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head) +DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head); -PREDECL_ATOMLIST(rcu_threads) +PREDECL_ATOMLIST(rcu_threads); struct rcu_thread { struct rcu_threads_item head; @@ -70,7 +70,7 @@ struct rcu_thread { /* only accessed by thread itself, not atomic */ unsigned depth; }; -DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head) +DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head); static const struct rcu_action rcua_next = { .type = RCUA_NEXT }; static const struct rcu_action rcua_end = { .type = RCUA_END }; diff --git a/lib/frrcu.h b/lib/frrcu.h index 47751ae7df..3808259040 100644 --- a/lib/frrcu.h +++ b/lib/frrcu.h @@ -116,7 +116,7 @@ struct rcu_action { }; /* RCU cleanup function queue item */ -PREDECL_ATOMLIST(rcu_heads) +PREDECL_ATOMLIST(rcu_heads); struct rcu_head { struct rcu_heads_item head; const struct rcu_action *action; diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index a40b815caa..209765bd6f 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -34,7 +34,7 @@ #define GRAMMAR_STR "CLI grammar sandbox\n" -DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc") +DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc"); /** headers **/ void grammar_sandbox_init(void); diff --git a/lib/graph.c b/lib/graph.c index 128e45c570..1cbe1b90f9 100644 --- a/lib/graph.c +++ b/lib/graph.c @@ -25,8 +25,8 @@ #include "memory.h" #include "buffer.h" -DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph") -DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node") +DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph"); +DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node"); struct graph *graph_new(void) { struct graph *graph = XCALLOC(MTYPE_GRAPH, sizeof(struct graph)); diff --git a/lib/hash.c b/lib/hash.c index ec616ee724..e9132f7907 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -31,9 +31,9 @@ #include "frr_pthread.h" #include "libfrr_trace.h" -DEFINE_MTYPE_STATIC(LIB, HASH, "Hash") -DEFINE_MTYPE_STATIC(LIB, HASH_BUCKET, "Hash Bucket") -DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index") +DEFINE_MTYPE_STATIC(LIB, HASH, "Hash"); +DEFINE_MTYPE_STATIC(LIB, HASH_BUCKET, "Hash Bucket"); +DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index"); static pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER; static struct list *_hashes; diff --git a/lib/hook.c b/lib/hook.c index 5a8ad00d66..895243aad7 100644 --- a/lib/hook.c +++ b/lib/hook.c @@ -23,7 +23,7 @@ #include "memory.h" #include "hook.h" -DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry") +DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry"); void _hook_register(struct hook *hook, struct hookent *stackent, void *funcptr, void *arg, bool has_arg, struct frrmod_runtime *module, diff --git a/lib/hook.h b/lib/hook.h index bef5351e90..ff3ef29fa3 100644 --- a/lib/hook.h +++ b/lib/hook.h @@ -35,10 +35,10 @@ extern "C" { * * mydaemon.h: * #include "hook.h" - * DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info)) + * DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info)); * * mydaemon.c: - * DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info)) + * DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info)); * ... * hook_call (some_update_event, info) * @@ -184,7 +184,7 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, #define HOOK_ADDARG(...) (hookarg , ## __VA_ARGS__) /* use in header file - declares the hook and its arguments - * usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2)) + * usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2)); * as above, "passlist" must use the same order and same names as "arglist" * * theoretically passlist is not neccessary, but let's keep things simple and @@ -201,7 +201,9 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, int(*funcptr) HOOK_ADDDEF arglist) \ { \ return (void *)funcptr; \ - } + } \ + MACRO_REQUIRE_SEMICOLON() /* end */ + #define DECLARE_KOOH(hookname, arglist, passlist) \ DECLARE_HOOK(hookname, arglist, passlist) @@ -230,7 +232,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, hooksum += hookp.farg HOOK_ADDARG passlist; \ } \ return hooksum; \ - } + } \ + MACRO_REQUIRE_SEMICOLON() /* end */ #define DEFINE_HOOK(hookname, arglist, passlist) \ DEFINE_HOOK_INT(hookname, arglist, passlist, false) diff --git a/lib/id_alloc.c b/lib/id_alloc.c index 95096fa5f0..9179dc4299 100644 --- a/lib/id_alloc.c +++ b/lib/id_alloc.c @@ -29,13 +29,14 @@ #include <inttypes.h> -DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR, "ID Number Allocator") -DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR_NAME, "ID Number Allocator Name") -DEFINE_MTYPE_STATIC(LIB, IDALLOC_DIRECTORY, "ID Number Allocator Directory") +DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR, "ID Number Allocator"); +DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR_NAME, "ID Number Allocator Name"); +DEFINE_MTYPE_STATIC(LIB, IDALLOC_DIRECTORY, "ID Number Allocator Directory"); DEFINE_MTYPE_STATIC(LIB, IDALLOC_SUBDIRECTORY, - "ID Number Allocator Subdirectory") -DEFINE_MTYPE_STATIC(LIB, IDALLOC_PAGE, "ID Number Allocator Page") -DEFINE_MTYPE_STATIC(LIB, IDALLOC_POOL, "ID Number temporary holding pool entry") + "ID Number Allocator Subdirectory"); +DEFINE_MTYPE_STATIC(LIB, IDALLOC_PAGE, "ID Number Allocator Page"); +DEFINE_MTYPE_STATIC(LIB, IDALLOC_POOL, + "ID Number temporary holding pool entry"); #if UINT_MAX >= UINT32_MAX #define FFS32(x) ffs(x) @@ -39,11 +39,11 @@ #include "lib/if_clippy.c" #endif -DEFINE_MTYPE_STATIC(LIB, IF, "Interface") -DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected") -DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected") -DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label") -DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters") +DEFINE_MTYPE_STATIC(LIB, IF, "Interface"); +DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected"); +DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected"); +DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label"); +DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters"); static struct interface *if_lookup_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); @@ -53,10 +53,10 @@ static int if_cmp_index_func(const struct interface *ifp1, RB_GENERATE(if_name_head, interface, name_entry, if_cmp_func); RB_GENERATE(if_index_head, interface, index_entry, if_cmp_index_func); -DEFINE_QOBJ_TYPE(interface) +DEFINE_QOBJ_TYPE(interface); -DEFINE_HOOK(if_add, (struct interface * ifp), (ifp)) -DEFINE_KOOH(if_del, (struct interface * ifp), (ifp)) +DEFINE_HOOK(if_add, (struct interface * ifp), (ifp)); +DEFINE_KOOH(if_del, (struct interface * ifp), (ifp)); static struct interface_master{ int (*create_hook)(struct interface *ifp); @@ -31,7 +31,7 @@ extern "C" { #endif -DECLARE_MTYPE(CONNECTED_LABEL) +DECLARE_MTYPE(CONNECTED_LABEL); /* Interface link-layer type, if known. Derived from: * @@ -301,14 +301,14 @@ struct interface { */ bool configured; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(if_name_head, interface); RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func) RB_HEAD(if_index_head, interface); RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_index_func) -DECLARE_QOBJ_TYPE(interface) +DECLARE_QOBJ_TYPE(interface); #define IFNAME_RB_INSERT(vrf, ifp) \ ({ \ @@ -378,8 +378,8 @@ DECLARE_QOBJ_TYPE(interface) * can use 1000+ so they run after the daemon has initialised daemon-specific * interface data */ -DECLARE_HOOK(if_add, (struct interface * ifp), (ifp)) -DECLARE_KOOH(if_del, (struct interface * ifp), (ifp)) +DECLARE_HOOK(if_add, (struct interface * ifp), (ifp)); +DECLARE_KOOH(if_del, (struct interface * ifp), (ifp)); #define METRIC_MAX (~0) diff --git a/lib/if_rmap.c b/lib/if_rmap.c index 1973d40be4..8282e476df 100644 --- a/lib/if_rmap.c +++ b/lib/if_rmap.c @@ -26,10 +26,11 @@ #include "if.h" #include "if_rmap.h" -DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container") -DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME, "Interface route map container name") -DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map") -DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name") +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container"); +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME, + "Interface route map container name"); +DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map"); +DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name"); static struct list *if_rmap_ctx_list; diff --git a/lib/keychain.c b/lib/keychain.c index 82fd6a65f2..db5c23b1ba 100644 --- a/lib/keychain.c +++ b/lib/keychain.c @@ -25,11 +25,11 @@ #include "linklist.h" #include "keychain.h" -DEFINE_MTYPE_STATIC(LIB, KEY, "Key") -DEFINE_MTYPE_STATIC(LIB, KEYCHAIN, "Key chain") +DEFINE_MTYPE_STATIC(LIB, KEY, "Key"); +DEFINE_MTYPE_STATIC(LIB, KEYCHAIN, "Key chain"); -DEFINE_QOBJ_TYPE(keychain) -DEFINE_QOBJ_TYPE(key) +DEFINE_QOBJ_TYPE(keychain); +DEFINE_QOBJ_TYPE(key); /* Master list of key chain. */ static struct list *keychain_list; diff --git a/lib/keychain.h b/lib/keychain.h index e5cf39f7c6..eb6d2f175e 100644 --- a/lib/keychain.h +++ b/lib/keychain.h @@ -32,9 +32,9 @@ struct keychain { struct list *key; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(keychain) +DECLARE_QOBJ_TYPE(keychain); struct key_range { time_t start; @@ -51,9 +51,9 @@ struct key { struct key_range send; struct key_range accept; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(key) +DECLARE_QOBJ_TYPE(key); extern void keychain_init(void); extern struct keychain *keychain_lookup(const char *); diff --git a/lib/ldp_sync.c b/lib/ldp_sync.c index c9d7eb37cf..8912d15589 100644 --- a/lib/ldp_sync.c +++ b/lib/ldp_sync.c @@ -31,7 +31,7 @@ #include "ldp_sync.h" /* Library code */ -DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info") +DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info"); /* * ldp_sync_info_create - Allocate the LDP_SYNC information diff --git a/lib/libfrr.c b/lib/libfrr.c index 51b97369c9..5b0a523fb5 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -45,10 +45,10 @@ #include "defaults.h" #include "frrscript.h" -DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) -DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm)) -DEFINE_KOOH(frr_early_fini, (), ()) -DEFINE_KOOH(frr_fini, (), ()) +DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)); +DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm)); +DEFINE_KOOH(frr_early_fini, (), ()); +DEFINE_KOOH(frr_fini, (), ()); const char frr_sysconfdir[] = SYSCONFDIR; char frr_vtydir[256]; diff --git a/lib/libfrr.h b/lib/libfrr.h index 825f502bdf..db0f364986 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -124,8 +124,8 @@ struct frr_daemon_info { __VA_ARGS__}; \ FRR_COREMOD_SETUP(.name = #execname, \ .description = #execname " daemon", \ - .version = FRR_VERSION, ) \ -/* end */ + .version = FRR_VERSION, ); \ + MACRO_REQUIRE_SEMICOLON() /* end */ extern void frr_init_vtydir(void); extern void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv); @@ -141,8 +141,8 @@ extern enum frr_cli_mode frr_get_cli_mode(void); extern uint32_t frr_get_fd_limit(void); extern bool frr_is_startup_fd(int fd); -DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) -DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm)) +DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm)); +DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm)); extern void frr_config_fork(void); extern void frr_run(struct thread_master *master); @@ -153,10 +153,10 @@ extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len, /* these two are before the protocol daemon does its own shutdown * it's named this way being the counterpart to frr_late_init */ -DECLARE_KOOH(frr_early_fini, (), ()) +DECLARE_KOOH(frr_early_fini, (), ()); extern void frr_early_fini(void); /* and these two are after the daemon did its own cleanup */ -DECLARE_KOOH(frr_fini, (), ()) +DECLARE_KOOH(frr_fini, (), ()); extern void frr_fini(void); extern char config_default[512]; diff --git a/lib/link_state.c b/lib/link_state.c index ecf0d0698d..8606f8eb09 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -33,10 +33,13 @@ #include "vty.h" #include "zclient.h" #include "stream.h" +#include "sbuf.h" +#include "printfrr.h" +#include <lib/json.h> #include "link_state.h" /* Link State Memory allocation */ -DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database") +DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database"); /** * Link State Node management functions @@ -46,7 +49,7 @@ struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid, { struct ls_node *new; - if (adv.origin == NONE) + if (adv.origin == UNKNOWN) return NULL; new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node)); @@ -70,6 +73,9 @@ struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid, void ls_node_del(struct ls_node *node) { + if (!node) + return; + XFREE(MTYPE_LS_DB, node); node = NULL; } @@ -111,7 +117,7 @@ struct ls_attributes *ls_attributes_new(struct ls_node_id adv, { struct ls_attributes *new; - if (adv.origin == NONE) + if (adv.origin == UNKNOWN) return NULL; new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes)); @@ -139,7 +145,7 @@ struct ls_attributes *ls_attributes_new(struct ls_node_id adv, return new; } -void ls_attributes_del(struct ls_attributes *attr) +void ls_attributes_srlg_del(struct ls_attributes *attr) { if (!attr) return; @@ -147,6 +153,18 @@ void ls_attributes_del(struct ls_attributes *attr) if (attr->srlgs) XFREE(MTYPE_LS_DB, attr->srlgs); + attr->srlgs = NULL; + attr->srlg_len = 0; + UNSET_FLAG(attr->flags, LS_ATTR_SRLG); +} + +void ls_attributes_del(struct ls_attributes *attr) +{ + if (!attr) + return; + + ls_attributes_srlg_del(attr); + XFREE(MTYPE_LS_DB, attr); attr = NULL; } @@ -179,75 +197,155 @@ int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2) } /** - * Link State Vertices management functions + * Link State prefix management functions */ -struct ls_vertex *ls_vertex_new(struct ls_node *node) +struct ls_prefix *ls_prefix_new(struct ls_node_id adv, struct prefix p) { - struct ls_vertex *new; + struct ls_prefix *new; - if (node == NULL) + if (adv.origin == UNKNOWN) return NULL; - new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_vertex)); - new->node = node; - new->incoming_edges = list_new(); - new->outgoing_edges = list_new(); - new->prefixes = list_new(); + new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes)); + new->adv = adv; + new->pref = p; return new; } -void ls_vertex_del(struct ls_vertex *vertex) +void ls_prefix_del(struct ls_prefix *pref) { - if (vertex == NULL) + if (!pref) return; - list_delete_all_node(vertex->incoming_edges); - list_delete_all_node(vertex->outgoing_edges); - list_delete_all_node(vertex->prefixes); - XFREE(MTYPE_LS_DB, vertex); - vertex = NULL; + XFREE(MTYPE_LS_DB, pref); + pref = NULL; } +int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2) +{ + if ((p1 && !p2) || (!p1 && p2)) + return 0; + + if (p1 == p2) + return 1; + + if (p1->flags != p2->flags) + return 0; + + if (p1->adv.origin != p2->adv.origin) + return 0; + + if (!memcmp(&p1->adv.id, &p2->adv.id, sizeof(struct ls_node_id))) + return 0; + + /* Do we need to test individually each field, instead performing a + * global memcmp? There is a risk that an old value that is bit masked + * i.e. corresponding flag = 0, will result into a false negative + */ + if (!memcmp(p1, p2, sizeof(struct ls_prefix))) + return 0; + else + return 1; +} + +/** + * Link State Vertices management functions + */ struct ls_vertex *ls_vertex_add(struct ls_ted *ted, struct ls_node *node) { struct ls_vertex *new; + uint64_t key = 0; if ((ted == NULL) || (node == NULL)) return NULL; - new = ls_vertex_new(node); - if (!new) - return NULL; - /* set Key as the IPv4/Ipv6 Router ID or ISO System ID */ switch (node->adv.origin) { case OSPFv2: case STATIC: case DIRECT: - memcpy(&new->key, &node->adv.id.ip.addr, IPV4_MAX_BYTELEN); + key = ((uint64_t)ntohl(node->adv.id.ip.addr.s_addr)) + & 0xffffffff; break; case ISIS_L1: case ISIS_L2: - memcpy(&new->key, &node->adv.id.iso.sys_id, ISO_SYS_ID_LEN); + memcpy(&key, &node->adv.id.iso.sys_id, ISO_SYS_ID_LEN); break; default: - new->key = 0; + key = 0; break; } - /* Remove Vertex if key is not set */ - if (new->key == 0) { - ls_vertex_del(new); + /* Check that key is valid */ + if (key == 0) return NULL; - } - /* Add Vertex to TED */ + /* Create Vertex and add it to the TED */ + new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_vertex)); + if (!new) + return NULL; + + new->key = key; + new->node = node; + new->status = NEW; + new->type = VERTEX; + new->incoming_edges = list_new(); + new->incoming_edges->cmp = (int (*)(void *, void *))edge_cmp; + new->outgoing_edges = list_new(); + new->outgoing_edges->cmp = (int (*)(void *, void *))edge_cmp; + new->prefixes = list_new(); + new->prefixes->cmp = (int (*)(void *, void *))subnet_cmp; vertices_add(&ted->vertices, new); return new; } +void ls_vertex_del(struct ls_ted *ted, struct ls_vertex *vertex) +{ + struct listnode *node, *nnode; + struct ls_edge *edge; + struct ls_subnet *subnet; + + if (!ted || !vertex) + return; + + /* Remove outgoing Edges and list */ + for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge)) + ls_edge_del_all(ted, edge); + list_delete(&vertex->outgoing_edges); + + /* Disconnect incoming Edges and remove list */ + for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) { + ls_disconnect(vertex, edge, false); + if (edge->source == NULL) + ls_edge_del_all(ted, edge); + } + list_delete(&vertex->incoming_edges); + + /* Remove subnet and list */ + for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet)) + ls_subnet_del_all(ted, subnet); + list_delete(&vertex->prefixes); + + /* Then remove Vertex from Link State Data Base and free memory */ + vertices_del(&ted->vertices, vertex); + XFREE(MTYPE_LS_DB, vertex); + vertex = NULL; +} + +void ls_vertex_del_all(struct ls_ted *ted, struct ls_vertex *vertex) +{ + if (!ted || !vertex) + return; + + /* First remove associated Link State Node */ + ls_node_del(vertex->node); + + /* Then, Vertex itself */ + ls_vertex_del(ted, vertex); +} + struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node) { struct ls_vertex *old; @@ -261,49 +359,46 @@ struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node) ls_node_del(old->node); old->node = node; } + old->status = UPDATE; return old; } return ls_vertex_add(ted, node); } -void ls_vertex_remove(struct ls_ted *ted, struct ls_vertex *vertex) -{ - vertices_del(&ted->vertices, vertex); - ls_vertex_del(vertex); -} - struct ls_vertex *ls_find_vertex_by_key(struct ls_ted *ted, const uint64_t key) { - struct ls_vertex node = {}; + struct ls_vertex vertex = {}; if (key == 0) return NULL; - node.key = key; - return vertices_find(&ted->vertices, &node); + vertex.key = key; + return vertices_find(&ted->vertices, &vertex); } struct ls_vertex *ls_find_vertex_by_id(struct ls_ted *ted, struct ls_node_id nid) { - struct ls_vertex node = {}; + struct ls_vertex vertex = {}; + vertex.key = 0; switch (nid.origin) { case OSPFv2: case STATIC: case DIRECT: - memcpy(&node.key, &nid.id.ip.addr, IPV4_MAX_BYTELEN); + vertex.key = + ((uint64_t)ntohl(nid.id.ip.addr.s_addr)) & 0xffffffff; break; case ISIS_L1: case ISIS_L2: - memcpy(&node.key, &nid.id.iso.sys_id, ISO_SYS_ID_LEN); + memcpy(&vertex.key, &nid.id.iso.sys_id, ISO_SYS_ID_LEN); break; default: return NULL; } - return vertices_find(&ted->vertices, &node); + return vertices_find(&ted->vertices, &vertex); } int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2) @@ -323,6 +418,49 @@ int ls_vertex_same(struct ls_vertex *v1, struct ls_vertex *v2) return ls_node_same(v1->node, v2->node); } +void ls_vertex_clean(struct ls_ted *ted, struct ls_vertex *vertex, + struct zclient *zclient) +{ + struct listnode *node, *nnode; + struct ls_edge *edge; + struct ls_subnet *subnet; + struct ls_message msg; + + /* Remove Orphan Edge ... */ + for (ALL_LIST_ELEMENTS(vertex->outgoing_edges, node, nnode, edge)) { + if (edge->status == ORPHAN) { + if (zclient) { + edge->status = DELETE; + ls_edge2msg(&msg, edge); + ls_send_msg(zclient, &msg, NULL); + } + ls_edge_del_all(ted, edge); + } + } + for (ALL_LIST_ELEMENTS(vertex->incoming_edges, node, nnode, edge)) { + if (edge->status == ORPHAN) { + if (zclient) { + edge->status = DELETE; + ls_edge2msg(&msg, edge); + ls_send_msg(zclient, &msg, NULL); + } + ls_edge_del_all(ted, edge); + } + } + + /* ... and Subnet from the Vertex */ + for (ALL_LIST_ELEMENTS(vertex->prefixes, node, nnode, subnet)) { + if (subnet->status == ORPHAN) { + if (zclient) { + subnet->status = DELETE; + ls_subnet2msg(&msg, subnet); + ls_send_msg(zclient, &msg, NULL); + } + ls_subnet_del_all(ted, subnet); + } + } +} + /** * Link State Edges management functions */ @@ -354,18 +492,18 @@ static void ls_edge_connect_to(struct ls_ted *ted, struct ls_edge *edge) vertex = ls_vertex_add(ted, node); } /* and attach the edge as source to the vertex */ - listnode_add(vertex->outgoing_edges, edge); + listnode_add_sort_nodup(vertex->outgoing_edges, edge); edge->source = vertex; /* Then search if there is a reverse Edge */ dst = ls_find_edge_by_destination(ted, edge->attributes); /* attach the destination edge to the vertex */ if (dst) { - listnode_add(vertex->incoming_edges, dst); + listnode_add_sort_nodup(vertex->incoming_edges, dst); dst->destination = vertex; /* and destination vertex to this edge */ vertex = dst->source; - listnode_add(vertex->incoming_edges, edge); + listnode_add_sort_nodup(vertex->incoming_edges, edge); edge->destination = vertex; } } @@ -374,37 +512,43 @@ struct ls_edge *ls_edge_add(struct ls_ted *ted, struct ls_attributes *attributes) { struct ls_edge *new; + uint64_t key = 0; if (attributes == NULL) return NULL; - new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge)); - new->attributes = attributes; /* Key is the IPv4 local address */ if (!IPV4_NET0(attributes->standard.local.s_addr)) - new->key = ((uint64_t)attributes->standard.local.s_addr) - & 0xffffffff; + key = ((uint64_t)ntohl(attributes->standard.local.s_addr)) + & 0xffffffff; /* or the IPv6 local address if IPv4 is not defined */ else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6)) - new->key = (uint64_t)(attributes->standard.local6.s6_addr32[0] - & 0xffffffff) - | ((uint64_t)attributes->standard.local6.s6_addr32[1] - << 32); + key = (uint64_t)(attributes->standard.local6.s6_addr32[0] + & 0xffffffff) + | ((uint64_t)attributes->standard.local6.s6_addr32[1] + << 32); /* of local identifier if no IP addresses are defined */ else if (attributes->standard.local_id != 0) - new->key = (uint64_t)( + key = (uint64_t)( (attributes->standard.local_id & 0xffffffff) | ((uint64_t)attributes->standard.remote_id << 32)); - /* Remove Edge if key is not known */ - if (new->key == 0) { - XFREE(MTYPE_LS_DB, new); + /* Check that key is valid */ + if (key == 0) + return NULL; + + /* Create Edge and add it to the TED */ + new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge)); + if (!new) return NULL; - } + new->attributes = attributes; + new->key = key; + new->status = NEW; + new->type = EDGE; edges_add(&ted->edges, new); - /* Finally, connect edge to vertices */ + /* Finally, connect Edge to Vertices */ ls_edge_connect_to(ted, new); return new; @@ -429,9 +573,10 @@ struct ls_edge *ls_find_edge_by_source(struct ls_ted *ted, if (attributes == NULL) return NULL; + edge.key = 0; /* Key is the IPv4 local address */ if (!IPV4_NET0(attributes->standard.local.s_addr)) - edge.key = ((uint64_t)attributes->standard.local.s_addr) + edge.key = ((uint64_t)ntohl(attributes->standard.local.s_addr)) & 0xffffffff; /* or the IPv6 local address if IPv4 is not defined */ else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.local6)) @@ -459,18 +604,19 @@ struct ls_edge *ls_find_edge_by_destination(struct ls_ted *ted, if (attributes == NULL) return NULL; - /* Key is the IPv4 local address */ + edge.key = 0; + /* Key is the IPv4 remote address */ if (!IPV4_NET0(attributes->standard.remote.s_addr)) - edge.key = ((uint64_t)attributes->standard.remote.s_addr) + edge.key = ((uint64_t)ntohl(attributes->standard.remote.s_addr)) & 0xffffffff; - /* or the IPv6 local address if IPv4 is not defined */ + /* or the IPv6 remote address if IPv4 is not defined */ else if (!IN6_IS_ADDR_UNSPECIFIED(&attributes->standard.remote6)) edge.key = (uint64_t)(attributes->standard.remote6.s6_addr32[0] & 0xffffffff) | ((uint64_t)attributes->standard.remote6.s6_addr32[1] << 32); - /* of local identifier if no IP addresses are defined */ + /* of remote identifier if no IP addresses are defined */ else if (attributes->standard.remote_id != 0) edge.key = (uint64_t)( (attributes->standard.remote_id & 0xffffffff) @@ -498,6 +644,7 @@ struct ls_edge *ls_edge_update(struct ls_ted *ted, ls_attributes_del(old->attributes); old->attributes = attributes; } + old->status = UPDATE; return old; } @@ -505,15 +652,46 @@ struct ls_edge *ls_edge_update(struct ls_ted *ted, return ls_edge_add(ted, attributes); } +int ls_edge_same(struct ls_edge *e1, struct ls_edge *e2) +{ + if ((e1 && !e2) || (!e1 && e2)) + return 0; + + if (!e1 && !e2) + return 1; + + if (e1->key != e2->key) + return 0; + + if (e1->attributes == e2->attributes) + return 1; + + return ls_attributes_same(e1->attributes, e2->attributes); +} + void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge) { - /* Fist disconnect Edge */ + if (!ted || !edge) + return; + + /* Fist disconnect Edge from Vertices */ ls_disconnect_edge(edge); /* Then remove it from the Data Base */ edges_del(&ted->edges, edge); XFREE(MTYPE_LS_DB, edge); } +void ls_edge_del_all(struct ls_ted *ted, struct ls_edge *edge) +{ + if (!ted || !edge) + return; + + /* Remove associated Link State Attributes */ + ls_attributes_del(edge->attributes); + /* Then Edge itself */ + ls_edge_del(ted, edge); +} + /** * Link State Subnet Management functions. */ @@ -531,6 +709,8 @@ struct ls_subnet *ls_subnet_add(struct ls_ted *ted, new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_subnet)); new->ls_pref = ls_pref; new->key = ls_pref->pref; + new->status = NEW; + new->type = SUBNET; /* Find Vertex */ vertex = ls_find_vertex_by_id(ted, ls_pref->adv); @@ -541,19 +721,73 @@ struct ls_subnet *ls_subnet_add(struct ls_ted *ted, } /* And attach the subnet to the corresponding Vertex */ new->vertex = vertex; - listnode_add(vertex->prefixes, new); + listnode_add_sort_nodup(vertex->prefixes, new); subnets_add(&ted->subnets, new); return new; } +struct ls_subnet *ls_subnet_update(struct ls_ted *ted, struct ls_prefix *pref) +{ + struct ls_subnet *old; + + if (pref == NULL) + return NULL; + + old = ls_find_subnet(ted, pref->pref); + if (old) { + if (!ls_prefix_same(old->ls_pref, pref)) { + ls_prefix_del(old->ls_pref); + old->ls_pref = pref; + } + old->status = UPDATE; + return old; + } + + return ls_subnet_add(ted, pref); +} + +int ls_subnet_same(struct ls_subnet *s1, struct ls_subnet *s2) +{ + if ((s1 && !s2) || (!s1 && s2)) + return 0; + + if (!s1 && !s2) + return 1; + + if (!prefix_same(&s1->key, &s2->key)) + return 0; + + if (s1->ls_pref == s2->ls_pref) + return 1; + + return ls_prefix_same(s1->ls_pref, s2->ls_pref); +} + void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet) { + if (!ted || !subnet) + return; + + /* First, disconnect Subnet from associated Vertex */ + listnode_delete(subnet->vertex->prefixes, subnet); + /* Then delete Subnet */ subnets_del(&ted->subnets, subnet); XFREE(MTYPE_LS_DB, subnet); } +void ls_subnet_del_all(struct ls_ted *ted, struct ls_subnet *subnet) +{ + if (!ted || !subnet) + return; + + /* First, remove associated Link State Subnet */ + ls_prefix_del(subnet->ls_pref); + /* Then, delete Subnet itself */ + ls_subnet_del(ted, subnet); +} + struct ls_subnet *ls_find_subnet(struct ls_ted *ted, const struct prefix prefix) { struct ls_subnet subnet = {}; @@ -592,6 +826,11 @@ void ls_ted_del(struct ls_ted *ted) if (ted == NULL) return; + /* Check that TED is empty */ + if (vertices_count(&ted->vertices) || edges_count(&ted->edges) + || subnets_count(&ted->subnets)) + return; + /* Release RB Tree */ vertices_fini(&ted->vertices); edges_fini(&ted->edges); @@ -601,16 +840,63 @@ void ls_ted_del(struct ls_ted *ted) ted = NULL; } +void ls_ted_del_all(struct ls_ted *ted) +{ + struct ls_vertex *vertex; + struct ls_edge *edge; + struct ls_subnet *subnet; + + if (ted == NULL) + return; + + /* First remove Vertices, Edges and Subnets and associated Link State */ + frr_each (vertices, &ted->vertices, vertex) + ls_vertex_del_all(ted, vertex); + frr_each (edges, &ted->edges, edge) + ls_edge_del_all(ted, edge); + frr_each (subnets, &ted->subnets, subnet) + ls_subnet_del_all(ted, subnet); + + /* then remove TED itself */ + ls_ted_del(ted); +} + +void ls_ted_clean(struct ls_ted *ted) +{ + struct ls_vertex *vertex; + struct ls_edge *edge; + struct ls_subnet *subnet; + + if (ted == NULL) + return; + + /* First, start with Vertices */ + frr_each (vertices, &ted->vertices, vertex) + if (vertex->status == ORPHAN) + ls_vertex_del_all(ted, vertex); + + /* Then Edges */ + frr_each (edges, &ted->edges, edge) + if (edge->status == ORPHAN) + ls_edge_del_all(ted, edge); + + /* and Subnets */ + frr_each (subnets, &ted->subnets, subnet) + if (subnet->status == ORPHAN) + ls_subnet_del_all(ted, subnet); + +} + void ls_connect(struct ls_vertex *vertex, struct ls_edge *edge, bool source) { if (vertex == NULL || edge == NULL) return; if (source) { - listnode_add(vertex->outgoing_edges, edge); + listnode_add_sort_nodup(vertex->outgoing_edges, edge); edge->source = vertex; } else { - listnode_add(vertex->incoming_edges, edge); + listnode_add_sort_nodup(vertex->incoming_edges, edge); edge->destination = vertex; } } @@ -640,11 +926,10 @@ void ls_connect_vertices(struct ls_vertex *src, struct ls_vertex *dst, edge->destination = dst; if (src != NULL) - listnode_add(src->outgoing_edges, edge); + listnode_add_sort_nodup(src->outgoing_edges, edge); if (dst != NULL) - listnode_add(dst->incoming_edges, edge); - + listnode_add_sort_nodup(dst->incoming_edges, edge); } void ls_disconnect_edge(struct ls_edge *edge) @@ -654,12 +939,68 @@ void ls_disconnect_edge(struct ls_edge *edge) ls_disconnect(edge->source, edge, true); ls_disconnect(edge->destination, edge, false); + + /* Mark this Edge as ORPHAN for future cleanup */ + edge->status = ORPHAN; } /** * Link State Message management functions */ +int ls_register(struct zclient *zclient, bool server) +{ + int rc; + + if (server) + rc = zclient_register_opaque(zclient, LINK_STATE_SYNC); + else + rc = zclient_register_opaque(zclient, LINK_STATE_UPDATE); + + return rc; +} + +int ls_unregister(struct zclient *zclient, bool server) +{ + int rc; + + if (server) + rc = zclient_unregister_opaque(zclient, LINK_STATE_SYNC); + else + rc = zclient_unregister_opaque(zclient, LINK_STATE_UPDATE); + + return rc; +} + +int ls_request_sync(struct zclient *zclient) +{ + struct stream *s; + uint16_t flags = 0; + + /* Check buffer size */ + if (STREAM_SIZE(zclient->obuf) + < (ZEBRA_HEADER_SIZE + 3 * sizeof(uint32_t))) + return -1; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); + + /* Set type and flags */ + stream_putl(s, LINK_STATE_SYNC); + stream_putw(s, flags); + /* Send destination client info */ + stream_putc(s, zclient->redist_default); + stream_putw(s, zclient->instance); + stream_putl(s, zclient->session_id); + + /* Put length into the header at the start of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + static struct ls_node *ls_parse_node(struct stream *s) { struct ls_node *node; @@ -723,7 +1064,7 @@ static struct ls_attributes *ls_parse_attributes(struct stream *s) STREAM_GET(attr->name, s, len); } if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC)) - STREAM_GETL(s, attr->standard.metric); + STREAM_GETL(s, attr->metric); if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) STREAM_GETL(s, attr->standard.te_metric); if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) @@ -804,7 +1145,7 @@ static struct ls_attributes *ls_parse_attributes(struct stream *s) stream_failure: zlog_err("LS(%s): Could not parse Link State Attributes. Abort!", __func__); - /* Clean memeory allocation */ + /* Clean memory allocation */ if (attr->srlgs != NULL) XFREE(MTYPE_LS_DB, attr->srlgs); XFREE(MTYPE_LS_DB, attr); @@ -947,7 +1288,7 @@ static int ls_format_attributes(struct stream *s, struct ls_attributes *attr) stream_putc(s, '\0'); } if (CHECK_FLAG(attr->flags, LS_ATTR_METRIC)) - stream_putl(s, attr->standard.metric); + stream_putl(s, attr->metric); if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) stream_putl(s, attr->standard.te_metric); if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) @@ -1084,6 +1425,10 @@ int ls_send_msg(struct zclient *zclient, struct ls_message *msg, struct stream *s; uint16_t flags = 0; + /* Check if we have a valid message */ + if (msg->event == LS_MSG_EVENT_UNDEF) + return -1; + /* Check buffer size */ if (STREAM_SIZE(zclient->obuf) < (ZEBRA_HEADER_SIZE + sizeof(uint32_t) + sizeof(msg))) @@ -1094,7 +1439,7 @@ int ls_send_msg(struct zclient *zclient, struct ls_message *msg, zclient_create_header(s, ZEBRA_OPAQUE_MESSAGE, VRF_DEFAULT); - /* Send sub-type, flags and destination for unicast message */ + /* Set sub-type, flags and destination for unicast message */ stream_putl(s, LINK_STATE_UPDATE); if (dst != NULL) { SET_FLAG(flags, ZAPI_OPAQUE_FLAG_UNICAST); @@ -1103,8 +1448,9 @@ int ls_send_msg(struct zclient *zclient, struct ls_message *msg, stream_putc(s, dst->proto); stream_putw(s, dst->instance); stream_putl(s, dst->session_id); - } else + } else { stream_putw(s, flags); + } /* Format Link State message */ if (ls_format_msg(s, msg) < 0) { @@ -1128,8 +1474,25 @@ struct ls_message *ls_vertex2msg(struct ls_message *msg, memset(msg, 0, sizeof(*msg)); msg->type = LS_MSG_TYPE_NODE; + switch (vertex->status) { + case NEW: + msg->event = LS_MSG_EVENT_ADD; + break; + case UPDATE: + msg->event = LS_MSG_EVENT_UPDATE; + break; + case DELETE: + msg->event = LS_MSG_EVENT_DELETE; + break; + case SYNC: + msg->event = LS_MSG_EVENT_SYNC; + break; + default: + msg->event = LS_MSG_EVENT_UNDEF; + break; + } msg->data.node = vertex->node; - msg->remote_id.origin = NONE; + msg->remote_id.origin = UNKNOWN; return msg; } @@ -1143,11 +1506,28 @@ struct ls_message *ls_edge2msg(struct ls_message *msg, struct ls_edge *edge) memset(msg, 0, sizeof(*msg)); msg->type = LS_MSG_TYPE_ATTRIBUTES; + switch (edge->status) { + case NEW: + msg->event = LS_MSG_EVENT_ADD; + break; + case UPDATE: + msg->event = LS_MSG_EVENT_UPDATE; + break; + case DELETE: + msg->event = LS_MSG_EVENT_DELETE; + break; + case SYNC: + msg->event = LS_MSG_EVENT_SYNC; + break; + default: + msg->event = LS_MSG_EVENT_UNDEF; + break; + } msg->data.attr = edge->attributes; if (edge->destination != NULL) msg->remote_id = edge->destination->node->adv; else - msg->remote_id.origin = NONE; + msg->remote_id.origin = UNKNOWN; return msg; } @@ -1162,34 +1542,189 @@ struct ls_message *ls_subnet2msg(struct ls_message *msg, memset(msg, 0, sizeof(*msg)); msg->type = LS_MSG_TYPE_PREFIX; + switch (subnet->status) { + case NEW: + msg->event = LS_MSG_EVENT_ADD; + break; + case UPDATE: + msg->event = LS_MSG_EVENT_UPDATE; + break; + case DELETE: + msg->event = LS_MSG_EVENT_DELETE; + break; + case SYNC: + msg->event = LS_MSG_EVENT_SYNC; + break; + default: + msg->event = LS_MSG_EVENT_UNDEF; + break; + } msg->data.prefix = subnet->ls_pref; - msg->remote_id.origin = NONE; + msg->remote_id.origin = UNKNOWN; return msg; } -void ls_delete_msg(struct ls_message *msg) +struct ls_vertex *ls_msg2vertex(struct ls_ted *ted, struct ls_message *msg, + bool delete) { - if (msg == NULL) - return; + struct ls_node *node = (struct ls_node *)msg->data.node; + struct ls_vertex *vertex = NULL; + + switch (msg->event) { + case LS_MSG_EVENT_SYNC: + vertex = ls_vertex_add(ted, node); + if (vertex) + vertex->status = SYNC; + break; + case LS_MSG_EVENT_ADD: + vertex = ls_vertex_add(ted, node); + if (vertex) + vertex->status = NEW; + break; + case LS_MSG_EVENT_UPDATE: + vertex = ls_vertex_update(ted, node); + if (vertex) + vertex->status = UPDATE; + break; + case LS_MSG_EVENT_DELETE: + vertex = ls_find_vertex_by_id(ted, node->adv); + if (vertex) { + if (delete) + ls_vertex_del_all(ted, vertex); + else + vertex->status = DELETE; + } + break; + default: + vertex = NULL; + break; + } + + return vertex; +} + +struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg, + bool delete) +{ + struct ls_attributes *attr = (struct ls_attributes *)msg->data.attr; + struct ls_edge *edge = NULL; + + switch (msg->event) { + case LS_MSG_EVENT_SYNC: + edge = ls_edge_add(ted, attr); + if (edge) + edge->status = SYNC; + break; + case LS_MSG_EVENT_ADD: + edge = ls_edge_add(ted, attr); + if (edge) + edge->status = NEW; + break; + case LS_MSG_EVENT_UPDATE: + edge = ls_edge_update(ted, attr); + if (edge) + edge->status = UPDATE; + break; + case LS_MSG_EVENT_DELETE: + edge = ls_find_edge_by_source(ted, attr); + if (edge) { + if (delete) + ls_edge_del_all(ted, edge); + else + edge->status = DELETE; + } + break; + default: + edge = NULL; + break; + } + + return edge; +} + +struct ls_subnet *ls_msg2subnet(struct ls_ted *ted, struct ls_message *msg, + bool delete) +{ + struct ls_prefix *pref = (struct ls_prefix *)msg->data.prefix; + struct ls_subnet *subnet = NULL; + + switch (msg->event) { + case LS_MSG_EVENT_SYNC: + subnet = ls_subnet_add(ted, pref); + if (subnet) + subnet->status = SYNC; + break; + case LS_MSG_EVENT_ADD: + subnet = ls_subnet_add(ted, pref); + if (subnet) + subnet->status = NEW; + break; + case LS_MSG_EVENT_UPDATE: + subnet = ls_subnet_update(ted, pref); + if (subnet) + subnet->status = UPDATE; + break; + case LS_MSG_EVENT_DELETE: + subnet = ls_find_subnet(ted, pref->pref); + if (subnet) { + if (delete) + ls_subnet_del_all(ted, subnet); + else + subnet->status = DELETE; + } + break; + default: + subnet = NULL; + break; + } + + return subnet; +} + +struct ls_element *ls_msg2ted(struct ls_ted *ted, struct ls_message *msg, + bool delete) +{ + struct ls_element *lse = NULL; switch (msg->type) { case LS_MSG_TYPE_NODE: - if (msg->data.node) - XFREE(MTYPE_LS_DB, msg->data.node); + lse = (struct ls_element *)ls_msg2vertex(ted, msg, delete); break; case LS_MSG_TYPE_ATTRIBUTES: - if (msg->data.attr) - XFREE(MTYPE_LS_DB, msg->data.attr); + lse = (struct ls_element *)ls_msg2edge(ted, msg, delete); break; case LS_MSG_TYPE_PREFIX: - if (msg->data.prefix) - XFREE(MTYPE_LS_DB, msg->data.prefix); + lse = (struct ls_element *)ls_msg2subnet(ted, msg, delete); break; default: + lse = NULL; break; } + return lse; +} + +struct ls_element *ls_stream2ted(struct ls_ted *ted, struct stream *s, + bool delete) +{ + struct ls_message *msg; + struct ls_element *lse = NULL; + + msg = ls_parse_msg(s); + if (msg) { + lse = ls_msg2ted(ted, msg, delete); + ls_delete_msg(msg); + } + + return lse; +} + +void ls_delete_msg(struct ls_message *msg) +{ + if (msg == NULL) + return; + XFREE(MTYPE_LS_DB, msg); } @@ -1201,9 +1736,6 @@ int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient, struct ls_subnet *subnet; struct ls_message msg; - /* Prepare message */ - msg.event = LS_MSG_EVENT_SYNC; - /* Loop TED, start sending Node, then Attributes and finally Prefix */ frr_each(vertices, &ted->vertices, vertex) { ls_vertex2msg(&msg, vertex); @@ -1220,33 +1752,696 @@ int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient, return 0; } +/** + * Link State Show functions + */ +static const char *const origin2txt[] = { + "Unknown", + "ISIS_L1", + "ISIS_L2", + "OSPFv2", + "Direct", + "Static" +}; + +static const char *const type2txt[] = { + "Unknown", + "Standard", + "ABR", + "ASBR", + "Remote ASBR", + "Pseudo" +}; + +static const char *const status2txt[] = { + "Unknown", + "New", + "Update", + "Delete", + "Sync", + "Orphan" +}; + +static const char *ls_node_id_to_text(struct ls_node_id lnid, char *str, + size_t size) +{ + if (lnid.origin == ISIS_L1 || lnid.origin == ISIS_L2) { + uint8_t *id; + + id = lnid.id.iso.sys_id; + snprintfrr(str, size, "%02x%02x.%02x%02x.%02x%02x", id[0], + id[1], id[2], id[3], id[4], id[5]); + } else + snprintfrr(str, size, "%pI4", &lnid.id.ip.addr); + + return str; +} + +static void ls_show_vertex_vty(struct ls_vertex *vertex, struct vty *vty, + bool verbose) +{ + struct listnode *node; + struct ls_node *lsn; + struct ls_edge *edge; + struct ls_subnet *subnet; + struct sbuf sbuf; + uint32_t upper; + + /* Sanity Check */ + if (!vertex) + return; + + lsn = vertex->node; + + sbuf_init(&sbuf, NULL, 0); + + sbuf_push(&sbuf, 2, "Vertex (%" PRIu64 "): %s", vertex->key, lsn->name); + sbuf_push(&sbuf, 0, "\tRouter Id: %pI4", &lsn->router_id); + sbuf_push(&sbuf, 0, "\tOrigin: %s", origin2txt[lsn->adv.origin]); + sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[vertex->status]); + if (!verbose) { + sbuf_push( + &sbuf, 0, + "\t%d Outgoing Edges, %d Incoming Edges, %d Subnets\n", + listcount(vertex->outgoing_edges), + listcount(vertex->incoming_edges), + listcount(vertex->prefixes)); + goto end; + } + + if (CHECK_FLAG(lsn->flags, LS_NODE_TYPE)) + sbuf_push(&sbuf, 4, "Type: %s\n", type2txt[lsn->type]); + if (CHECK_FLAG(lsn->flags, LS_NODE_AS_NUMBER)) + sbuf_push(&sbuf, 4, "AS number: %u\n", lsn->as_number); + if (CHECK_FLAG(lsn->flags, LS_NODE_SR)) { + sbuf_push(&sbuf, 4, "Segment Routing Capabilities:\n"); + upper = lsn->srgb.lower_bound + lsn->srgb.range_size - 1; + sbuf_push(&sbuf, 8, "SRGB: [%d/%d]", lsn->srgb.lower_bound, + upper); + if (CHECK_FLAG(lsn->flags, LS_NODE_SRLB)) { + upper = lsn->srlb.lower_bound + lsn->srlb.range_size + - 1; + sbuf_push(&sbuf, 0, "\tSRLB: [%d/%d]", + lsn->srlb.lower_bound, upper); + } + sbuf_push(&sbuf, 0, "\tAlgo: "); + for (int i = 0; i < 2; i++) { + if (lsn->algo[i] == 255) + continue; + + sbuf_push(&sbuf, 0, + lsn->algo[i] == 0 ? "SPF " : "S-SPF "); + } + if (CHECK_FLAG(lsn->flags, LS_NODE_MSD)) + sbuf_push(&sbuf, 0, "\tMSD: %d", lsn->msd); + sbuf_push(&sbuf, 0, "\n"); + } + + sbuf_push(&sbuf, 4, "Outgoing Edges: %d\n", + listcount(vertex->outgoing_edges)); + for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) { + if (edge->destination) { + lsn = edge->destination->node; + sbuf_push(&sbuf, 6, "To:\t%s(%pI4)", lsn->name, + &lsn->router_id); + } else { + sbuf_push(&sbuf, 6, "To:\t- (0.0.0.0)"); + } + sbuf_push(&sbuf, 0, "\tLocal: %pI4\tRemote: %pI4\n", + &edge->attributes->standard.local, + &edge->attributes->standard.remote); + } + + sbuf_push(&sbuf, 4, "Incoming Edges: %d\n", + listcount(vertex->incoming_edges)); + for (ALL_LIST_ELEMENTS_RO(vertex->incoming_edges, node, edge)) { + if (edge->source) { + lsn = edge->source->node; + sbuf_push(&sbuf, 6, "From:\t%s(%pI4)", lsn->name, + &lsn->router_id); + } else { + sbuf_push(&sbuf, 6, "From:\t- (0.0.0.0)"); + } + sbuf_push(&sbuf, 0, "\tRemote: %pI4\tLocal: %pI4\n", + &edge->attributes->standard.local, + &edge->attributes->standard.remote); + } + + sbuf_push(&sbuf, 4, "Subnets: %d\n", listcount(vertex->prefixes)); + for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet)) + sbuf_push(&sbuf, 6, "Prefix:\t%pFX\n", &subnet->key); + +end: + vty_out(vty, "%s\n", sbuf_buf(&sbuf)); + sbuf_free(&sbuf); +} + +static void ls_show_vertex_json(struct ls_vertex *vertex, + struct json_object *json) +{ + struct ls_node *lsn; + json_object *jsr, *jalgo, *jobj; + char buf[INET6_BUFSIZ]; + + /* Sanity Check */ + if (!vertex) + return; + + lsn = vertex->node; + + json_object_int_add(json, "vertex-id", vertex->key); + json_object_string_add(json, "status", status2txt[vertex->status]); + json_object_string_add(json, "origin", origin2txt[lsn->adv.origin]); + if (CHECK_FLAG(lsn->flags, LS_NODE_NAME)) + json_object_string_add(json, "name", lsn->name); + if (CHECK_FLAG(lsn->flags, LS_NODE_ROUTER_ID)) { + snprintfrr(buf, INET6_BUFSIZ, "%pI4", &lsn->router_id); + json_object_string_add(json, "router-id", buf); + } + if (CHECK_FLAG(lsn->flags, LS_NODE_ROUTER_ID6)) { + snprintfrr(buf, INET6_BUFSIZ, "%pI6", &lsn->router6_id); + json_object_string_add(json, "router-id-v6", buf); + } + if (CHECK_FLAG(lsn->flags, LS_NODE_TYPE)) + json_object_string_add(json, "vertex-type", + type2txt[lsn->type]); + if (CHECK_FLAG(lsn->flags, LS_NODE_AS_NUMBER)) + json_object_int_add(json, "asn", lsn->as_number); + if (CHECK_FLAG(lsn->flags, LS_NODE_SR)) { + jsr = json_object_new_object(); + json_object_object_add(json, "segment-routing", jsr); + json_object_int_add(jsr, "srgb-size", lsn->srgb.range_size); + json_object_int_add(jsr, "srgb-lower", lsn->srgb.lower_bound); + jalgo = json_object_new_array(); + json_object_object_add(jsr, "algorithms", jalgo); + for (int i = 0; i < 2; i++) { + if (lsn->algo[i] == 255) + continue; + jobj = json_object_new_object(); + + snprintfrr(buf, 2, "%u", i); + json_object_string_add( + jobj, buf, lsn->algo[i] == 0 ? "SPF" : "S-SPF"); + json_object_array_add(jalgo, jobj); + } + if (CHECK_FLAG(lsn->flags, LS_NODE_SRLB)) { + json_object_int_add(jsr, "srlb-size", + lsn->srlb.range_size); + json_object_int_add(jsr, "srlb-lower", + lsn->srlb.lower_bound); + } + if (CHECK_FLAG(lsn->flags, LS_NODE_MSD)) + json_object_int_add(jsr, "msd", lsn->msd); + } +} + +void ls_show_vertex(struct ls_vertex *vertex, struct vty *vty, + struct json_object *json, bool verbose) +{ + if (json) + ls_show_vertex_json(vertex, json); + else if (vty) + ls_show_vertex_vty(vertex, vty, verbose); +} + +void ls_show_vertices(struct ls_ted *ted, struct vty *vty, + struct json_object *json, bool verbose) +{ + struct ls_vertex *vertex; + json_object *jnodes, *jnode; + + if (json) { + jnodes = json_object_new_array(); + json_object_object_add(json, "vertices", jnodes); + frr_each (vertices, &ted->vertices, vertex) { + jnode = json_object_new_object(); + ls_show_vertex(vertex, NULL, jnode, verbose); + json_object_array_add(jnodes, jnode); + } + } else if (vty) { + frr_each (vertices, &ted->vertices, vertex) + ls_show_vertex(vertex, vty, NULL, verbose); + } +} + +static void ls_show_edge_vty(struct ls_edge *edge, struct vty *vty, + bool verbose) +{ + struct ls_attributes *attr; + struct sbuf sbuf; + char buf[INET6_BUFSIZ]; + + attr = edge->attributes; + sbuf_init(&sbuf, NULL, 0); + + sbuf_push(&sbuf, 2, "Edge (%" PRIu64 "): ", edge->key); + if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) + sbuf_push(&sbuf, 0, "%pI4", &attr->standard.local); + else if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) + sbuf_push(&sbuf, 0, "%pI6", &attr->standard.local6); + else + sbuf_push(&sbuf, 0, "%u/%u", attr->standard.local_id, + attr->standard.remote_id); + ls_node_id_to_text(attr->adv, buf, INET6_BUFSIZ); + sbuf_push(&sbuf, 0, "\tAdv. Vertex: %s", buf); + sbuf_push(&sbuf, 0, "\tMetric: %u", attr->metric); + sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[edge->status]); + + if (!verbose) + goto end; + + sbuf_push(&sbuf, 4, "Origin: %s\n", origin2txt[attr->adv.origin]); + if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) + sbuf_push(&sbuf, 4, "Name: %s\n", attr->name); + if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) + sbuf_push(&sbuf, 4, "TE Metric: %u\n", + attr->standard.te_metric); + if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) + sbuf_push(&sbuf, 4, "Admin Group: 0x%x\n", + attr->standard.admin_group); + if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) + sbuf_push(&sbuf, 4, "Local IPv4 address: %pI4\n", + &attr->standard.local); + if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) + sbuf_push(&sbuf, 4, "Remote IPv4 address: %pI4\n", + &attr->standard.remote); + if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) + sbuf_push(&sbuf, 4, "Local IPv6 address: %pI6\n", + &attr->standard.local6); + if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6)) + sbuf_push(&sbuf, 4, "Remote IPv6 address: %pI6\n", + &attr->standard.remote6); + if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID)) + sbuf_push(&sbuf, 4, "Local Identifier: %u\n", + attr->standard.local_id); + if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID)) + sbuf_push(&sbuf, 4, "Remote Identifier: %u\n", + attr->standard.remote_id); + if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW)) + sbuf_push(&sbuf, 4, "Maximum Bandwidth: %g (Bytes/s)\n", + attr->standard.max_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW)) + sbuf_push(&sbuf, 4, + "Maximum Reservable Bandwidth: %g (Bytes/s)\n", + attr->standard.max_rsv_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW)) { + sbuf_push(&sbuf, 4, "Unreserved Bandwidth per Class Type\n"); + for (int i = 0; i < MAX_CLASS_TYPE; i += 2) + sbuf_push(&sbuf, 8, + "[%d]: %g (Bytes/sec)\t[%d]: %g (Bytes/s)\n", + i, attr->standard.unrsv_bw[i], i + 1, + attr->standard.unrsv_bw[i + 1]); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS)) + sbuf_push(&sbuf, 4, "Remote AS: %u\n", + attr->standard.remote_as); + if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR)) + sbuf_push(&sbuf, 4, "Remote ASBR IPv4 address: %pI4\n", + &attr->standard.remote_addr); + if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6)) + sbuf_push(&sbuf, 4, "Remote ASBR IPv6 address: %pI6\n", + &attr->standard.remote_addr6); + if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY)) + sbuf_push(&sbuf, 4, "Average Link Delay: %d (micro-sec)\n", + attr->extended.delay); + if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) + sbuf_push(&sbuf, 4, "Min/Max Link Delay: %d/%d (micro-sec)\n", + attr->extended.min_delay, attr->extended.max_delay); + if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER)) + sbuf_push(&sbuf, 4, "Delay Variation: %d (micro-sec)\n", + attr->extended.jitter); + if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS)) + sbuf_push(&sbuf, 4, "Link Loss: %g (%%)\n", + (float)(attr->extended.pkt_loss * LOSS_PRECISION)); + if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW)) + sbuf_push(&sbuf, 4, "Available Bandwidth: %g (Bytes/s)\n", + attr->extended.ava_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW)) + sbuf_push(&sbuf, 4, "Residual Bandwidth: %g (Bytes/s)\n", + attr->extended.rsv_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW)) + sbuf_push(&sbuf, 4, "Utilized Bandwidth: %g (Bytes/s)\n", + attr->extended.used_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) { + sbuf_push(&sbuf, 4, "Adjacency-SID: %u", attr->adj_sid[0].sid); + sbuf_push(&sbuf, 0, "\tFlags: 0x%x\tWeight: 0x%x\n", + attr->adj_sid[0].flags, attr->adj_sid[0].weight); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) { + sbuf_push(&sbuf, 4, "Bck. Adjacency-SID: %u", + attr->adj_sid[1].sid); + sbuf_push(&sbuf, 0, "\tFlags: 0x%x\tWeight: 0x%x\n", + attr->adj_sid[1].flags, attr->adj_sid[1].weight); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { + sbuf_push(&sbuf, 4, "SRLGs: %d", attr->srlg_len); + for (int i = 1; i < attr->srlg_len; i++) { + if (i % 8) + sbuf_push(&sbuf, 8, "\n%u", attr->srlgs[i]); + else + sbuf_push(&sbuf, 8, ", %u", attr->srlgs[i]); + } + sbuf_push(&sbuf, 0, "\n"); + } + +end: + vty_out(vty, "%s\n", sbuf_buf(&sbuf)); + sbuf_free(&sbuf); +} + +static void ls_show_edge_json(struct ls_edge *edge, struct json_object *json) +{ + struct ls_attributes *attr; + struct json_object *jte, *jbw, *jobj, *jsr = NULL, *jsrlg; + char buf[INET6_BUFSIZ]; + + attr = edge->attributes; + + json_object_int_add(json, "edge-id", edge->key); + json_object_string_add(json, "status", status2txt[edge->status]); + json_object_string_add(json, "origin", origin2txt[attr->adv.origin]); + ls_node_id_to_text(attr->adv, buf, INET6_BUFSIZ); + json_object_string_add(json, "advertised-router", buf); + if (edge->source) + json_object_int_add(json, "local-vertex-id", edge->source->key); + if (edge->destination) + json_object_int_add(json, "remote-vertex-id", + edge->destination->key); + json_object_int_add(json, "metric", attr->metric); + if (CHECK_FLAG(attr->flags, LS_ATTR_NAME)) + json_object_string_add(json, "name", attr->name); + jte = json_object_new_object(); + json_object_object_add(json, "edge-attributes", jte); + if (CHECK_FLAG(attr->flags, LS_ATTR_TE_METRIC)) + json_object_int_add(jte, "te-metric", attr->standard.te_metric); + if (CHECK_FLAG(attr->flags, LS_ATTR_ADM_GRP)) + json_object_int_add(jte, "admin-group", + attr->standard.admin_group); + if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR)) { + snprintfrr(buf, INET6_BUFSIZ, "%pI4", &attr->standard.local); + json_object_string_add(jte, "local-address", buf); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR)) { + snprintfrr(buf, INET6_BUFSIZ, "%pI4", &attr->standard.remote); + json_object_string_add(jte, "remote-address", buf); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ADDR6)) { + snprintfrr(buf, INET6_BUFSIZ, "%pI6", &attr->standard.local6); + json_object_string_add(jte, "local-address-v6", buf); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ADDR6)) { + snprintfrr(buf, INET6_BUFSIZ, "%pI6", &attr->standard.remote6); + json_object_string_add(jte, "remote-address-v6", buf); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_LOCAL_ID)) + json_object_int_add(jte, "local-identifier", + attr->standard.local_id); + if (CHECK_FLAG(attr->flags, LS_ATTR_NEIGH_ID)) + json_object_int_add(jte, "remote-identifier", + attr->standard.remote_id); + if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_BW)) + json_object_double_add(jte, "max-link-bandwidth", + attr->standard.max_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_MAX_RSV_BW)) + json_object_double_add(jte, "max-resv-link-bandwidth", + attr->standard.max_rsv_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_UNRSV_BW)) { + jbw = json_object_new_array(); + json_object_object_add(jte, "unreserved-bandwidth", jbw); + for (int i = 0; i < MAX_CLASS_TYPE; i++) { + jobj = json_object_new_object(); + snprintfrr(buf, 13, "class-type-%u", i); + json_object_double_add(jobj, buf, + attr->standard.unrsv_bw[i]); + json_object_array_add(jbw, jobj); + } + } + if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_AS)) + json_object_int_add(jte, "remote-asn", + attr->standard.remote_as); + if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR)) { + snprintfrr(buf, INET6_BUFSIZ, "%pI4", + &attr->standard.remote_addr); + json_object_string_add(jte, "remote-as-address", buf); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_REMOTE_ADDR6)) { + snprintfrr(buf, INET6_BUFSIZ, "%pI6", + &attr->standard.remote_addr6); + json_object_string_add(jte, "remote-as-address-v6", buf); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_DELAY)) + json_object_int_add(jte, "delay", attr->extended.delay); + if (CHECK_FLAG(attr->flags, LS_ATTR_MIN_MAX_DELAY)) { + json_object_int_add(jte, "min-delay", attr->extended.min_delay); + json_object_int_add(jte, "max-delay", attr->extended.max_delay); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_JITTER)) + json_object_int_add(jte, "jitter", attr->extended.jitter); + if (CHECK_FLAG(attr->flags, LS_ATTR_PACKET_LOSS)) + json_object_double_add( + jte, "loss", attr->extended.pkt_loss * LOSS_PRECISION); + if (CHECK_FLAG(attr->flags, LS_ATTR_AVA_BW)) + json_object_double_add(jte, "available-bandwidth", + attr->extended.ava_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_RSV_BW)) + json_object_double_add(jte, "residual-bandwidth", + attr->extended.rsv_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_USE_BW)) + json_object_double_add(jte, "utilized-bandwidth", + attr->extended.used_bw); + if (CHECK_FLAG(attr->flags, LS_ATTR_SRLG)) { + jsrlg = json_object_new_array(); + json_object_object_add(jte, "srlgs", jsrlg); + for (int i = 1; i < attr->srlg_len; i++) { + jobj = json_object_new_object(); + json_object_int_add(jobj, "srlg", attr->srlgs[i]); + json_object_array_add(jsrlg, jobj); + } + } + if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID)) { + jsr = json_object_new_array(); + json_object_object_add(json, "segment-routing", jsr); + jobj = json_object_new_object(); + json_object_int_add(jobj, "adj-sid", attr->adj_sid[0].sid); + snprintfrr(buf, 6, "0x%x", attr->adj_sid[0].flags); + json_object_string_add(jobj, "flags", buf); + json_object_int_add(jobj, "weight", attr->adj_sid[0].weight); + json_object_array_add(jsr, jobj); + } + if (CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) { + if (!jsr) { + jsr = json_object_new_array(); + json_object_object_add(json, "segment-routing", jsr); + } + jobj = json_object_new_object(); + json_object_int_add(jobj, "adj-sid", attr->adj_sid[1].sid); + snprintfrr(buf, 6, "0x%x", attr->adj_sid[1].flags); + json_object_string_add(jobj, "flags", buf); + json_object_int_add(jobj, "weight", attr->adj_sid[1].weight); + json_object_array_add(jsr, jobj); + } +} + +void ls_show_edge(struct ls_edge *edge, struct vty *vty, + struct json_object *json, bool verbose) +{ + /* Sanity Check */ + if (!edge) + return; + + if (json) + ls_show_edge_json(edge, json); + else if (vty) + ls_show_edge_vty(edge, vty, verbose); +} + +void ls_show_edges(struct ls_ted *ted, struct vty *vty, + struct json_object *json, bool verbose) +{ + struct ls_edge *edge; + json_object *jedges, *jedge; + + if (json) { + jedges = json_object_new_array(); + json_object_object_add(json, "edges", jedges); + frr_each (edges, &ted->edges, edge) { + jedge = json_object_new_object(); + ls_show_edge(edge, NULL, jedge, verbose); + json_object_array_add(jedges, jedge); + } + } else if (vty) { + frr_each (edges, &ted->edges, edge) + ls_show_edge(edge, vty, NULL, verbose); + } +} + +static void ls_show_subnet_vty(struct ls_subnet *subnet, struct vty *vty, + bool verbose) +{ + struct ls_prefix *pref; + struct sbuf sbuf; + char buf[INET6_BUFSIZ]; + + pref = subnet->ls_pref; + sbuf_init(&sbuf, NULL, 0); + + sbuf_push(&sbuf, 2, "Subnet: %pFX", &subnet->key); + ls_node_id_to_text(pref->adv, buf, INET6_BUFSIZ); + sbuf_push(&sbuf, 0, "\tAdv. Vertex: %s", buf); + sbuf_push(&sbuf, 0, "\tMetric: %d", pref->metric); + sbuf_push(&sbuf, 0, "\tStatus: %s\n", status2txt[subnet->status]); + + if (!verbose) + goto end; + + sbuf_push(&sbuf, 4, "Origin: %s\n", origin2txt[pref->adv.origin]); + if (CHECK_FLAG(pref->flags, LS_PREF_IGP_FLAG)) + sbuf_push(&sbuf, 4, "Flags: %d\n", pref->igp_flag); + + if (CHECK_FLAG(pref->flags, LS_PREF_ROUTE_TAG)) + sbuf_push(&sbuf, 4, "Tag: %d\n", pref->route_tag); + + if (CHECK_FLAG(pref->flags, LS_PREF_EXTENDED_TAG)) + sbuf_push(&sbuf, 4, "Extended Tag: %" PRIu64 "\n", + pref->extended_tag); + + if (CHECK_FLAG(pref->flags, LS_PREF_SR)) + sbuf_push(&sbuf, 4, "SID: %d\tAlgorithm: %d\tFlags: 0x%x\n", + pref->sr.sid, pref->sr.algo, pref->sr.sid_flag); + +end: + vty_out(vty, "%s\n", sbuf_buf(&sbuf)); + sbuf_free(&sbuf); +} + +static void ls_show_subnet_json(struct ls_subnet *subnet, + struct json_object *json) +{ + struct ls_prefix *pref; + json_object *jsr; + char buf[INET6_BUFSIZ]; + + pref = subnet->ls_pref; + + snprintfrr(buf, INET6_BUFSIZ, "%pFX", &subnet->key); + json_object_string_add(json, "subnet-id", buf); + json_object_string_add(json, "status", status2txt[subnet->status]); + json_object_string_add(json, "origin", origin2txt[pref->adv.origin]); + ls_node_id_to_text(pref->adv, buf, INET6_BUFSIZ); + json_object_string_add(json, "advertised-router", buf); + if (subnet->vertex) + json_object_int_add(json, "vertex-id", subnet->vertex->key); + json_object_int_add(json, "metric", pref->metric); + if (CHECK_FLAG(pref->flags, LS_PREF_IGP_FLAG)) { + snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->igp_flag); + json_object_string_add(json, "flags", buf); + } + if (CHECK_FLAG(pref->flags, LS_PREF_ROUTE_TAG)) + json_object_int_add(json, "tag", pref->route_tag); + if (CHECK_FLAG(pref->flags, LS_PREF_EXTENDED_TAG)) + json_object_int_add(json, "extended-tag", pref->extended_tag); + if (CHECK_FLAG(pref->flags, LS_PREF_SR)) { + jsr = json_object_new_object(); + json_object_object_add(json, "segment-routing", jsr); + json_object_int_add(jsr, "pref-sid", pref->sr.sid); + json_object_int_add(jsr, "algo", pref->sr.algo); + snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->sr.sid_flag); + json_object_string_add(jsr, "flags", buf); + } +} + +void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty, + struct json_object *json, bool verbose) +{ + /* Sanity Check */ + if (!subnet) + return; + + if (json) + ls_show_subnet_json(subnet, json); + else if (vty) + ls_show_subnet_vty(subnet, vty, verbose); +} + +void ls_show_subnets(struct ls_ted *ted, struct vty *vty, + struct json_object *json, bool verbose) +{ + struct ls_subnet *subnet; + json_object *jsubs, *jsub; + + if (json) { + jsubs = json_object_new_array(); + json_object_object_add(json, "subnets", jsubs); + frr_each (subnets, &ted->subnets, subnet) { + jsub = json_object_new_object(); + ls_show_subnet(subnet, NULL, jsub, verbose); + json_object_array_add(jsubs, jsub); + } + } else if (vty) { + frr_each (subnets, &ted->subnets, subnet) + ls_show_subnet(subnet, vty, NULL, verbose); + } +} + +void ls_show_ted(struct ls_ted *ted, struct vty *vty, struct json_object *json, + bool verbose) +{ + json_object *jted; + + if (json) { + jted = json_object_new_object(); + json_object_object_add(json, "ted", jted); + json_object_string_add(jted, "name", ted->name); + json_object_int_add(jted, "key", ted->key); + json_object_int_add(jted, "verticesCount", + vertices_count(&ted->vertices)); + json_object_int_add(jted, "edgesCount", + edges_count(&ted->edges)); + json_object_int_add(jted, "subnetsCount", + subnets_count(&ted->subnets)); + ls_show_vertices(ted, NULL, jted, verbose); + ls_show_edges(ted, NULL, jted, verbose); + ls_show_subnets(ted, NULL, jted, verbose); + return; + } + + if (vty) { + vty_out(vty, + "\n\tTraffic Engineering Database: %s (key: %d)\n\n", + ted->name, ted->key); + ls_show_vertices(ted, vty, NULL, verbose); + ls_show_edges(ted, vty, NULL, verbose); + ls_show_subnets(ted, vty, NULL, verbose); + vty_out(vty, + "\n\tTotal: %zu Vertices, %zu Edges, %zu Subnets\n\n", + vertices_count(&ted->vertices), + edges_count(&ted->edges), subnets_count(&ted->subnets)); + } +} + void ls_dump_ted(struct ls_ted *ted) { struct ls_vertex *vertex; struct ls_edge *edge; struct ls_subnet *subnet; - struct ls_message msg; + const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; zlog_debug("(%s) Ted init", __func__); - /* Prepare message */ - msg.event = LS_MSG_EVENT_SYNC; /* Loop TED, start printing Node, then Attributes and finally Prefix */ - frr_each(vertices, &ted->vertices, vertex) { - ls_vertex2msg(&msg, vertex); + frr_each (vertices, &ted->vertices, vertex) { zlog_debug(" Ted node (%s %pI4 %s)", vertex->node->name[0] ? vertex->node->name : "no name node", &vertex->node->router_id, - vertex->node->adv.origin == DIRECT ? "DIRECT" - : "NO DIRECT"); + origin2txt[vertex->node->adv.origin]); struct listnode *lst_node; struct ls_edge *vertex_edge; for (ALL_LIST_ELEMENTS_RO(vertex->incoming_edges, lst_node, vertex_edge)) { zlog_debug( - " inc edge key:%"PRIu64"n attr key:%pI4 loc:(%pI4) rmt:(%pI4)", + " inc edge key:%" PRIu64 " attr key:%pI4 loc:(%pI4) rmt:(%pI4)", vertex_edge->key, &vertex_edge->attributes->adv.id.ip.addr, &vertex_edge->attributes->standard.local, @@ -1255,29 +2450,25 @@ void ls_dump_ted(struct ls_ted *ted) for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, lst_node, vertex_edge)) { zlog_debug( - " out edge key:%"PRIu64" attr key:%pI4 loc:(%pI4) rmt:(%pI4)", + " out edge key:%" PRIu64 " attr key:%pI4 loc:(%pI4) rmt:(%pI4)", vertex_edge->key, &vertex_edge->attributes->adv.id.ip.addr, &vertex_edge->attributes->standard.local, &vertex_edge->attributes->standard.remote); } } - frr_each(edges, &ted->edges, edge) { - ls_edge2msg(&msg, edge); - zlog_debug(" Ted edge key:%"PRIu64" src:%s dst:%s", - edge->key, - edge->source ? edge->source->node->name - : "no_source", - edge->destination ? edge->destination->node->name - : "no_dest"); + frr_each (edges, &ted->edges, edge) { + zlog_debug(" Ted edge key:%" PRIu64 "src:%pI4 dst:%pI4", edge->key, + edge->source ? &edge->source->node->router_id + : &inaddr_any, + edge->destination + ? &edge->destination->node->router_id + : &inaddr_any); } - frr_each(subnets, &ted->subnets, subnet) { - ls_subnet2msg(&msg, subnet); - zlog_debug( - " Ted subnet key:%pFX vertex:%pI4 pfx:%pFX", - &subnet->key, - &subnet->vertex->node->adv.id.ip.addr, - &subnet->ls_pref->pref); + frr_each (subnets, &ted->subnets, subnet) { + zlog_debug(" Ted subnet key:%pFX vertex:%pI4", + &subnet->ls_pref->pref, + &subnet->vertex->node->adv.id.ip.addr); } zlog_debug("(%s) Ted end", __func__); } diff --git a/lib/link_state.h b/lib/link_state.h index 93669f5b23..de116df89e 100644 --- a/lib/link_state.h +++ b/lib/link_state.h @@ -53,20 +53,26 @@ extern "C" { * id for OSPF and the ISO System id plus the IS-IS level for IS-IS. */ +/* external reference */ +struct zapi_opaque_reg_info; +struct zclient; + /* Link State Common definitions */ #define MAX_NAME_LENGTH 256 #define ISO_SYS_ID_LEN 6 /* Type of Node */ enum ls_node_type { + NONE = 0, /* Unknown */ STANDARD, /* a P or PE node */ ABR, /* an Array Border Node */ ASBR, /* an Autonomous System Border Node */ - PSEUDO, /* a Pseudo Node */ + RMT_ASBR, /* Remote ASBR */ + PSEUDO /* a Pseudo Node */ }; /* Origin of the Link State information */ -enum ls_origin {NONE = 0, ISIS_L1, ISIS_L2, OSPFv2, DIRECT, STATIC}; +enum ls_origin { UNKNOWN = 0, ISIS_L1, ISIS_L2, OSPFv2, DIRECT, STATIC }; /** * Link State Node Identifier as: @@ -108,19 +114,17 @@ struct ls_node { struct in_addr router_id; /* IPv4 Router ID */ struct in6_addr router6_id; /* IPv6 Router ID */ uint8_t node_flag; /* IS-IS or OSPF Node flag */ - enum node_type type; /* Type of Node */ + enum ls_node_type type; /* Type of Node */ uint32_t as_number; /* Local or neighbor AS number */ - struct { /* Segment Routing Global Block */ + struct ls_srgb { /* Segment Routing Global Block */ uint32_t lower_bound; /* MPLS label lower bound */ uint32_t range_size; /* MPLS label range size */ uint8_t flag; /* IS-IS SRGB flags */ } srgb; -#define LS_NODE_SRGB_SIZE 9 - struct { /* Segment Routing Local Block */ + struct ls_srlb { /* Segment Routing Local Block */ uint32_t lower_bound; /* MPLS label lower bound */ uint32_t range_size; /* MPLS label range size */ } srlb; -#define LS_NODE_SRLB_SIZE 8 uint8_t algo[2]; /* Segment Routing Algorithms */ uint8_t msd; /* Maximum Stack Depth */ }; @@ -150,17 +154,17 @@ struct ls_node { #define LS_ATTR_AVA_BW 0x00100000 #define LS_ATTR_RSV_BW 0x00200000 #define LS_ATTR_USE_BW 0x00400000 -#define LS_ATTR_ADJ_SID 0x00800000 -#define LS_ATTR_BCK_ADJ_SID 0x01000000 -#define LS_ATTR_SRLG 0x02000000 +#define LS_ATTR_ADJ_SID 0x01000000 +#define LS_ATTR_BCK_ADJ_SID 0x02000000 +#define LS_ATTR_SRLG 0x10000000 /* Link State Attributes */ struct ls_attributes { uint32_t flags; /* Flag for parameters validity */ struct ls_node_id adv; /* Adv. Router of this Link State */ char name[MAX_NAME_LENGTH]; /* Name of the Edge. Could be null */ - struct { /* Standard TE metrics */ - uint32_t metric; /* IGP standard metric */ + uint32_t metric; /* IGP standard metric */ + struct ls_standard { /* Standard TE metrics */ uint32_t te_metric; /* Traffic Engineering metric */ uint32_t admin_group; /* Administrative Group */ struct in_addr local; /* Local IPv4 address */ @@ -176,8 +180,7 @@ struct ls_attributes { struct in_addr remote_addr; /* Remote IPv4 address */ struct in6_addr remote_addr6; /* Remote IPv6 address */ } standard; -#define LS_ATTR_STANDARD_SIZE 124 - struct { /* Extended TE Metrics */ + struct ls_extended { /* Extended TE Metrics */ uint32_t delay; /* Unidirectional average delay */ uint32_t min_delay; /* Unidirectional minimum delay */ uint32_t max_delay; /* Unidirectional maximum delay */ @@ -187,8 +190,7 @@ struct ls_attributes { float rsv_bw; /* Reserved Bandwidth */ float used_bw; /* Utilized Bandwidth */ } extended; -#define LS_ATTR_EXTENDED_SIZE 32 - struct { /* (LAN)-Adjacency SID for OSPF */ + struct ls_adjacency { /* (LAN)-Adjacency SID for OSPF */ uint32_t sid; /* SID as MPLS label or index */ uint8_t flags; /* Flags */ uint8_t weight; /* Administrative weight */ @@ -197,7 +199,6 @@ struct ls_attributes { uint8_t sysid[ISO_SYS_ID_LEN]; /* or Sys-ID for ISIS */ } neighbor; } adj_sid[2]; /* Primary & Backup (LAN)-Adj. SID */ -#define LS_ATTR_ADJ_SID_SIZE 120 uint32_t *srlgs; /* List of Shared Risk Link Group */ uint8_t srlg_len; /* number of SRLG in the list */ }; @@ -219,7 +220,7 @@ struct ls_prefix { uint32_t route_tag; /* IGP Route Tag */ uint64_t extended_tag; /* IGP Extended Route Tag */ uint32_t metric; /* Route metric for this prefix */ - struct { + struct ls_sid { uint32_t sid; /* Segment Routing ID */ uint8_t sid_flag; /* Segment Routing Flags */ uint8_t algo; /* Algorithm for Segment Routing */ @@ -273,9 +274,16 @@ extern struct ls_attributes *ls_attributes_new(struct ls_node_id adv, uint32_t local_id); /** + * Remove SRLGs from Link State Attributes if defined. + * + * @param attr Pointer to a valid Link State Attribute structure + */ +extern void ls_attributes_srlg_del(struct ls_attributes *attr); + +/** * Remove Link State Attributes. Data structure is freed. * - * @param attr Pointer to a valid Link State Attribute structure + * @param attr Pointer to a valid Link State Attribute structure */ extern void ls_attributes_del(struct ls_attributes *attr); @@ -292,6 +300,34 @@ extern int ls_attributes_same(struct ls_attributes *a1, struct ls_attributes *a2); /** + * Create a new Link State Prefix. Structure is dynamically allocated. + * + * @param adv Mandatory Link State Node ID i.e. advertise router ID + * @param p Mandatory Prefix + * + * @return New Link State Prefix + */ +extern struct ls_prefix *ls_prefix_new(struct ls_node_id adv, struct prefix p); + +/** + * Remove Link State Prefix. Data Structure is freed. + * + * @param pref Pointer to a valid Link State Attribute Prefix. + */ +extern void ls_prefix_del(struct ls_prefix *pref); + +/** + * Check if two Link State Prefix are equal. Note that this routine has the + * same return value sense as '==' (which is different from a comparison). + * + * @param p1 First Link State Prefix to be compare + * @param p2 Second Link State Prefix to be compare + * + * @return 1 if equal, 0 otherwise + */ +extern int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2); + +/** * In addition a Graph model is defined as an overlay on top of link state * database in order to ease Path Computation algorithm implementation. * Denoted G(V, E), a graph is composed by a list of Vertices (V) which @@ -323,9 +359,14 @@ extern int ls_attributes_same(struct ls_attributes *a1, * */ +enum ls_status { UNSET = 0, NEW, UPDATE, DELETE, SYNC, ORPHAN }; +enum ls_type { GENERIC = 0, VERTEX, EDGE, SUBNET }; + /* Link State Vertex structure */ -PREDECL_RBTREE_UNIQ(vertices) +PREDECL_RBTREE_UNIQ(vertices); struct ls_vertex { + enum ls_type type; /* Link State Type */ + enum ls_status status; /* Status of the Vertex in the TED */ struct vertices_item entry; /* Entry in RB Tree */ uint64_t key; /* Unique Key identifier */ struct ls_node *node; /* Link State Node */ @@ -335,8 +376,10 @@ struct ls_vertex { }; /* Link State Edge structure */ -PREDECL_RBTREE_UNIQ(edges) +PREDECL_RBTREE_UNIQ(edges); struct ls_edge { + enum ls_type type; /* Link State Type */ + enum ls_status status; /* Status of the Edge in the TED */ struct edges_item entry; /* Entry in RB tree */ uint64_t key; /* Unique Key identifier */ struct ls_attributes *attributes; /* Link State attributes */ @@ -345,12 +388,14 @@ struct ls_edge { }; /* Link State Subnet structure */ -PREDECL_RBTREE_UNIQ(subnets) +PREDECL_RBTREE_UNIQ(subnets); struct ls_subnet { + enum ls_type type; /* Link State Type */ + enum ls_status status; /* Status of the Subnet in the TED */ struct subnets_item entry; /* Entry in RB tree */ struct prefix key; /* Unique Key identifier */ - struct ls_vertex *vertex; /* Back pointer to the Vertex owner */ struct ls_prefix *ls_pref; /* Link State Prefix */ + struct ls_vertex *vertex; /* Back pointer to the Vertex owner */ }; /* Declaration of Vertices, Edges and Prefixes RB Trees */ @@ -359,21 +404,21 @@ macro_inline int vertex_cmp(const struct ls_vertex *node1, { return (node1->key - node2->key); } -DECLARE_RBTREE_UNIQ(vertices, struct ls_vertex, entry, vertex_cmp) +DECLARE_RBTREE_UNIQ(vertices, struct ls_vertex, entry, vertex_cmp); macro_inline int edge_cmp(const struct ls_edge *edge1, const struct ls_edge *edge2) { return (edge1->key - edge2->key); } -DECLARE_RBTREE_UNIQ(edges, struct ls_edge, entry, edge_cmp) +DECLARE_RBTREE_UNIQ(edges, struct ls_edge, entry, edge_cmp); macro_inline int subnet_cmp(const struct ls_subnet *a, const struct ls_subnet *b) { return prefix_cmp(&a->key, &b->key); } -DECLARE_RBTREE_UNIQ(subnets, struct ls_subnet, entry, subnet_cmp) +DECLARE_RBTREE_UNIQ(subnets, struct ls_subnet, entry, subnet_cmp); /* Link State TED Structure */ struct ls_ted { @@ -386,37 +431,45 @@ struct ls_ted { struct subnets_head subnets; /* List of Subnets */ }; +/* Generic Link State Element */ +struct ls_element { + enum ls_type type; /* Link State Element Type */ + enum ls_status status; /* Link State Status in the TED */ + void *data; /* Link State payload */ +}; + /** - * Create a new Link State Vertex structure and initialize is with the Link - * State Node parameter. + * Add new vertex to the Link State DB. Vertex is created from the Link State + * Node. Vertex data structure is dynamically allocated. * + * @param ted Traffic Engineering Database structure * @param node Link State Node * - * @return New Vertex + * @return New Vertex or NULL in case of error */ -extern struct ls_vertex *ls_vertex_new(struct ls_node *node); +extern struct ls_vertex *ls_vertex_add(struct ls_ted *ted, + struct ls_node *node); /** * Delete Link State Vertex. This function clean internal Vertex lists (incoming - * and outgoing Link State Edge and Link State Subnet). Note that referenced - * objects of the different lists (Edges & SubNet) are not removed as they could - * be connected to other Vertices. + * and outgoing Link State Edge and Link State Subnet). Vertex Data structure + * is freed but not the Link State Node. Link State DB is not modified if Vertex + * is NULL or not found in the Data Base. Note that referenced to Link State + * Edges & SubNets are not removed as they could be connected to other Vertices. * + * @param ted Traffic Engineering Database structure * @param vertex Link State Vertex to be removed */ -extern void ls_vertex_del(struct ls_vertex *vertex); +extern void ls_vertex_del(struct ls_ted *ted, struct ls_vertex *vertex); /** - * Add new vertex to the Link State DB. Vertex is created from the Link State - * Node. Vertex data structure is dynamically allocated. + * Delete Link State Vertex as ls_vertex_del() but also removed associated + * Link State Node. * - * @param ted Traffic Engineering Database structure - * @param node Link State Node - * - * @return New Vertex or NULL in case of error + * @param ted Traffic Engineering Database structure + * @param vertex Link State Vertex to be removed */ -extern struct ls_vertex *ls_vertex_add(struct ls_ted *ted, - struct ls_node *node); +extern void ls_vertex_del_all(struct ls_ted *ted, struct ls_vertex *vertex); /** * Update Vertex with the Link State Node. A new vertex is created if no one @@ -431,15 +484,15 @@ extern struct ls_vertex *ls_vertex_update(struct ls_ted *ted, struct ls_node *node); /** - * Remove Vertex from the Link State DB. Vertex Data structure is freed but - * not the Link State Node. Link State DB is not modified if Vertex is NULL or - * not found in the Data Base. + * Clean Vertex structure by removing all Edges and Subnets marked as ORPHAN + * from this vertex. Link State Update message is sent if zclient is not NULL. * * @param ted Link State Data Base - * @param vertex Vertex to be removed + * @param vertex Link State Vertex to be cleaned + * @param zclient Reference to Zebra Client */ -extern void ls_vertex_remove(struct ls_ted *ted, struct ls_vertex *vertex); - +extern void ls_vertex_clean(struct ls_ted *ted, struct ls_vertex *vertex, + struct zclient *zclient); /** * Find Vertex in the Link State DB by its unique key. * @@ -498,6 +551,17 @@ extern struct ls_edge *ls_edge_update(struct ls_ted *ted, struct ls_attributes *attributes); /** + * Check if two Edges are equal. Note that this routine has the same return + * value sense as '==' (which is different from a comparison). + * + * @param e1 First edge to compare + * @param e2 Second edge to compare + * + * @return 1 if equal, 0 otherwise + */ +extern int ls_edge_same(struct ls_edge *e1, struct ls_edge *e2); + +/** * Remove Edge from the Link State DB. Edge data structure is freed but not the * Link State Attributes data structure. Link State DB is not modified if Edge * is NULL or not found in the Data Base. @@ -508,6 +572,15 @@ extern struct ls_edge *ls_edge_update(struct ls_ted *ted, extern void ls_edge_del(struct ls_ted *ted, struct ls_edge *edge); /** + * Remove Edge and associated Link State Attributes from the Link State DB. + * Link State DB is not modified if Edge is NULL or not found. + * + * @param ted Link State Data Base + * @param edge Edge to be removed + */ +extern void ls_edge_del_all(struct ls_ted *ted, struct ls_edge *edge); + +/** * Find Edge in the Link State Data Base by Edge key. * * @param ted Link State Data Base @@ -520,8 +593,7 @@ extern struct ls_edge *ls_find_edge_by_key(struct ls_ted *ted, /** * Find Edge in the Link State Data Base by the source (local IPv4 or IPv6 - * address or local ID) informations of the Link - * State Attributes + * address or local ID) informations of the Link State Attributes * * @param ted Link State Data Base * @param attributes Link State Attributes @@ -557,6 +629,29 @@ extern struct ls_subnet *ls_subnet_add(struct ls_ted *ted, struct ls_prefix *pref); /** + * Update the Link State Prefix information of an existing Subnet. If there is + * no corresponding Subnet in the Link State Data Base, a new Subnet is created. + * + * @param ted Link State Data Base + * @param pref Link State Prefix + * + * @return Updated Link State Subnet, or NULL in case of error + */ +extern struct ls_subnet *ls_subnet_update(struct ls_ted *ted, + struct ls_prefix *pref); + +/** + * Check if two Subnets are equal. Note that this routine has the same return + * value sense as '==' (which is different from a comparison). + * + * @param s1 First subnet to compare + * @param s2 Second subnet to compare + * + * @return 1 if equal, 0 otherwise + */ +extern int ls_subnet_same(struct ls_subnet *s1, struct ls_subnet *s2); + +/** * Remove Subnet from the Link State DB. Subnet data structure is freed but * not the Link State prefix data structure. Link State DB is not modified * if Subnet is NULL or not found in the Data Base. @@ -567,6 +662,15 @@ extern struct ls_subnet *ls_subnet_add(struct ls_ted *ted, extern void ls_subnet_del(struct ls_ted *ted, struct ls_subnet *subnet); /** + * Remove Subnet and the associated Link State Prefix from the Link State DB. + * Link State DB is not modified if Subnet is NULL or not found. + * + * @param ted Link State Data Base + * @param subnet Subnet to be removed + */ +extern void ls_subnet_del_all(struct ls_ted *ted, struct ls_subnet *subnet); + +/** * Find Subnet in the Link State Data Base by prefix. * * @param ted Link State Data Base @@ -582,7 +686,7 @@ extern struct ls_subnet *ls_find_subnet(struct ls_ted *ted, * * @param key Unique key of the data base. Must be different from 0 * @param name Name of the data base (may be NULL) - * @param asn AS Number for this data base. Must be different from 0 + * @param asn AS Number for this data base. 0 if unknown * * @return New Link State Database or NULL in case of error */ @@ -590,13 +694,29 @@ extern struct ls_ted *ls_ted_new(const uint32_t key, const char *name, uint32_t asn); /** - * Delete existing Link State Data Base. + * Delete existing Link State Data Base. Vertices, Edges, and Subnets are not + * removed. * * @param ted Link State Data Base */ extern void ls_ted_del(struct ls_ted *ted); /** + * Delete all Link State Vertices, Edges and SubNets and the Link State DB. + * + * @param ted Link State Data Base + */ +extern void ls_ted_del_all(struct ls_ted *ted); + +/** + * Clean Link State Data Base by removing all Vertices, Edges and SubNets marked + * as ORPHAN. + * + * @param ted Link State Data Base + */ +extern void ls_ted_clean(struct ls_ted *ted); + +/** * Connect Source and Destination Vertices by given Edge. Only non NULL source * and destination vertices are connected. * @@ -657,6 +777,7 @@ extern void ls_disconnect_edge(struct ls_edge *edge); */ /* ZAPI Opaque Link State Message Event */ +#define LS_MSG_EVENT_UNDEF 0 #define LS_MSG_EVENT_SYNC 1 #define LS_MSG_EVENT_ADD 2 #define LS_MSG_EVENT_UPDATE 3 @@ -680,6 +801,35 @@ struct ls_message { }; /** + * Register Link State daemon as a server or client for Zebra OPAQUE API. + * + * @param zclient Zebra client structure + * @param server Register daemon as a server (true) or as a client (false) + * + * @return 0 if success, -1 otherwise + */ +extern int ls_register(struct zclient *zclient, bool server); + +/** + * Unregister Link State daemon as a server or client for Zebra OPAQUE API. + * + * @param zclient Zebra client structure + * @param server Unregister daemon as a server (true) or as a client (false) + * + * @return 0 if success, -1 otherwise + */ +extern int ls_unregister(struct zclient *zclient, bool server); + +/** + * Send Link State SYNC message to request the complete Link State Database. + * + * @param zclient Zebra client + * + * @return 0 if success, -1 otherwise + */ +extern int ls_request_sync(struct zclient *zclient); + +/** * Parse Link State Message from stream. Used this function once receiving a * new ZAPI Opaque message of type Link State. * @@ -690,7 +840,7 @@ struct ls_message { extern struct ls_message *ls_parse_msg(struct stream *s); /** - * Delete existing message, freeing all substructure. + * Delete existing message. Data structure is freed. * * @param msg Link state message to be deleted */ @@ -751,6 +901,81 @@ extern struct ls_message *ls_subnet2msg(struct ls_message *msg, struct ls_subnet *subnet); /** + * Convert Link State Message into Vertex and update TED accordingly to + * the message event: SYNC, ADD, UPDATE or DELETE. + * + * @param ted Link State Database + * @param msg Link State Message + * @param delete True to delete the Link State Vertex from the Database, + * False otherwise. If true, return value is NULL in case + * of deletion. + * + * @return Vertex if success, NULL otherwise or if Vertex is removed + */ +extern struct ls_vertex *ls_msg2vertex(struct ls_ted *ted, + struct ls_message *msg, bool delete); + +/** + * Convert Link State Message into Edge and update TED accordingly to + * the message event: SYNC, ADD, UPDATE or DELETE. + * + * @param ted Link State Database + * @param msg Link State Message + * @param delete True to delete the Link State Edge from the Database, + * False otherwise. If true, return value is NULL in case + * of deletion. + * + * @return Edge if success, NULL otherwise or if Edge is removed + */ +extern struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg, + bool delete); + +/** + * Convert Link State Message into Subnet and update TED accordingly to + * the message event: SYNC, ADD, UPDATE or DELETE. + * + * @param ted Link State Database + * @param msg Link State Message + * @param delete True to delete the Link State Subnet from the Database, + * False otherwise. If true, return value is NULL in case + * of deletion. + * + * @return Subnet if success, NULL otherwise or if Subnet is removed + */ +extern struct ls_subnet *ls_msg2subnet(struct ls_ted *ted, + struct ls_message *msg, bool delete); + +/** + * Convert Link State Message into Link State element (Vertex, Edge or Subnet) + * and update TED accordingly to the message event: SYNC, ADD, UPDATE or DELETE. + * + * @param ted Link State Database + * @param msg Link State Message + * @param delete True to delete the Link State Element from the Database, + * False otherwise. If true, return value is NULL in case + * of deletion. + * + * @return Element if success, NULL otherwise or if Element is removed + */ +extern struct ls_element *ls_msg2ted(struct ls_ted *ted, struct ls_message *msg, + bool delete); + +/** + * Convert stream buffer into Link State element (Vertex, Edge or Subnet) and + * update TED accordingly to the message event: SYNC, ADD, UPDATE or DELETE. + * + * @param ted Link State Database + * @param s Stream buffer + * @param delete True to delete the Link State Element from the Database, + * False otherwise. If true, return value is NULL in case + * of deletion. + * + * @return Element if success, NULL otherwise or if Element is removed + */ +extern struct ls_element *ls_stream2ted(struct ls_ted *ted, struct stream *s, + bool delete); + +/** * Send all the content of the Link State Data Base to the given destination. * Link State content is sent is this order: Vertices, Edges, Subnet. * This function must be used when a daemon request a Link State Data Base @@ -765,6 +990,92 @@ extern struct ls_message *ls_subnet2msg(struct ls_message *msg, extern int ls_sync_ted(struct ls_ted *ted, struct zclient *zclient, struct zapi_opaque_reg_info *dst); +struct json_object; +struct vty; +/** + * Show Link State Vertex information. If both vty and json are specified, + * Json format output supersedes standard vty output. + * + * @param vertex Link State Vertex to show. Must not be NULL + * @param vty Pointer to vty output, could be NULL + * @param json Pointer to json output, could be NULL + * @param verbose Set to true for more detail + */ +extern void ls_show_vertex(struct ls_vertex *vertex, struct vty *vty, + struct json_object *json, bool verbose); + +/** + * Show all Link State Vertices information. If both vty and json are specified, + * Json format output supersedes standard vty output. + * + * @param ted Link State Data Base. Must not be NULL + * @param vty Pointer to vty output, could be NULL + * @param json Pointer to json output, could be NULL + * @param verbose Set to true for more detail + */ +extern void ls_show_vertices(struct ls_ted *ted, struct vty *vty, + struct json_object *json, bool verbose); + +/** + * Show Link State Edge information. If both vty and json are specified, + * Json format output supersedes standard vty output. + * + * @param edge Link State Edge to show. Must not be NULL + * @param vty Pointer to vty output, could be NULL + * @param json Pointer to json output, could be NULL + * @param verbose Set to true for more detail + */ +extern void ls_show_edge(struct ls_edge *edge, struct vty *vty, + struct json_object *json, bool verbose); + +/** + * Show all Link State Edges information. If both vty and json are specified, + * Json format output supersedes standard vty output. + * + * @param ted Link State Data Base. Must not be NULL + * @param vty Pointer to vty output, could be NULL + * @param json Pointer to json output, could be NULL + * @param verbose Set to true for more detail + */ +extern void ls_show_edges(struct ls_ted *ted, struct vty *vty, + struct json_object *json, bool verbose); + +/** + * Show Link State Subnets information. If both vty and json are specified, + * Json format output supersedes standard vty output. + * + * @param subnet Link State Subnet to show. Must not be NULL + * @param vty Pointer to vty output, could be NULL + * @param json Pointer to json output, could be NULL + * @param verbose Set to true for more detail + */ +extern void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty, + struct json_object *json, bool verbose); + +/** + * Show all Link State Subnet information. If both vty and json are specified, + * Json format output supersedes standard vty output. + * + * @param ted Link State Data Base. Must not be NULL + * @param vty Pointer to vty output, could be NULL + * @param json Pointer to json output, could be NULL + * @param verbose Set to true for more detail + */ +extern void ls_show_subnets(struct ls_ted *ted, struct vty *vty, + struct json_object *json, bool verbose); + +/** + * Show Link State Data Base information. If both vty and json are specified, + * Json format output supersedes standard vty output. + * + * @param ted Link State Data Base to show. Must not be NULL + * @param vty Pointer to vty output, could be NULL + * @param json Pointer to json output, could be NULL + * @param verbose Set to true for more detail + */ +extern void ls_show_ted(struct ls_ted *ted, struct vty *vty, + struct json_object *json, bool verbose); + /** * Dump all Link State Data Base elements for debugging purposes * diff --git a/lib/linklist.c b/lib/linklist.c index 43c2002231..5de6c8a817 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -25,8 +25,8 @@ #include "memory.h" #include "libfrr_trace.h" -DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List") -DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node") +DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List"); +DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node"); struct list *list_new(void) { @@ -462,7 +462,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_NHG_DEL), DESC_ENTRY(ZEBRA_NHG_NOTIFY_OWNER), DESC_ENTRY(ZEBRA_ROUTE_NOTIFY_REQUEST), - DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY)}; + DESC_ENTRY(ZEBRA_CLIENT_CLOSE_NOTIFY), + DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_ADD), + DESC_ENTRY(ZEBRA_EVPN_REMOTE_NH_DEL)}; #undef DESC_ENTRY static const struct zebra_desc_table unknown = {0, "unknown", '?'}; diff --git a/lib/log_vty.c b/lib/log_vty.c index d1dcac2340..c26621ae99 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -33,7 +33,7 @@ #define ZLOG_MAXLVL(a, b) MAX(a, b) -DEFINE_HOOK(zlog_rotate, (), ()) +DEFINE_HOOK(zlog_rotate, (), ()); static const int log_default_lvl = LOG_DEBUG; @@ -532,6 +532,28 @@ DEFUN (no_config_log_timestamp_precision, return CMD_SUCCESS; } +DEFPY (config_log_ec, + config_log_ec_cmd, + "[no] log error-category", + NO_STR + "Logging control\n" + "Prefix log message text with [EC 9999] code\n") +{ + zlog_set_prefix_ec(!no); + return CMD_SUCCESS; +} + +DEFPY (config_log_xid, + config_log_xid_cmd, + "[no] log unique-id", + NO_STR + "Logging control\n" + "Prefix log message text with [XXXXX-XXXXX] identifier\n") +{ + zlog_set_prefix_xid(!no); + return CMD_SUCCESS; +} + DEFPY (config_log_filterfile, config_log_filterfile_cmd, "log filtered-file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]", @@ -699,6 +721,11 @@ void log_config_write(struct vty *vty) if (zt_file.ts_subsec > 0) vty_out(vty, "log timestamp precision %d\n", zt_file.ts_subsec); + + if (!zlog_get_prefix_ec()) + vty_out(vty, "no log error-category\n"); + if (!zlog_get_prefix_xid()) + vty_out(vty, "no log unique-id\n"); } static int log_vty_init(const char *progname, const char *protoname, @@ -707,6 +734,9 @@ static int log_vty_init(const char *progname, const char *protoname, zlog_progname = progname; zlog_protoname = protoname; + zlog_set_prefix_ec(true); + zlog_set_prefix_xid(true); + zlog_filterfile_init(&zt_filterfile); zlog_file_set_fd(&zt_stdout, STDOUT_FILENO); @@ -737,6 +767,8 @@ void log_cmd_init(void) install_element(CONFIG_NODE, &no_config_log_record_priority_cmd); install_element(CONFIG_NODE, &config_log_timestamp_precision_cmd); install_element(CONFIG_NODE, &no_config_log_timestamp_precision_cmd); + install_element(CONFIG_NODE, &config_log_ec_cmd); + install_element(CONFIG_NODE, &config_log_xid_cmd); install_element(VIEW_NODE, &show_log_filter_cmd); install_element(CONFIG_NODE, &log_filter_cmd); diff --git a/lib/log_vty.h b/lib/log_vty.h index 16c4475467..f0fb7d3dba 100644 --- a/lib/log_vty.h +++ b/lib/log_vty.h @@ -34,7 +34,7 @@ extern void log_config_write(struct vty *vty); extern int log_level_match(const char *s); extern void log_show_syslog(struct vty *vty); -DECLARE_HOOK(zlog_rotate, (), ()) +DECLARE_HOOK(zlog_rotate, (), ()); extern void zlog_rotate(void); #ifdef __cplusplus diff --git a/lib/memory.c b/lib/memory.c index a377d3b945..0dc8e90524 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -34,8 +34,8 @@ static struct memgroup *mg_first = NULL; struct memgroup **mg_insert = &mg_first; -DEFINE_MGROUP(LIB, "libfrr") -DEFINE_MTYPE(LIB, TMP, "Temporary memory") +DEFINE_MGROUP(LIB, "libfrr"); +DEFINE_MTYPE(LIB, TMP, "Temporary memory"); static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr) { diff --git a/lib/memory.h b/lib/memory.h index e9db12fce2..c95602f485 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -56,20 +56,20 @@ struct memgroup { /* macro usage: * * mydaemon.h - * DECLARE_MGROUP(MYDAEMON) - * DECLARE_MTYPE(MYDAEMON_COMMON) + * DECLARE_MGROUP(MYDAEMON); + * DECLARE_MTYPE(MYDAEMON_COMMON); * * mydaemon.c - * DEFINE_MGROUP(MYDAEMON, "my daemon memory") + * DEFINE_MGROUP(MYDAEMON, "my daemon memory"); * DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON, - * "this mtype is used in multiple files in mydaemon") + * "this mtype is used in multiple files in mydaemon"); * foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo)) * * mydaemon_io.c * bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar)) * * DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO, - * "this mtype is used only in this file") + * "this mtype is used only in this file"); * baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz)) * * Note: Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced @@ -78,7 +78,7 @@ struct memgroup { * but MGROUP_* aren't. */ -#define DECLARE_MGROUP(name) extern struct memgroup _mg_##name; +#define DECLARE_MGROUP(name) extern struct memgroup _mg_##name #define _DEFINE_MGROUP(mname, desc, ...) \ struct memgroup _mg_##mname \ __attribute__((section(".data.mgroups"))) = { \ @@ -104,7 +104,7 @@ struct memgroup { _mg_##mname.next->ref = _mg_##mname.ref; \ *_mg_##mname.ref = _mg_##mname.next; \ } \ - /* end */ + MACRO_REQUIRE_SEMICOLON() /* end */ #define DEFINE_MGROUP(mname, desc) \ _DEFINE_MGROUP(mname, desc, ) @@ -112,7 +112,7 @@ struct memgroup { _DEFINE_MGROUP(mname, desc, .active_at_exit = true) #define DECLARE_MTYPE(name) \ - extern struct memtype MTYPE_##name[1]; \ + extern struct memtype MTYPE_##name[1] \ /* end */ #define DEFINE_MTYPE_ATTR(group, mname, attr, desc) \ @@ -140,7 +140,7 @@ struct memgroup { MTYPE_##mname->next->ref = MTYPE_##mname->ref; \ *MTYPE_##mname->ref = MTYPE_##mname->next; \ } \ - /* end */ + MACRO_REQUIRE_SEMICOLON() /* end */ #define DEFINE_MTYPE(group, name, desc) \ DEFINE_MTYPE_ATTR(group, name, , desc) \ @@ -150,8 +150,8 @@ struct memgroup { DEFINE_MTYPE_ATTR(group, name, static, desc) \ /* end */ -DECLARE_MGROUP(LIB) -DECLARE_MTYPE(TMP) +DECLARE_MGROUP(LIB); +DECLARE_MTYPE(TMP); extern void *qmalloc(struct memtype *mt, size_t size) diff --git a/lib/module.c b/lib/module.c index 3d299a6a2e..d2491a3479 100644 --- a/lib/module.c +++ b/lib/module.c @@ -27,8 +27,8 @@ #include "memory.h" #include "version.h" -DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name") -DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments") +DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name"); +DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments"); static struct frrmod_info frrmod_default_info = { .name = "libfrr", @@ -43,7 +43,7 @@ union _frrmod_runtime_u frrmod_default = { }, }; -XREF_SETUP() +XREF_SETUP(); // if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE) // union _frrmod_runtime_u _frrmod_this_module diff --git a/lib/module.h b/lib/module.h index 5d8d9cfbcc..6275877cb3 100644 --- a/lib/module.h +++ b/lib/module.h @@ -79,12 +79,13 @@ extern union _frrmod_runtime_u _frrmod_this_module; NULL, \ &_frrmod_info, \ }}; \ - XREF_SETUP() \ - /* end */ + XREF_SETUP(); \ + MACRO_REQUIRE_SEMICOLON() /* end */ #define FRR_MODULE_SETUP(...) \ - FRR_COREMOD_SETUP(__VA_ARGS__) \ - DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r; + FRR_COREMOD_SETUP(__VA_ARGS__); \ + DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r; \ + MACRO_REQUIRE_SEMICOLON() /* end */ extern struct frrmod_runtime *frrmod_list; diff --git a/lib/netns_linux.c b/lib/netns_linux.c index c688433983..cde842b88c 100644 --- a/lib/netns_linux.c +++ b/lib/netns_linux.c @@ -40,8 +40,8 @@ #include "vrf.h" #include "lib_errors.h" -DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context") -DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name") +DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context"); +DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name"); static inline int ns_compare(const struct ns *ns, const struct ns *ns2); static struct ns *ns_lookup_name_internal(const char *name); diff --git a/lib/netns_other.c b/lib/netns_other.c index 3fc4b8df4b..b6570d3b9e 100644 --- a/lib/netns_other.c +++ b/lib/netns_other.c @@ -26,8 +26,8 @@ #include "log.h" #include "memory.h" -DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context") -DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name") +DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context"); +DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name"); static inline int ns_compare(const struct ns *ns, const struct ns *ns2); diff --git a/lib/nexthop.c b/lib/nexthop.c index dd8c108205..8439398149 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -34,8 +34,8 @@ #include "vrf.h" #include "nexthop_group.h" -DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop") -DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label") +DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop"); +DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label"); static int _nexthop_labels_cmp(const struct nexthop *nh1, const struct nexthop *nh2) @@ -730,80 +730,99 @@ int nexthop_str2backups(const char *str, int *num_backups, * nexthop2str() */ printfrr_ext_autoreg_p("NH", printfrr_nh) -static ssize_t printfrr_nh(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct nexthop *nexthop = ptr; - struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 }; bool do_ifi = false; - const char *s, *v_is = "", *v_via = "", *v_viaif = "via "; - ssize_t ret = 3; + const char *v_is = "", *v_via = "", *v_viaif = "via "; + ssize_t ret = 0; - /* NULL-check */ - if (nexthop == NULL) { - if (fmt[2] == 'v' && fmt[3] == 'v') - ret++; - - strlcpy(buf, "NULL", bsz); - - return ret; - } - - switch (fmt[2]) { + switch (*ea->fmt) { case 'v': - if (fmt[3] == 'v') { + ea->fmt++; + if (*ea->fmt == 'v') { v_is = "is "; v_via = "via "; v_viaif = ""; - ret++; + ea->fmt++; } + if (!nexthop) + return bputs(buf, "(null)"); + switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - bprintfrr(&fb, "%s%pI4", v_via, &nexthop->gate.ipv4); + ret += bprintfrr(buf, "%s%pI4", v_via, + &nexthop->gate.ipv4); do_ifi = true; break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - bprintfrr(&fb, "%s%pI6", v_via, &nexthop->gate.ipv6); + ret += bprintfrr(buf, "%s%pI6", v_via, + &nexthop->gate.ipv6); do_ifi = true; break; case NEXTHOP_TYPE_IFINDEX: - bprintfrr(&fb, "%sdirectly connected, %s", v_is, - ifindex2ifname(nexthop->ifindex, - nexthop->vrf_id)); + ret += bprintfrr(buf, "%sdirectly connected, %s", v_is, + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); break; case NEXTHOP_TYPE_BLACKHOLE: + ret += bputs(buf, "unreachable"); + switch (nexthop->bh_type) { case BLACKHOLE_REJECT: - s = " (ICMP unreachable)"; + ret += bputs(buf, " (ICMP unreachable)"); break; case BLACKHOLE_ADMINPROHIB: - s = " (ICMP admin-prohibited)"; + ret += bputs(buf, " (ICMP admin-prohibited)"); break; case BLACKHOLE_NULL: - s = " (blackhole)"; + ret += bputs(buf, " (blackhole)"); break; default: - s = ""; break; } - bprintfrr(&fb, "unreachable%s", s); break; default: break; } if (do_ifi && nexthop->ifindex) - bprintfrr(&fb, ", %s%s", v_viaif, ifindex2ifname( - nexthop->ifindex, - nexthop->vrf_id)); + ret += bprintfrr(buf, ", %s%s", v_viaif, + ifindex2ifname(nexthop->ifindex, + nexthop->vrf_id)); - *fb.pos = '\0'; return ret; case 's': - nexthop2str(nexthop, buf, bsz); - return 3; + ea->fmt++; + + if (!nexthop) + return bputs(buf, "(null)"); + + switch (nexthop->type) { + case NEXTHOP_TYPE_IFINDEX: + ret += bprintfrr(buf, "if %u", nexthop->ifindex); + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + ret += bprintfrr(buf, "%pI4 if %u", &nexthop->gate.ipv4, + nexthop->ifindex); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + ret += bprintfrr(buf, "%pI6 if %u", &nexthop->gate.ipv6, + nexthop->ifindex); + break; + case NEXTHOP_TYPE_BLACKHOLE: + ret += bputs(buf, "blackhole"); + break; + default: + ret += bputs(buf, "unknown"); + break; + } + return ret; } - return 0; + return -1; } diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index dee98ad8d7..4fee9bde3c 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -32,7 +32,7 @@ #include "lib/nexthop_group_clippy.c" #endif -DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group") +DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group"); /* * Internal struct used to hold nhg config strings @@ -620,7 +620,7 @@ static void nhgc_delete(struct nexthop_group_cmd *nhgc) XFREE(MTYPE_TMP, nhgc); } -DEFINE_QOBJ_TYPE(nexthop_group_cmd) +DEFINE_QOBJ_TYPE(nexthop_group_cmd); DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NHGNAME", "Enter into the nexthop-group submode\n" diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 5f7bde0def..8e75e5c6ac 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -97,12 +97,12 @@ struct nexthop_group_cmd { struct list *nhg_list; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(nhgc_entry_head, nexthp_group_cmd); RB_PROTOTYPE(nhgc_entry_head, nexthop_group_cmd, nhgc_entry, nexthop_group_cmd_compare) -DECLARE_QOBJ_TYPE(nexthop_group_cmd) +DECLARE_QOBJ_TYPE(nexthop_group_cmd); /* * Initialize nexthop_groups. If you are interested in when diff --git a/lib/northbound.c b/lib/northbound.c index b6d3518285..34ad5dbfa9 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -32,9 +32,9 @@ #include "northbound_db.h" #include "frrstr.h" -DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node") -DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration") -DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry") +DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node"); +DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration"); +DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry"); /* Running configuration - shouldn't be modified directly. */ struct nb_config *running_config; @@ -1260,27 +1260,36 @@ static int nb_callback_configuration(struct nb_context *context, } if (ret != NB_OK) { - int priority; - enum lib_log_refs ref; - yang_dnode_get_path(dnode, xpath, sizeof(xpath)); switch (event) { case NB_EV_VALIDATE: - priority = LOG_WARNING; - ref = EC_LIB_NB_CB_CONFIG_VALIDATE; + flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, + "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", + nb_err_name(ret), nb_event_name(event), + nb_operation_name(operation), xpath, + errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_PREPARE: - priority = LOG_WARNING; - ref = EC_LIB_NB_CB_CONFIG_PREPARE; + flog_warn(EC_LIB_NB_CB_CONFIG_PREPARE, + "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", + nb_err_name(ret), nb_event_name(event), + nb_operation_name(operation), xpath, + errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_ABORT: - priority = LOG_WARNING; - ref = EC_LIB_NB_CB_CONFIG_ABORT; + flog_warn(EC_LIB_NB_CB_CONFIG_ABORT, + "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", + nb_err_name(ret), nb_event_name(event), + nb_operation_name(operation), xpath, + errmsg[0] ? " message: " : "", errmsg); break; case NB_EV_APPLY: - priority = LOG_ERR; - ref = EC_LIB_NB_CB_CONFIG_APPLY; + flog_err(EC_LIB_NB_CB_CONFIG_APPLY, + "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s", + nb_err_name(ret), nb_event_name(event), + nb_operation_name(operation), xpath, + errmsg[0] ? " message: " : "", errmsg); break; default: flog_err(EC_LIB_DEVELOPMENT, @@ -1288,15 +1297,6 @@ static int nb_callback_configuration(struct nb_context *context, event, xpath); exit(1); } - - flog(priority, ref, - "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]", - nb_err_name(ret), nb_event_name(event), - nb_operation_name(operation), xpath); - if (strlen(errmsg) > 0) - flog(priority, ref, - "error processing configuration change: %s", - errmsg); } return ret; diff --git a/lib/northbound.h b/lib/northbound.h index 3e1342f985..417ecc81ea 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -474,6 +474,23 @@ struct nb_callbacks { int (*rpc)(struct nb_cb_rpc_args *args); /* + * Optional callback to compare the data nodes when printing + * the CLI commands associated with them. + * + * dnode1 + * The first data node to compare. + * + * dnode2 + * The second data node to compare. + * + * Returns: + * <0 when the CLI command for the dnode1 should be printed first + * >0 when the CLI command for the dnode2 should be printed first + * 0 when there is no difference + */ + int (*cli_cmp)(struct lyd_node *dnode1, struct lyd_node *dnode2); + + /* * Optional callback to show the CLI command associated to the given * YANG data node. * @@ -677,9 +694,9 @@ typedef int (*nb_oper_data_cb)(const struct lys_node *snode, /* Hooks. */ DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments), - (xpath, arguments)) -DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty)) -DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set)) + (xpath, arguments)); +DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty)); +DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set)); /* Northbound debugging records */ extern struct debug nb_dbg_cbs_config; diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index a2c8bc8633..f88c2161da 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -529,25 +529,6 @@ static int nb_cli_candidate_load_transaction(struct vty *vty, return CMD_SUCCESS; } -/* - * ly_iter_next_is_up: detects when iterating up on the yang model. - * - * This function detects whether next node in the iteration is upwards, - * then return the node otherwise return NULL. - */ -static struct lyd_node *ly_iter_next_up(const struct lyd_node *elem) -{ - /* Are we going downwards? Is this still not a leaf? */ - if (!(elem->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) - return NULL; - - /* Are there still leaves in this branch? */ - if (elem->next != NULL) - return NULL; - - return elem->parent; -} - /* Prepare the configuration for display. */ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults) { @@ -569,53 +550,80 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults) ly_native_ctx); } -void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root, - bool with_defaults) +static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root, + bool with_defaults) { - struct lyd_node *next, *child, *parent; - - LY_TREE_DFS_BEGIN (root, next, child) { - struct nb_node *nb_node; + struct nb_node *nb_node, *sort_node = NULL; + struct listnode *listnode; + struct lyd_node *child; + struct list *sort_list; + void *data; + LY_TREE_FOR (root->child, child) { nb_node = child->schema->priv; - if (!nb_node || !nb_node->cbs.cli_show) - goto next; - /* Skip default values. */ - if (!with_defaults && yang_dnode_is_default_recursive(child)) - goto next; - - (*nb_node->cbs.cli_show)(vty, child, with_defaults); - next: /* - * When transiting upwards in the yang model we should - * give the previous container/list node a chance to - * print its close vty output (e.g. "!" or "end-family" - * etc...). + * We finished processing current list, + * it's time to print the config. */ - parent = ly_iter_next_up(child); - if (parent != NULL) { - nb_node = parent->schema->priv; - if (nb_node && nb_node->cbs.cli_show_end) - (*nb_node->cbs.cli_show_end)(vty, parent); + if (sort_node && nb_node != sort_node) { + for (ALL_LIST_ELEMENTS_RO(sort_list, listnode, data)) + nb_cli_show_dnode_cmds(vty, data, + with_defaults); + + list_delete(&sort_list); + sort_node = NULL; } /* - * There is a possible path in this macro that ends up - * dereferencing child->parent->parent. We just null checked - * child->parent by checking (ly_iter_next_up(child) != NULL) - * above. - * - * I am not sure whether it is possible for the other - * conditions within this macro guarding the problem - * dereference to be satisfied when child->parent == NULL. + * If the config needs to be sorted, + * then add the dnode to the sorting + * list for later processing. */ -#ifndef __clang_analyzer__ - LY_TREE_DFS_END(root, next, child); -#endif + if (nb_node && nb_node->cbs.cli_cmp) { + if (!sort_node) { + sort_node = nb_node; + sort_list = list_new(); + sort_list->cmp = (int (*)(void *, void *)) + nb_node->cbs.cli_cmp; + } + + listnode_add_sort(sort_list, child); + continue; + } + + nb_cli_show_dnode_cmds(vty, child, with_defaults); + } + + if (sort_node) { + for (ALL_LIST_ELEMENTS_RO(sort_list, listnode, data)) + nb_cli_show_dnode_cmds(vty, data, with_defaults); + + list_delete(&sort_list); + sort_node = NULL; } } +void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root, + bool with_defaults) +{ + struct nb_node *nb_node; + + if (!with_defaults && yang_dnode_is_default_recursive(root)) + return; + + nb_node = root->schema->priv; + + if (nb_node && nb_node->cbs.cli_show) + (*nb_node->cbs.cli_show)(vty, root, with_defaults); + + if (!(root->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) + show_dnode_children_cmds(vty, root, with_defaults); + + if (nb_node && nb_node->cbs.cli_show_end) + (*nb_node->cbs.cli_show_end)(vty, root); +} + static void nb_cli_show_config_cmds(struct vty *vty, struct nb_config *config, bool with_defaults) { diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index 8acba9fd2b..3d8771ffbc 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -32,7 +32,7 @@ #include <confd_dp.h> #include <confd_maapi.h> -DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module") +DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module"); static struct debug nb_dbg_client_confd = {0, "Northbound client: ConfD"}; @@ -1483,4 +1483,5 @@ static int frr_confd_module_init(void) FRR_MODULE_SETUP(.name = "frr_confd", .version = FRR_VERSION, .description = "FRR ConfD integration module", - .init = frr_confd_module_init, ) + .init = frr_confd_module_init, +); diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index abdae993b1..d042e15dad 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -1412,4 +1412,5 @@ static int frr_grpc_module_init(void) FRR_MODULE_SETUP(.name = "frr_grpc", .version = FRR_VERSION, .description = "FRR gRPC northbound module", - .init = frr_grpc_module_init, ) + .init = frr_grpc_module_init, +); diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index c027f4de72..9fc640ceea 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -32,7 +32,7 @@ #include <sysrepo/values.h> #include <sysrepo/xpath.h> -DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module") +DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module"); static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"}; @@ -768,4 +768,5 @@ static int frr_sr_module_init(void) FRR_MODULE_SETUP(.name = "frr_sysrepo", .version = FRR_VERSION, .description = "FRR sysrepo integration module", - .init = frr_sr_module_init, ) + .init = frr_sr_module_init, +); diff --git a/lib/plist.c b/lib/plist.c index fe4689becd..92c8b8ee55 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -33,10 +33,10 @@ #include "plist_int.h" -DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST, "Prefix List") -DEFINE_MTYPE_STATIC(LIB, MPREFIX_LIST_STR, "Prefix List Str") -DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_ENTRY, "Prefix List Entry") -DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table") +DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST, "Prefix List"); +DEFINE_MTYPE_STATIC(LIB, MPREFIX_LIST_STR, "Prefix List Str"); +DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_ENTRY, "Prefix List Entry"); +DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table"); /* not currently changeable, code assumes bytes further down */ #define PLC_BITS 8 diff --git a/lib/prefix.c b/lib/prefix.c index 5e5c2d89a8..7dbb5f07f0 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -32,8 +32,8 @@ #include "printfrr.h" #include "vxlan.h" -DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix") -DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec") +DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix"); +DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec"); /* Maskbit. */ static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, @@ -1198,15 +1198,6 @@ int netmask_str2prefix_str(const char *net_str, const char *mask_str, return 1; } -/* Utility function for making IPv6 address string. */ -const char *inet6_ntoa(struct in6_addr addr) -{ - static char buf[INET6_ADDRSTRLEN]; - - inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN); - return buf; -} - /* converts to internal representation of mac address * returns 1 on success, 0 otherwise * format accepted: AA:BB:CC:DD:EE:FF @@ -1361,92 +1352,92 @@ char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len) } printfrr_ext_autoreg_p("EA", printfrr_ea) -static ssize_t printfrr_ea(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct ethaddr *mac = ptr; + char cbuf[ETHER_ADDR_STRLEN]; - if (mac) - prefix_mac2str(mac, buf, bsz); - else - strlcpy(buf, "NULL", bsz); + if (!mac) + return bputs(buf, "(null)"); - return 2; + /* need real length even if buffer is too short */ + prefix_mac2str(mac, cbuf, sizeof(cbuf)); + return bputs(buf, cbuf); } printfrr_ext_autoreg_p("IA", printfrr_ia) -static ssize_t printfrr_ia(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_ia(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct ipaddr *ipa = ptr; + char cbuf[INET6_ADDRSTRLEN]; - if (ipa) - ipaddr2str(ipa, buf, bsz); - else - strlcpy(buf, "NULL", bsz); + if (!ipa) + return bputs(buf, "(null)"); - return 2; + ipaddr2str(ipa, cbuf, sizeof(cbuf)); + return bputs(buf, cbuf); } printfrr_ext_autoreg_p("I4", printfrr_i4) -static ssize_t printfrr_i4(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_i4(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { - if (ptr) - inet_ntop(AF_INET, ptr, buf, bsz); - else - strlcpy(buf, "NULL", bsz); + char cbuf[INET_ADDRSTRLEN]; - return 2; + if (!ptr) + return bputs(buf, "(null)"); + + inet_ntop(AF_INET, ptr, cbuf, sizeof(cbuf)); + return bputs(buf, cbuf); } printfrr_ext_autoreg_p("I6", printfrr_i6) -static ssize_t printfrr_i6(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_i6(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { - if (ptr) - inet_ntop(AF_INET6, ptr, buf, bsz); - else - strlcpy(buf, "NULL", bsz); + char cbuf[INET6_ADDRSTRLEN]; - return 2; + if (!ptr) + return bputs(buf, "(null)"); + + inet_ntop(AF_INET6, ptr, cbuf, sizeof(cbuf)); + return bputs(buf, cbuf); } printfrr_ext_autoreg_p("FX", printfrr_pfx) -static ssize_t printfrr_pfx(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { - if (ptr) - prefix2str(ptr, buf, bsz); - else - strlcpy(buf, "NULL", bsz); + char cbuf[PREFIX_STRLEN]; + + if (!ptr) + return bputs(buf, "(null)"); - return 2; + prefix2str(ptr, cbuf, sizeof(cbuf)); + return bputs(buf, cbuf); } printfrr_ext_autoreg_p("SG4", printfrr_psg) -static ssize_t printfrr_psg(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_psg(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct prefix_sg *sg = ptr; - struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 }; + ssize_t ret = 0; - if (sg) { - if (sg->src.s_addr == INADDR_ANY) - bprintfrr(&fb, "(*,"); - else - bprintfrr(&fb, "(%pI4,", &sg->src); - - if (sg->grp.s_addr == INADDR_ANY) - bprintfrr(&fb, "*)"); - else - bprintfrr(&fb, "%pI4)", &sg->grp); + if (!sg) + return bputs(buf, "(null)"); - fb.pos[0] = '\0'; + if (sg->src.s_addr == INADDR_ANY) + ret += bputs(buf, "(*,"); + else + ret += bprintfrr(buf, "(%pI4,", &sg->src); - } else { - strlcpy(buf, "NULL", bsz); - } + if (sg->grp.s_addr == INADDR_ANY) + ret += bputs(buf, "*)"); + else + ret += bprintfrr(buf, "%pI4)", &sg->grp); - return 3; + return ret; } diff --git a/lib/prefix.h b/lib/prefix.h index b2f3b0592f..d7ee1b8e4c 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -504,8 +504,6 @@ extern void apply_mask_ipv6(struct prefix_ipv6 *); extern int ip6_masklen(struct in6_addr); extern void masklen2ip6(const int, struct in6_addr *); -extern const char *inet6_ntoa(struct in6_addr); - extern int is_zero_mac(const struct ethaddr *mac); extern bool is_mcast_mac(const struct ethaddr *mac); extern bool is_bcast_mac(const struct ethaddr *mac); diff --git a/lib/printf/glue.c b/lib/printf/glue.c index 29ca26ad5d..1147901236 100644 --- a/lib/printf/glue.c +++ b/lib/printf/glue.c @@ -210,15 +210,16 @@ void printfrr_ext_reg(const struct printfrr_ext *ext) exts[i] = ext; } -ssize_t printfrr_extp(char *buf, size_t sz, const char *fmt, int prec, +ssize_t printfrr_extp(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { + const char *fmt = ea->fmt; const struct printfrr_ext *ext; size_t i; for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) { if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0]) - return 0; + return -1; if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1]) continue; ext = exts[i]; @@ -226,20 +227,22 @@ ssize_t printfrr_extp(char *buf, size_t sz, const char *fmt, int prec, continue; if (strncmp(ext->match, fmt, strlen(ext->match))) continue; - return ext->print_ptr(buf, sz, fmt, prec, ptr); + ea->fmt += strlen(ext->match); + return ext->print_ptr(buf, ea, ptr); } - return 0; + return -1; } -ssize_t printfrr_exti(char *buf, size_t sz, const char *fmt, int prec, +ssize_t printfrr_exti(struct fbuf *buf, struct printfrr_eargs *ea, uintmax_t num) { + const char *fmt = ea->fmt; const struct printfrr_ext *ext; size_t i; for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) { if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0]) - return 0; + return -1; if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1]) continue; ext = exts[i]; @@ -247,7 +250,48 @@ ssize_t printfrr_exti(char *buf, size_t sz, const char *fmt, int prec, continue; if (strncmp(ext->match, fmt, strlen(ext->match))) continue; - return ext->print_int(buf, sz, fmt, prec, num); + ea->fmt += strlen(ext->match); + return ext->print_int(buf, ea, num); } - return 0; + return -1; +} + +printfrr_ext_autoreg_p("FB", printfrr_fb) +static ssize_t printfrr_fb(struct fbuf *out, struct printfrr_eargs *ea, + const void *ptr) +{ + const struct fbuf *in = ptr; + ptrdiff_t copy_len; + + if (!in) + return bputs(out, "NULL"); + + if (out) { + copy_len = MIN(in->pos - in->buf, + out->buf + out->len - out->pos); + if (copy_len > 0) { + memcpy(out->pos, in->buf, copy_len); + out->pos += copy_len; + } + } + + return in->pos - in->buf; +} + +printfrr_ext_autoreg_p("VA", printfrr_va) +static ssize_t printfrr_va(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + const struct va_format *vaf = ptr; + va_list ap; + + if (!vaf || !vaf->fmt || !vaf->va) + return bputs(buf, "NULL"); + + /* make sure we don't alter the data passed in - especially since + * bprintfrr (and thus this) might be called on the same format twice, + * when allocating a larger buffer in asnprintfrr() + */ + va_copy(ap, *vaf->va); + return vbprintfrr(buf, vaf->fmt, ap); } diff --git a/lib/printf/printflocal.h b/lib/printf/printflocal.h index 335e09872e..bac80e801c 100644 --- a/lib/printf/printflocal.h +++ b/lib/printf/printflocal.h @@ -100,6 +100,8 @@ int _frr_find_arguments(const char *, va_list, union arg **) DSO_LOCAL; int _frr_find_warguments(const wchar_t *, va_list, union arg **) DSO_LOCAL; #endif -/* returns number of bytes consumed for extended specifier */ -ssize_t printfrr_extp(char *, size_t, const char *, int, const void *) DSO_LOCAL; -ssize_t printfrr_exti(char *, size_t, const char *, int, uintmax_t) DSO_LOCAL; +/* returns number of bytes needed for full output, or -1 */ +ssize_t printfrr_extp(struct fbuf *, struct printfrr_eargs *ea, const void *) + DSO_LOCAL; +ssize_t printfrr_exti(struct fbuf *, struct printfrr_eargs *ea, uintmax_t) + DSO_LOCAL; diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c index a0634cde4b..49fa2b718f 100644 --- a/lib/printf/vfprintf.c +++ b/lib/printf/vfprintf.c @@ -138,7 +138,7 @@ __wcsconv(wchar_t *wcsarg, int prec) * write a uintmax_t in octal (plus one byte). */ #if UINTMAX_MAX <= UINT64_MAX -#define BUF 64 +#define BUF 80 #else #error "BUF must be large enough to format a uintmax_t" #endif @@ -147,7 +147,7 @@ __wcsconv(wchar_t *wcsarg, int prec) * Non-MT-safe version */ ssize_t -vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap) +vbprintfrr(struct fbuf *cb_in, const char *fmt0, va_list ap) { const char *fmt; /* format string */ int ch; /* character from fmt */ @@ -177,6 +177,9 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap) int nextarg; /* 1-based argument index */ va_list orgap; /* original argument pointer */ char *convbuf; /* wide to multibyte conversion result */ + char *extstart = NULL; /* where printfrr_ext* started printing */ + struct fbuf cb_copy, *cb; + struct fmt_outpos *opos; static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; @@ -268,6 +271,16 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap) argtable = NULL; nextarg = 1; va_copy(orgap, ap); + + if (cb_in) { + /* prevent printfrr exts from polluting cb->outpos */ + cb_copy = *cb_in; + cb_copy.outpos = NULL; + cb_copy.outpos_n = cb_copy.outpos_i = 0; + cb = &cb_copy; + } else + cb = NULL; + io_init(&io, cb); ret = 0; @@ -292,11 +305,16 @@ vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap) flags = 0; dprec = 0; - width = 0; + width = -1; prec = -1; sign = '\0'; ox[1] = '\0'; + if (cb_in && cb_in->outpos_i < cb_in->outpos_n) + opos = &cb_in->outpos[cb_in->outpos_i]; + else + opos = NULL; + rflag: ch = *fmt++; reswitch: switch (ch) { case ' ': @@ -438,15 +456,24 @@ reswitch: switch (ch) { ulval = SARG(); if (printfrr_ext_char(fmt[0])) { - n2 = printfrr_exti(buf, sizeof(buf), fmt, prec, + struct printfrr_eargs ea = { + .fmt = fmt, + .precision = prec, + .width = width, + .alt_repr = !!(flags & ALT), + .leftadj = !!(flags & LADJUST), + }; + + if (cb) + extstart = cb->pos; + + size = printfrr_exti(cb, &ea, (flags & INTMAX_SIZE) ? ujval : (uintmax_t)ulval); - if (n2 > 0) { - fmt += n2; - cp = buf; - size = strlen(cp); - sign = '\0'; - break; + if (size >= 0) { + fmt = ea.fmt; + width = ea.width; + goto ext_printed; } } if (flags & INTMAX_SIZE) { @@ -503,35 +530,6 @@ reswitch: switch (ch) { size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp); sign = '\0'; break; -#ifdef DANGEROUS_PERCENT_N - /* FRR does not use %n in printf formats. This is just left - * here in case someone tries to use %n and starts debugging - * why the f* it doesn't work - */ - case 'n': - /* - * Assignment-like behavior is specified if the - * value overflows or is otherwise unrepresentable. - * C99 says to use `signed char' for %hhn conversions. - */ - if (flags & LLONGINT) - *GETARG(long long *) = ret; - else if (flags & SIZET) - *GETARG(ssize_t *) = (ssize_t)ret; - else if (flags & PTRDIFFT) - *GETARG(ptrdiff_t *) = ret; - else if (flags & INTMAXT) - *GETARG(intmax_t *) = ret; - else if (flags & LONGINT) - *GETARG(long *) = ret; - else if (flags & SHORTINT) - *GETARG(short *) = ret; - else if (flags & CHARINT) - *GETARG(signed char *) = ret; - else - *GETARG(int *) = ret; - continue; /* no output */ -#endif case 'O': flags |= LONGINT; /*FALLTHROUGH*/ @@ -551,14 +549,24 @@ reswitch: switch (ch) { * -- ANSI X3J11 */ ptrval = GETARG(void *); - if (printfrr_ext_char(fmt[0]) && - (n2 = printfrr_extp(buf, sizeof(buf), - fmt, prec, ptrval)) > 0) { - fmt += n2; - cp = buf; - size = strlen(cp); - sign = '\0'; - break; + if (printfrr_ext_char(fmt[0])) { + struct printfrr_eargs ea = { + .fmt = fmt, + .precision = prec, + .width = width, + .alt_repr = !!(flags & ALT), + .leftadj = !!(flags & LADJUST), + }; + + if (cb) + extstart = cb->pos; + + size = printfrr_extp(cb, &ea, ptrval); + if (size >= 0) { + fmt = ea.fmt; + width = ea.width; + goto ext_printed; + } } ujval = (uintmax_t)(uintptr_t)ptrval; base = 16; @@ -662,6 +670,7 @@ number: if ((dprec = prec) >= 0) cp = buf; size = 1; sign = '\0'; + opos = NULL; break; } @@ -679,6 +688,9 @@ number: if ((dprec = prec) >= 0) * Compute actual size, so we know how much to pad. * size excludes decimal prec; realsz includes it. */ + if (width < 0) + width = 0; + realsz = dprec > size ? dprec : size; if (sign) realsz++; @@ -686,7 +698,7 @@ number: if ((dprec = prec) >= 0) realsz += 2; prsize = width > realsz ? width : realsz; - if ((unsigned)ret + prsize > INT_MAX) { + if ((unsigned int)ret + prsize > INT_MAX) { ret = EOF; errno = EOVERFLOW; goto error; @@ -696,6 +708,9 @@ number: if ((dprec = prec) >= 0) if ((flags & (LADJUST|ZEROPAD)) == 0) PAD(width - realsz, blanks); + if (opos) + opos->off_start = cb->pos - cb->buf; + /* prefix */ if (sign) PRINT(&sign, 1); @@ -713,6 +728,74 @@ number: if ((dprec = prec) >= 0) /* leading zeroes from decimal precision */ PAD(dprec - size, zeroes); PRINT(cp, size); + + if (opos) { + opos->off_end = cb->pos - cb->buf; + cb_in->outpos_i++; + } + + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + PAD(width - realsz, blanks); + + /* finally, adjust ret */ + ret += prsize; + + FLUSH(); /* copy out the I/O vectors */ + continue; + +ext_printed: + /* when we arrive here, a printfrr extension has written to cb + * (if non-NULL), but we still need to handle padding. The + * original cb->pos is in extstart; the return value from the + * ext is in size. + * + * Keep analogous to code above please. + */ + + if (width < 0) + width = 0; + + realsz = size; + prsize = width > realsz ? width : realsz; + if ((unsigned int)ret + prsize > INT_MAX) { + ret = EOF; + errno = EOVERFLOW; + goto error; + } + + /* right-adjusting blank padding - need to move the chars + * that the extension has already written. Should be very + * rare. + */ + if (cb && width > size && (flags & (LADJUST|ZEROPAD)) == 0) { + size_t nwritten = cb->pos - extstart; + size_t navail = cb->buf + cb->len - extstart; + size_t npad = width - realsz; + size_t nmove; + + if (navail < npad) + navail = 0; + else + navail -= npad; + nmove = MIN(nwritten, navail); + + memmove(extstart + npad, extstart, nmove); + + cb->pos = extstart; + PAD(npad, blanks); + cb->pos += nmove; + extstart += npad; + } + + io.avail = cb ? cb->len - (cb->pos - cb->buf) : 0; + + if (opos && extstart <= cb->pos) { + opos->off_start = extstart - cb->buf; + opos->off_end = cb->pos - cb->buf; + cb_in->outpos_i++; + } + /* left-adjusting padding (always blank) */ if (flags & LADJUST) PAD(width - realsz, blanks); @@ -730,6 +813,8 @@ error: free(convbuf); if ((argtable != NULL) && (argtable != statargtable)) free (argtable); + if (cb_in) + cb_in->pos = cb->pos; return (ret); /* NOTREACHED */ } diff --git a/lib/printfrr.h b/lib/printfrr.h index a775e1517b..4338ac3a2f 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -28,10 +28,17 @@ extern "C" { #endif +struct fmt_outpos { + unsigned int off_start, off_end; +}; + struct fbuf { char *buf; char *pos; size_t len; + + struct fmt_outpos *outpos; + size_t outpos_n, outpos_i; }; #define at(a, b) PRINTFRR(a, b) @@ -105,6 +112,8 @@ char *asnprintfrr(struct memtype *mt, char *out, size_t sz, */ #define printfrr_ext_char(ch) ((ch) >= 'A' && (ch) <= 'Z') +struct printfrr_eargs; + struct printfrr_ext { /* embedded string to minimize cache line pollution */ char match[8]; @@ -112,23 +121,80 @@ struct printfrr_ext { /* both can be given, if not the code continues searching * (you can do %pX and %dX in 2 different entries) * - * return value: number of bytes consumed from the format string, so - * you can consume extra flags (e.g. register for "%pX", consume - * "%pXfoo" or "%pXbar" for flags.) Convention is to make those flags - * lowercase letters or numbers. + * return value: number of bytes that would be printed if the buffer + * was large enough. be careful about not under-reporting this; + * otherwise asnprintf() & co. will get broken. Returning -1 means + * something went wrong & default %p/%d handling should be executed. * - * bsz is a compile-time constant in printf; it's gonna be relatively - * small. This isn't designed to print Shakespeare from a pointer. + * to consume extra input flags after %pXY, increment *fmt. It points + * at the first character after %pXY at entry. Convention is to make + * those flags lowercase letters or numbers. + */ + ssize_t (*print_ptr)(struct fbuf *buf, struct printfrr_eargs *info, + const void *); + ssize_t (*print_int)(struct fbuf *buf, struct printfrr_eargs *info, + uintmax_t); +}; + +/* additional information passed to extended formatters */ + +struct printfrr_eargs { + /* position in the format string. Points to directly after the + * extension specifier. Increment when consuming extra "flag + * characters". + */ + const char *fmt; + + /* %.1234x / %.*x + * not POSIX compatible when used with %p, will cause warnings from + * GCC & clang. Usable with %d. Not used by the printfrr() itself + * for extension specifiers, so essentially available as a "free" + * parameter. -1 if not specified. Value in the format string + * cannot be negative, but negative values can be passed with %.*x + */ + int precision; + + /* %1234x / %*x + * regular width specification. Internally handled by printfrr(), set + * to 0 if consumed by the extension in order to suppress standard + * width/padding behavior. 0 if not specified. * - * prec is the precision specifier (the 999 in "%.999p") -1 means - * none given (value in the format string cannot be negative) + * NB: always positive, even if a negative value is passed in with + * %*x. (The sign is used for the - flag.) */ - ssize_t (*print_ptr)(char *buf, size_t bsz, const char *fmt, int prec, - const void *); - ssize_t (*print_int)(char *buf, size_t bsz, const char *fmt, int prec, - uintmax_t); + int width; + + /* %#x + * "alternate representation" flag, not POSIX compatible when used + * with %p or %d, will cause warnings from GCC & clang. Not used by + * printfrr() itself for extension specifiers. + */ + bool alt_repr; + + /* %-x + * left-pad flag. Internally handled by printfrr() if width is + * nonzero. Only use if the extension sets width to 0. + */ + bool leftadj; }; +/* for any extension that needs a buffer length */ + +static inline ssize_t printfrr_ext_len(struct printfrr_eargs *ea) +{ + ssize_t rv; + + if (ea->precision >= 0) + rv = ea->precision; + else if (ea->width >= 0) { + rv = ea->width; + ea->width = -1; + } else + rv = -1; + + return rv; +} + /* no locking - must be called when single threaded (e.g. at startup.) * this restriction hopefully won't be a huge bother considering normal usage * scenarios... @@ -136,7 +202,7 @@ struct printfrr_ext { void printfrr_ext_reg(const struct printfrr_ext *); #define printfrr_ext_autoreg_p(matchs, print_fn) \ - static ssize_t print_fn(char *, size_t, const char *, int, \ + static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *, \ const void *); \ static const struct printfrr_ext _printext_##print_fn = { \ .match = matchs, \ @@ -149,7 +215,8 @@ void printfrr_ext_reg(const struct printfrr_ext *); /* end */ #define printfrr_ext_autoreg_i(matchs, print_fn) \ - static ssize_t print_fn(char *, size_t, const char *, int, uintmax_t); \ + static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *, \ + uintmax_t); \ static const struct printfrr_ext _printext_##print_fn = { \ .match = matchs, \ .print_int = print_fn, \ @@ -160,6 +227,92 @@ void printfrr_ext_reg(const struct printfrr_ext *); } \ /* end */ +/* fbuf helper functions - note all 3 of these return the length that would + * be written regardless of how much space was available in the buffer, as + * needed for implementing printfrr extensions. (They also accept NULL buf + * for that.) + */ + +static inline ssize_t bputs(struct fbuf *buf, const char *str) +{ + size_t len = strlen(str); + size_t ncopy; + + if (!buf) + return len; + + ncopy = MIN(len, (size_t)(buf->buf + buf->len - buf->pos)); + memcpy(buf->pos, str, ncopy); + buf->pos += ncopy; + + return len; +} + +static inline ssize_t bputch(struct fbuf *buf, char ch) +{ + if (buf && buf->pos < buf->buf + buf->len) + *buf->pos++ = ch; + return 1; +} + +static inline ssize_t bputhex(struct fbuf *buf, uint8_t val) +{ + static const char hexch[] = "0123456789abcdef"; + + if (buf && buf->pos < buf->buf + buf->len) + *buf->pos++ = hexch[(val >> 4) & 0xf]; + if (buf && buf->pos < buf->buf + buf->len) + *buf->pos++ = hexch[val & 0xf]; + return 2; +} + +/* %pVA extension, equivalent to Linux kernel %pV */ + +struct va_format { + const char *fmt; + va_list *va; +}; + +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pFB" (struct fbuf *) +#pragma FRR printfrr_ext "%pVA" (struct va_format *) + +#pragma FRR printfrr_ext "%pHX" (signed char *) +#pragma FRR printfrr_ext "%pHX" (unsigned char *) +#pragma FRR printfrr_ext "%pHX" (void *) +#pragma FRR printfrr_ext "%pHS" (signed char *) +#pragma FRR printfrr_ext "%pHS" (unsigned char *) +#pragma FRR printfrr_ext "%pHS" (void *) + +#pragma FRR printfrr_ext "%pSE" (char *) +#pragma FRR printfrr_ext "%pSQ" (char *) +#endif + +/* when using non-ISO-C compatible extension specifiers... */ + +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#define FMT_NSTD_BEGIN +#define FMT_NSTD_END +#else /* !_FRR_ATTRIBUTE_PRINTFRR */ +#define FMT_NSTD_BEGIN \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wformat\"") \ + /* end */ +#define FMT_NSTD_END \ + _Pragma("GCC diagnostic pop") \ + /* end */ +#endif + +#define FMT_NSTD(expr) \ + ({ \ + typeof(expr) _v; \ + FMT_NSTD_BEGIN \ + _v = expr; \ + FMT_NSTD_END \ + _v; \ + }) \ + /* end */ + #ifdef __cplusplus } #endif diff --git a/lib/privs.c b/lib/privs.c index 5ca3c0d886..49761af871 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -28,7 +28,7 @@ #include "lib_errors.h" #include "lib/queue.h" -DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information") +DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information"); /* * Different capabilities/privileges apis have different characteristics: some diff --git a/lib/pullwr.c b/lib/pullwr.c index 0c326f29d4..15563d2471 100644 --- a/lib/pullwr.c +++ b/lib/pullwr.c @@ -48,8 +48,8 @@ struct pullwr { int64_t maxspin; /* PULLWR_MAXSPIN */ }; -DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller") -DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF, "pull-driven write buffer") +DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller"); +DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF, "pull-driven write buffer"); static int pullwr_run(struct thread *t); diff --git a/lib/qobj.c b/lib/qobj.c index cb3254cbe9..c6cb36c058 100644 --- a/lib/qobj.c +++ b/lib/qobj.c @@ -43,7 +43,7 @@ static int qobj_cmp(const struct qobj_node *na, const struct qobj_node *nb) } DECLARE_HASH(qobj_nodes, struct qobj_node, nodehash, - qobj_cmp, qobj_hash) + qobj_cmp, qobj_hash); static pthread_rwlock_t nodes_lock; static struct qobj_nodes_head nodes = { }; diff --git a/lib/qobj.h b/lib/qobj.h index 400ae0151c..5012c98d74 100644 --- a/lib/qobj.h +++ b/lib/qobj.h @@ -83,7 +83,7 @@ struct qobj_nodetype { RESERVED_SPACE_STRUCT(qobj_nodetype_capnp, capnp, 256) }; -PREDECL_HASH(qobj_nodes) +PREDECL_HASH(qobj_nodes); /* anchor to be embedded somewhere in the object's struct */ struct qobj_node { @@ -92,7 +92,7 @@ struct qobj_node { const struct qobj_nodetype *type; }; -#define QOBJ_FIELDS struct qobj_node qobj_node; +#define QOBJ_FIELDS struct qobj_node qobj_node /* call these at the end of any _create function (QOBJ_REG) * and beginning of any _destroy function (QOBJ_UNREG) */ @@ -118,16 +118,19 @@ void *qobj_get_typed(uint64_t id, const struct qobj_nodetype *type); /* type declarations */ #define DECLARE_QOBJ_TYPE(structname) \ - extern const struct qobj_nodetype qobj_t_##structname; + extern const struct qobj_nodetype qobj_t_##structname \ + /* end */ #define DEFINE_QOBJ_TYPE(structname) \ const struct qobj_nodetype qobj_t_##structname = { \ .node_member_offset = \ - (ptrdiff_t)offsetof(struct structname, qobj_node)}; + (ptrdiff_t)offsetof(struct structname, qobj_node)} \ + /* end */ #define DEFINE_QOBJ_TYPE_INIT(structname, ...) \ const struct qobj_nodetype qobj_t_##structname = { \ .node_member_offset = \ (ptrdiff_t)offsetof(struct structname, qobj_node), \ - __VA_ARGS__}; + __VA_ARGS__} \ + /* end */ /* ID dereference with typecheck. * will return NULL if id not found or wrong type. */ diff --git a/lib/resolver.c b/lib/resolver.c index c01284e29e..c2153e0a5e 100644 --- a/lib/resolver.c +++ b/lib/resolver.c @@ -21,7 +21,7 @@ #include "command.h" #include "xref.h" -XREF_SETUP() +XREF_SETUP(); struct resolver_state { ares_channel channel; diff --git a/lib/ringbuf.c b/lib/ringbuf.c index 26c4e744b4..49221e7cb3 100644 --- a/lib/ringbuf.c +++ b/lib/ringbuf.c @@ -22,7 +22,7 @@ #include "ringbuf.h" #include "memory.h" -DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer") +DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer"); struct ringbuf *ringbuf_new(size_t size) { diff --git a/lib/routemap.c b/lib/routemap.c index 7714086672..33c65ac333 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -33,17 +33,17 @@ #include "lib_errors.h" #include "table.h" -DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map") -DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name") -DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index") -DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule") -DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str") -DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled") -DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency") -DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data") - -DEFINE_QOBJ_TYPE(route_map_index) -DEFINE_QOBJ_TYPE(route_map) +DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map"); +DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name"); +DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index"); +DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule"); +DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str"); +DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled"); +DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency"); +DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data"); + +DEFINE_QOBJ_TYPE(route_map_index); +DEFINE_QOBJ_TYPE(route_map); #define IPv4_PREFIX_LIST "ip address prefix-list" #define IPv6_PREFIX_LIST "ipv6 address prefix-list" @@ -87,112 +87,126 @@ struct route_map_match_set_hooks rmap_match_set_hook; /* match interface */ void route_map_match_interface_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_interface = func; } /* no match interface */ void route_map_no_match_interface_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_interface = func; } /* match ip address */ void route_map_match_ip_address_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_ip_address = func; } /* no match ip address */ void route_map_no_match_ip_address_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_ip_address = func; } /* match ip address prefix list */ void route_map_match_ip_address_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_ip_address_prefix_list = func; } /* no match ip address prefix list */ void route_map_no_match_ip_address_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_ip_address_prefix_list = func; } /* match ip next hop */ void route_map_match_ip_next_hop_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_ip_next_hop = func; } /* no match ip next hop */ void route_map_no_match_ip_next_hop_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_ip_next_hop = func; } /* match ip next hop prefix list */ void route_map_match_ip_next_hop_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_ip_next_hop_prefix_list = func; } /* no match ip next hop prefix list */ void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_ip_next_hop_prefix_list = func; } /* match ip next-hop type */ void route_map_match_ip_next_hop_type_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_ip_next_hop_type = func; } /* no match ip next-hop type */ void route_map_no_match_ip_next_hop_type_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_ip_next_hop_type = func; } /* match ipv6 address */ void route_map_match_ipv6_address_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_ipv6_address = func; } /* no match ipv6 address */ void route_map_no_match_ipv6_address_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_ipv6_address = func; } @@ -200,178 +214,183 @@ void route_map_no_match_ipv6_address_hook(int (*func)( /* match ipv6 address prefix list */ void route_map_match_ipv6_address_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_ipv6_address_prefix_list = func; } /* no match ipv6 address prefix list */ void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_ipv6_address_prefix_list = func; } /* match ipv6 next-hop type */ void route_map_match_ipv6_next_hop_type_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_ipv6_next_hop_type = func; } /* no match ipv6 next-hop type */ void route_map_no_match_ipv6_next_hop_type_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_ipv6_next_hop_type = func; } /* match metric */ void route_map_match_metric_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_metric = func; } /* no match metric */ void route_map_no_match_metric_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_metric = func; } /* match tag */ -void route_map_match_tag_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +void route_map_match_tag_hook(int (*func)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type)) + route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.match_tag = func; } /* no match tag */ void route_map_no_match_tag_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)) + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_match_tag = func; } /* set sr-te color */ -void route_map_set_srte_color_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +void route_map_set_srte_color_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)) + const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.set_srte_color = func; } /* no set sr-te color */ -void route_map_no_set_srte_color_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +void route_map_no_set_srte_color_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)) + const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_set_srte_color = func; } /* set ip nexthop */ -void route_map_set_ip_nexthop_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +void route_map_set_ip_nexthop_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)) + const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.set_ip_nexthop = func; } /* no set ip nexthop */ -void route_map_no_set_ip_nexthop_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +void route_map_no_set_ip_nexthop_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)) + const char *arg, + char *errmsg, + size_t errmsg_len)) { rmap_match_set_hook.no_set_ip_nexthop = func; } /* set ipv6 nexthop local */ void route_map_set_ipv6_nexthop_local_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)) + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.set_ipv6_nexthop_local = func; } /* no set ipv6 nexthop local */ void route_map_no_set_ipv6_nexthop_local_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)) + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_set_ipv6_nexthop_local = func; } /* set metric */ -void route_map_set_metric_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +void route_map_set_metric_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)) + const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.set_metric = func; } /* no set metric */ -void route_map_no_set_metric_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +void route_map_no_set_metric_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)) + const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_set_metric = func; } /* set tag */ -void route_map_set_tag_hook(int (*func)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg)) +void route_map_set_tag_hook(int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.set_tag = func; } /* no set tag */ -void route_map_no_set_tag_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)) + const char *arg, + char *errmsg, size_t errmsg_len)) { rmap_match_set_hook.no_set_tag = func; } -int generic_match_add(struct vty *vty, struct route_map_index *index, +int generic_match_add(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type) + route_map_event_t type, + char *errmsg, size_t errmsg_len) { enum rmap_compile_rets ret; ret = route_map_add_match(index, command, arg, type); switch (ret) { case RMAP_RULE_MISSING: - if (vty) - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - else - zlog_warn("Can't find rule: %s", command); + snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.", + frr_protonameinst); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_ERROR: - if (vty) - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - else - zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg); + snprintf(errmsg, errmsg_len, + "%% [%s] Argument form is unsupported or malformed.", + frr_protonameinst); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_SUCCESS: /* @@ -383,9 +402,10 @@ int generic_match_add(struct vty *vty, struct route_map_index *index, return CMD_SUCCESS; } -int generic_match_delete(struct vty *vty, struct route_map_index *index, +int generic_match_delete(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type) + route_map_event_t type, + char *errmsg, size_t errmsg_len) { enum rmap_compile_rets ret; int retval = CMD_SUCCESS; @@ -409,20 +429,14 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, ret = route_map_delete_match(index, command, dep_name, type); switch (ret) { case RMAP_RULE_MISSING: - if (vty) - vty_out(vty, "%% [%s] Can't find rule.\n", - frr_protonameinst); - else - zlog_warn("Can't find rule: %s", command); + snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.", + frr_protonameinst); retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_ERROR: - if (vty) - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - else - zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg); + snprintf(errmsg, errmsg_len, + "%% [%s] Argument form is unsupported or malformed.", + frr_protonameinst); retval = CMD_WARNING_CONFIG_FAILED; break; case RMAP_COMPILE_SUCCESS: @@ -438,26 +452,22 @@ int generic_match_delete(struct vty *vty, struct route_map_index *index, return retval; } -int generic_set_add(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg) +int generic_set_add(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len) { enum rmap_compile_rets ret; ret = route_map_add_set(index, command, arg); switch (ret) { case RMAP_RULE_MISSING: - if (vty) - vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); - else - zlog_warn("Can't find rule: %s", command); + snprintf(errmsg, errmsg_len, + "%% [%s] Can't find rule.", frr_protonameinst); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_ERROR: - if (vty) - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - else - zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg); + snprintf(errmsg, errmsg_len, + "%% [%s] Argument form is unsupported or malformed.", + frr_protonameinst); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_SUCCESS: break; @@ -466,26 +476,22 @@ int generic_set_add(struct vty *vty, struct route_map_index *index, return CMD_SUCCESS; } -int generic_set_delete(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg) +int generic_set_delete(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len) { enum rmap_compile_rets ret; ret = route_map_delete_set(index, command, arg); switch (ret) { case RMAP_RULE_MISSING: - if (vty) - vty_out(vty, "%% [%s] Can't find rule.\n", frr_protonameinst); - else - zlog_warn("Can't find rule: %s", command); + snprintf(errmsg, errmsg_len, "%% [%s] Can't find rule.", + frr_protonameinst); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_ERROR: - if (vty) - vty_out(vty, - "%% [%s] Argument form is unsupported or malformed.\n", - frr_protonameinst); - else - zlog_warn("Argument form is unsupported or malformed: %s %s", command, arg); + snprintf(errmsg, errmsg_len, + "%% [%s] Argument form is unsupported or malformed.", + frr_protonameinst); return CMD_WARNING_CONFIG_FAILED; case RMAP_COMPILE_SUCCESS: break; @@ -2627,47 +2633,6 @@ static unsigned int route_map_dep_data_hash_make_key(const void *p) return string_hash_make(dep_data->rname); } -DEFUN (set_srte_color, - set_srte_color_cmd, - "set sr-te color [(1-4294967295)]", - SET_STR - SRTE_STR - SRTE_COLOR_STR - "Color of the SR-TE Policies to match with\n") -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - int idx = 0; - char *arg = argv_find(argv, argc, "(1-4294967295)", &idx) - ? argv[idx]->arg - : NULL; - - if (rmap_match_set_hook.set_srte_color) - return rmap_match_set_hook.set_srte_color(vty, index, - "sr-te color", arg); - return CMD_SUCCESS; -} - -DEFUN (no_set_srte_color, - no_set_srte_color_cmd, - "no set sr-te color [(1-4294967295)]", - NO_STR - SET_STR - SRTE_STR - SRTE_COLOR_STR - "Color of the SR-TE Policies to match with\n") -{ - VTY_DECLVAR_CONTEXT(route_map_index, index); - int idx = 0; - char *arg = argv_find(argv, argc, "(1-4294967295)", &idx) - ? argv[idx]->arg - : NULL; - - if (rmap_match_set_hook.no_set_srte_color) - return rmap_match_set_hook.no_set_srte_color( - vty, index, "sr-te color", arg); - return CMD_SUCCESS; -} - static void *route_map_dep_hash_alloc(void *p) { char *dep_name = (char *)p; @@ -3279,8 +3244,5 @@ void route_map_init(void) install_element(RMAP_NODE, &routemap_optimization_cmd); install_element(RMAP_NODE, &no_routemap_optimization_cmd); - install_element(RMAP_NODE, &set_srte_color_cmd); - install_element(RMAP_NODE, &no_set_srte_color_cmd); - install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd); } diff --git a/lib/routemap.h b/lib/routemap.h index 3e208c8cb5..6385193bbf 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -32,9 +32,9 @@ extern "C" { #endif -DECLARE_MTYPE(ROUTE_MAP_NAME) -DECLARE_MTYPE(ROUTE_MAP_RULE) -DECLARE_MTYPE(ROUTE_MAP_COMPILED) +DECLARE_MTYPE(ROUTE_MAP_NAME); +DECLARE_MTYPE(ROUTE_MAP_RULE); +DECLARE_MTYPE(ROUTE_MAP_COMPILED); /* Route map's type. */ enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY }; @@ -190,9 +190,9 @@ struct route_map_index { /* List of match/sets contexts. */ TAILQ_HEAD(, routemap_hook_context) rhclist; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(route_map_index) +DECLARE_QOBJ_TYPE(route_map_index); /* Route map list structure. */ struct route_map { @@ -225,9 +225,147 @@ struct route_map { struct route_table *ipv4_prefix_table; struct route_table *ipv6_prefix_table; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(route_map) +DECLARE_QOBJ_TYPE(route_map); + +/* Route-map match conditions */ +#define IS_MATCH_INTERFACE(C) \ + (strmatch(C, "frr-route-map:interface")) +#define IS_MATCH_IPv4_ADDRESS_LIST(C) \ + (strmatch(C, "frr-route-map:ipv4-address-list")) +#define IS_MATCH_IPv6_ADDRESS_LIST(C) \ + (strmatch(C, "frr-route-map:ipv6-address-list")) +#define IS_MATCH_IPv4_NEXTHOP_LIST(C) \ + (strmatch(C, "frr-route-map:ipv4-next-hop-list")) +#define IS_MATCH_IPv4_PREFIX_LIST(C) \ + (strmatch(C, "frr-route-map:ipv4-prefix-list")) +#define IS_MATCH_IPv6_PREFIX_LIST(C) \ + (strmatch(C, "frr-route-map:ipv6-prefix-list")) +#define IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(C) \ + (strmatch(C, "frr-route-map:ipv4-next-hop-prefix-list")) +#define IS_MATCH_IPv4_NEXTHOP_TYPE(C) \ + (strmatch(C, "frr-route-map:ipv4-next-hop-type")) +#define IS_MATCH_IPv6_NEXTHOP_TYPE(C) \ + (strmatch(C, "frr-route-map:ipv6-next-hop-type")) +#define IS_MATCH_METRIC(C) \ + (strmatch(C, "frr-route-map:match-metric")) +#define IS_MATCH_TAG(C) (strmatch(C, "frr-route-map:match-tag")) +/* Zebra route-map match conditions */ +#define IS_MATCH_IPv4_PREFIX_LEN(C) \ + (strmatch(C, "frr-zebra-route-map:ipv4-prefix-length")) +#define IS_MATCH_IPv6_PREFIX_LEN(C) \ + (strmatch(C, "frr-zebra-route-map:ipv6-prefix-length")) +#define IS_MATCH_IPv4_NH_PREFIX_LEN(C) \ + (strmatch(C, "frr-zebra-route-map:ipv4-next-hop-prefix-length")) +#define IS_MATCH_SRC_PROTO(C) \ + (strmatch(C, "frr-zebra-route-map:source-protocol")) +#define IS_MATCH_SRC_INSTANCE(C) \ + (strmatch(C, "frr-zebra-route-map:source-instance")) +/* BGP route-map match conditions */ +#define IS_MATCH_LOCAL_PREF(C) \ + (strmatch(C, "frr-bgp-route-map:match-local-preference")) +#define IS_MATCH_ORIGIN(C) \ + (strmatch(C, "frr-bgp-route-map:match-origin")) +#define IS_MATCH_RPKI(C) (strmatch(C, "frr-bgp-route-map:rpki")) +#define IS_MATCH_PROBABILITY(C) \ + (strmatch(C, "frr-bgp-route-map:probability")) +#define IS_MATCH_SRC_VRF(C) \ + (strmatch(C, "frr-bgp-route-map:source-vrf")) +#define IS_MATCH_PEER(C) (strmatch(C, "frr-bgp-route-map:peer")) +#define IS_MATCH_AS_LIST(C) \ + (strmatch(C, "frr-bgp-route-map:as-path-list")) +#define IS_MATCH_MAC_LIST(C) \ + (strmatch(C, "frr-bgp-route-map:mac-address-list")) +#define IS_MATCH_EVPN_ROUTE_TYPE(C) \ + (strmatch(C, "frr-bgp-route-map:evpn-route-type")) +#define IS_MATCH_EVPN_DEFAULT_ROUTE(C) \ + (strmatch(C, "frr-bgp-route-map:evpn-default-route")) +#define IS_MATCH_EVPN_VNI(C) \ + (strmatch(C, "frr-bgp-route-map:evpn-vni")) +#define IS_MATCH_EVPN_DEFAULT_ROUTE(C) \ + (strmatch(C, "frr-bgp-route-map:evpn-default-route")) +#define IS_MATCH_EVPN_RD(C) \ + (strmatch(C, "frr-bgp-route-map:evpn-rd")) +#define IS_MATCH_ROUTE_SRC(C) \ + (strmatch(C, "frr-bgp-route-map:ip-route-source")) +#define IS_MATCH_ROUTE_SRC_PL(C) \ + (strmatch(C, "frr-bgp-route-map:ip-route-source-prefix-list")) +#define IS_MATCH_COMMUNITY(C) \ + (strmatch(C, "frr-bgp-route-map:match-community")) +#define IS_MATCH_LCOMMUNITY(C) \ + (strmatch(C, "frr-bgp-route-map:match-large-community")) +#define IS_MATCH_EXTCOMMUNITY(C) \ + (strmatch(C, "frr-bgp-route-map:match-extcommunity")) +#define IS_MATCH_IPV4_NH(C) \ + (strmatch(C, "frr-bgp-route-map:ipv4-nexthop")) +#define IS_MATCH_IPV6_NH(C) \ + (strmatch(C, "frr-bgp-route-map:ipv6-nexthop")) + +/* Route-map set actions */ +#define IS_SET_IPv4_NH(A) \ + (strmatch(A, "frr-route-map:ipv4-next-hop")) +#define IS_SET_IPv6_NH(A) \ + (strmatch(A, "frr-route-map:ipv6-next-hop")) +#define IS_SET_METRIC(A) \ + (strmatch(A, "frr-route-map:set-metric")) +#define IS_SET_TAG(A) (strmatch(A, "frr-route-map:set-tag")) +#define IS_SET_SR_TE_COLOR(A) \ + (strmatch(A, "frr-route-map:set-sr-te-color")) +/* Zebra route-map set actions */ +#define IS_SET_SRC(A) \ + (strmatch(A, "frr-zebra-route-map:src-address")) +/* OSPF route-map set actions */ +#define IS_SET_METRIC_TYPE(A) \ + (strmatch(A, "frr-ospf-route-map:metric-type")) +#define IS_SET_FORWARDING_ADDR(A) \ + (strmatch(A, "frr-ospf6-route-map:forwarding-address")) +/* BGP route-map_set actions */ +#define IS_SET_WEIGHT(A) \ + (strmatch(A, "frr-bgp-route-map:weight")) +#define IS_SET_TABLE(A) (strmatch(A, "frr-bgp-route-map:table")) +#define IS_SET_LOCAL_PREF(A) \ + (strmatch(A, "frr-bgp-route-map:set-local-preference")) +#define IS_SET_LABEL_INDEX(A) \ + (strmatch(A, "frr-bgp-route-map:label-index")) +#define IS_SET_DISTANCE(A) \ + (strmatch(A, "frr-bgp-route-map:distance")) +#define IS_SET_ORIGIN(A) \ + (strmatch(A, "frr-bgp-route-map:set-origin")) +#define IS_SET_ATOMIC_AGGREGATE(A) \ + (strmatch(A, "frr-bgp-route-map:atomic-aggregate")) +#define IS_SET_ORIGINATOR_ID(A) \ + (strmatch(A, "frr-bgp-route-map:originator-id")) +#define IS_SET_COMM_LIST_DEL(A) \ + (strmatch(A, "frr-bgp-route-map:comm-list-delete")) +#define IS_SET_LCOMM_LIST_DEL(A) \ + (strmatch(A, "frr-bgp-route-map:large-comm-list-delete")) +#define IS_SET_LCOMMUNITY(A) \ + (strmatch(A, "frr-bgp-route-map:set-large-community")) +#define IS_SET_COMMUNITY(A) \ + (strmatch(A, "frr-bgp-route-map:set-community")) +#define IS_SET_EXTCOMMUNITY_RT(A) \ + (strmatch(A, "frr-bgp-route-map:set-extcommunity-rt")) +#define IS_SET_EXTCOMMUNITY_SOO(A) \ + (strmatch(A, "frr-bgp-route-map:set-extcommunity-soo")) +#define IS_SET_AGGREGATOR(A) \ + (strmatch(A, "frr-bgp-route-map:aggregator")) +#define IS_SET_AS_PREPEND(A) \ + (strmatch(A, "frr-bgp-route-map:as-path-prepend")) +#define IS_SET_AS_EXCLUDE(A) \ + (strmatch(A, "frr-bgp-route-map:as-path-exclude")) +#define IS_SET_IPV6_NH_GLOBAL(A) \ + (strmatch(A, "frr-bgp-route-map:ipv6-nexthop-global")) +#define IS_SET_IPV6_VPN_NH(A) \ + (strmatch(A, "frr-bgp-route-map:ipv6-vpn-address")) +#define IS_SET_IPV6_PEER_ADDR(A) \ + (strmatch(A, "frr-bgp-route-map:ipv6-peer-address")) +#define IS_SET_IPV6_PREFER_GLOBAL(A) \ + (strmatch(A, "frr-bgp-route-map:ipv6-prefer-global")) +#define IS_SET_IPV4_VPN_NH(A) \ + (strmatch(A, "frr-bgp-route-map:ipv4-vpn-address")) +#define IS_SET_BGP_IPV4_NH(A) \ + (strmatch(A, "frr-bgp-route-map:set-ipv4-nexthop")) /* Prototypes. */ extern void route_map_init(void); @@ -310,150 +448,186 @@ extern void route_map_notify_pentry_dependencies(const char *affected_name, struct prefix_list_entry *pentry, route_map_event_t event); -extern int generic_match_add(struct vty *vty, struct route_map_index *index, +extern int generic_match_add(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); - -extern int generic_match_delete(struct vty *vty, struct route_map_index *index, + route_map_event_t type, + char *errmsg, size_t errmsg_len); +extern int generic_match_delete(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); -extern int generic_set_add(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); -extern int generic_set_delete(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + route_map_event_t type, + char *errmsg, size_t errmsg_len); + +extern int generic_set_add(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); +extern int generic_set_delete(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* match interface */ extern void route_map_match_interface_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match interface */ extern void route_map_no_match_interface_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match ip address */ extern void route_map_match_ip_address_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match ip address */ extern void route_map_no_match_ip_address_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match ip address prefix list */ extern void route_map_match_ip_address_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match ip address prefix list */ extern void route_map_no_match_ip_address_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match ip next hop */ extern void route_map_match_ip_next_hop_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match ip next hop */ extern void route_map_no_match_ip_next_hop_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match ip next hop prefix list */ extern void route_map_match_ip_next_hop_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match ip next hop prefix list */ extern void route_map_no_match_ip_next_hop_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match ip next hop type */ extern void route_map_match_ip_next_hop_type_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match ip next hop type */ extern void route_map_no_match_ip_next_hop_type_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match ipv6 address */ extern void route_map_match_ipv6_address_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match ipv6 address */ extern void route_map_no_match_ipv6_address_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match ipv6 address prefix list */ extern void route_map_match_ipv6_address_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match ipv6 address prefix list */ extern void route_map_no_match_ipv6_address_prefix_list_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match ipv6 next-hop type */ extern void route_map_match_ipv6_next_hop_type_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match ipv6 next-hop type */ extern void route_map_no_match_ipv6_next_hop_type_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match metric */ extern void route_map_match_metric_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match metric */ extern void route_map_no_match_metric_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* match tag */ extern void route_map_match_tag_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* no match tag */ extern void route_map_no_match_tag_hook(int (*func)( - struct vty *vty, struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type)); + struct route_map_index *index, const char *command, + const char *arg, route_map_event_t type, + char *errmsg, size_t errmsg_len)); /* set sr-te color */ extern void route_map_set_srte_color_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)); + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)); /* no set sr-te color */ extern void route_map_no_set_srte_color_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)); + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)); /* set ip nexthop */ extern void route_map_set_ip_nexthop_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)); + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)); /* no set ip nexthop */ extern void route_map_no_set_ip_nexthop_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)); + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)); /* set ipv6 nexthop local */ extern void route_map_set_ipv6_nexthop_local_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)); + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)); /* no set ipv6 nexthop local */ extern void route_map_no_set_ipv6_nexthop_local_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)); + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)); /* set metric */ -extern void route_map_set_metric_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +extern void route_map_set_metric_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)); + const char *arg, + char *errmsg, + size_t errmsg_len)); /* no set metric */ extern void route_map_no_set_metric_hook( - int (*func)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg)); + int (*func)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len)); /* set tag */ -extern void route_map_set_tag_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +extern void route_map_set_tag_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)); + const char *arg, + char *errmsg, + size_t errmsg_len)); /* no set tag */ -extern void route_map_no_set_tag_hook(int (*func)(struct vty *vty, - struct route_map_index *index, +extern void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index, const char *command, - const char *arg)); + const char *arg, + char *errmsg, + size_t errmsg_len)); extern void *route_map_rule_tag_compile(const char *arg); extern void route_map_rule_tag_free(void *rule); @@ -467,181 +641,200 @@ extern void route_map_counter_decrement(struct route_map *map); /* Route map hooks data structure. */ struct route_map_match_set_hooks { /* match interface */ - int (*match_interface)(struct vty *vty, struct route_map_index *index, + int (*match_interface)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match interface */ - int (*no_match_interface)(struct vty *vty, - struct route_map_index *index, + int (*no_match_interface)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* match ip address */ - int (*match_ip_address)(struct vty *vty, struct route_map_index *index, + int (*match_ip_address)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match ip address */ - int (*no_match_ip_address)(struct vty *vty, - struct route_map_index *index, + int (*no_match_ip_address)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* match ip address prefix list */ - int (*match_ip_address_prefix_list)(struct vty *vty, - struct route_map_index *index, + int (*match_ip_address_prefix_list)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match ip address prefix list */ - int (*no_match_ip_address_prefix_list)(struct vty *vty, - struct route_map_index *index, + int (*no_match_ip_address_prefix_list)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* match ip next hop */ - int (*match_ip_next_hop)(struct vty *vty, struct route_map_index *index, + int (*match_ip_next_hop)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match ip next hop */ - int (*no_match_ip_next_hop)(struct vty *vty, - struct route_map_index *index, + int (*no_match_ip_next_hop)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* match ip next hop prefix list */ - int (*match_ip_next_hop_prefix_list)(struct vty *vty, - struct route_map_index *index, + int (*match_ip_next_hop_prefix_list)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match ip next hop prefix list */ - int (*no_match_ip_next_hop_prefix_list)(struct vty *vty, - struct route_map_index *index, + int (*no_match_ip_next_hop_prefix_list)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, + size_t errmsg_len); /* match ip next-hop type */ - int (*match_ip_next_hop_type)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); + int (*match_ip_next_hop_type)(struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type, + char *errmsg, + size_t errmsg_len); /* no match ip next-hop type */ - int (*no_match_ip_next_hop_type)(struct vty *vty, - struct route_map_index *index, - const char *command, - const char *arg, - route_map_event_t type); + int (*no_match_ip_next_hop_type)(struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type, + char *errmsg, + size_t errmsg_len); /* match ipv6 address */ - int (*match_ipv6_address)(struct vty *vty, - struct route_map_index *index, + int (*match_ipv6_address)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match ipv6 address */ - int (*no_match_ipv6_address)(struct vty *vty, - struct route_map_index *index, + int (*no_match_ipv6_address)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* match ipv6 address prefix list */ - int (*match_ipv6_address_prefix_list)(struct vty *vty, - struct route_map_index *index, + int (*match_ipv6_address_prefix_list)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match ipv6 address prefix list */ - int (*no_match_ipv6_address_prefix_list)(struct vty *vty, - struct route_map_index *index, + int (*no_match_ipv6_address_prefix_list)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, + size_t errmsg_len); /* match ipv6 next-hop type */ - int (*match_ipv6_next_hop_type)(struct vty *vty, - struct route_map_index *index, + int (*match_ipv6_next_hop_type)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match ipv6 next-hop type */ - int (*no_match_ipv6_next_hop_type)(struct vty *vty, - struct route_map_index *index, + int (*no_match_ipv6_next_hop_type)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* match metric */ - int (*match_metric)(struct vty *vty, struct route_map_index *index, + int (*match_metric)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match metric */ - int (*no_match_metric)(struct vty *vty, struct route_map_index *index, + int (*no_match_metric)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* match tag */ - int (*match_tag)(struct vty *vty, struct route_map_index *index, + int (*match_tag)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* no match tag */ - int (*no_match_tag)(struct vty *vty, struct route_map_index *index, + int (*no_match_tag)(struct route_map_index *index, const char *command, const char *arg, - route_map_event_t type); + route_map_event_t type, + char *errmsg, size_t errmsg_len); /* set sr-te color */ - int (*set_srte_color)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + int (*set_srte_color)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* no set sr-te color */ - int (*no_set_srte_color)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + int (*no_set_srte_color)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* set ip nexthop */ - int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + int (*set_ip_nexthop)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* no set ip nexthop */ - int (*no_set_ip_nexthop)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + int (*no_set_ip_nexthop)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* set ipv6 nexthop local */ - int (*set_ipv6_nexthop_local)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg); + int (*set_ipv6_nexthop_local)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* no set ipv6 nexthop local */ - int (*no_set_ipv6_nexthop_local)(struct vty *vty, - struct route_map_index *index, - const char *command, const char *arg); + int (*no_set_ipv6_nexthop_local)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* set metric */ - int (*set_metric)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + int (*set_metric)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* no set metric */ - int (*no_set_metric)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + int (*no_set_metric)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* set tag */ - int (*set_tag)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + int (*set_tag)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); /* no set tag */ - int (*no_set_tag)(struct vty *vty, struct route_map_index *index, - const char *command, const char *arg); + int (*no_set_tag)(struct route_map_index *index, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); }; extern struct route_map_match_set_hooks rmap_match_set_hook; @@ -666,15 +859,13 @@ extern struct route_map_index *route_map_index_get(struct route_map *map, extern void route_map_index_delete(struct route_map_index *index, int notify); /* routemap_northbound.c */ -typedef int (*routemap_match_hook_fun)(struct vty *vty, - struct route_map_index *rmi, +typedef int (*routemap_match_hook_fun)(struct route_map_index *rmi, const char *command, const char *arg, - route_map_event_t event); - -typedef int (*routemap_set_hook_fun)(struct vty *vty, - struct route_map_index *rmi, - const char *command, const char *arg); - + route_map_event_t event, + char *errmsg, size_t errmsg_len); +typedef int (*routemap_set_hook_fun)(struct route_map_index *rmi, + const char *command, const char *arg, + char *errmsg, size_t errmsg_len); struct routemap_hook_context { struct route_map_index *rhc_rmi; const char *rhc_rule; @@ -694,6 +885,8 @@ void routemap_hook_context_free(struct routemap_hook_context *rhc); extern const struct frr_yang_module_info frr_route_map_info; /* routemap_cli.c */ +extern int route_map_instance_cmp(struct lyd_node *dnode1, + struct lyd_node *dnode2); extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults); extern void route_map_instance_show_end(struct vty *vty, diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 339d025124..9a53c11a4c 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -46,9 +46,6 @@ DEFPY_YANG_NOSH( ROUTE_MAP_OP_CMD_STR ROUTE_MAP_SEQUENCE_CMD_STR) { - struct route_map_index *rmi; - struct route_map *rm; - int action_type; char xpath_action[XPATH_MAXLEN + 64]; char xpath_index[XPATH_MAXLEN + 32]; char xpath[XPATH_MAXLEN]; @@ -66,17 +63,9 @@ DEFPY_YANG_NOSH( nb_cli_enqueue_change(vty, xpath_action, NB_OP_MODIFY, action); rv = nb_cli_apply_changes(vty, NULL); - if (rv == CMD_SUCCESS) { + if (rv == CMD_SUCCESS) VTY_PUSH_XPATH(RMAP_NODE, xpath_index); - /* Add support for non-migrated route map users. */ - nb_cli_pending_commit_check(vty); - rm = route_map_get(name); - action_type = (action[0] == 'p') ? RMAP_PERMIT : RMAP_DENY; - rmi = route_map_index_get(rm, action_type, sequence); - VTY_PUSH_CONTEXT(RMAP_NODE, rmi); - } - return rv; } @@ -108,71 +97,29 @@ DEFPY_YANG( snprintf(xpath, sizeof(xpath), "/frr-route-map:lib/route-map[name='%s']/entry[sequence='%lu']", name, sequence); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } +int route_map_instance_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +{ + uint16_t seq1 = yang_dnode_get_uint16(dnode1, "./sequence"); + uint16_t seq2 = yang_dnode_get_uint16(dnode2, "./sequence"); + + return seq1 - seq2; +} + void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - const struct route_map_rule *rmr; - const struct route_map_index *rmi; const char *name = yang_dnode_get_string(dnode, "../name"); const char *action = yang_dnode_get_string(dnode, "./action"); const char *sequence = yang_dnode_get_string(dnode, "./sequence"); vty_out(vty, "route-map %s %s %s\n", name, action, sequence); - rmi = nb_running_get_entry(dnode, NULL, false); - if (rmi == NULL) { - /* - * We can't have outdated rules if route map hasn't - * been created yet. - */ - return; - } - -#define SKIP_RULE(name) if (strcmp((name), rmr->cmd->str) == 0) continue - - /* Print route map `match` for old CLI users. */ - for (rmr = rmi->match_list.head; rmr; rmr = rmr->next) { - /* Skip all matches implemented by northbound. */ - SKIP_RULE("interface"); - SKIP_RULE("ip address"); - SKIP_RULE("ip address prefix-list"); - SKIP_RULE("ip next-hop"); - SKIP_RULE("ip next-hop prefix-list"); - SKIP_RULE("ip next-hop type"); - SKIP_RULE("ipv6 address"); - SKIP_RULE("ipv6 address prefix-list"); - SKIP_RULE("ipv6 next-hop type"); - SKIP_RULE("metric"); - SKIP_RULE("tag"); - /* Zebra specific match conditions. */ - SKIP_RULE("ip address prefix-len"); - SKIP_RULE("ipv6 address prefix-len"); - SKIP_RULE("ip next-hop prefix-len"); - SKIP_RULE("source-protocol"); - SKIP_RULE("source-instance"); - - vty_out(vty, " match %s %s\n", rmr->cmd->str, - rmr->rule_str ? rmr->rule_str : ""); - } - - /* Print route map `set` for old CLI users. */ - for (rmr = rmi->set_list.head; rmr; rmr = rmr->next) { - /* Skip all sets implemented by northbound. */ - SKIP_RULE("metric"); - SKIP_RULE("tag"); - /* Zebra specific set actions. */ - SKIP_RULE("src"); - - vty_out(vty, " set %s %s\n", rmr->cmd->str, - rmr->rule_str ? rmr->rule_str : ""); - } - -#undef SKIP_RULE } void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode) @@ -187,11 +134,13 @@ DEFPY_YANG( "Match first hop interface of route\n" INTERFACE_STR) { - const char *xpath = "./match-condition[condition='interface']"; + const char *xpath = + "./match-condition[condition='frr-route-map:interface']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/interface", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/interface", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ifname); return nb_cli_apply_changes(vty, NULL); @@ -205,7 +154,8 @@ DEFPY_YANG( "Match first hop interface of route\n" INTERFACE_STR) { - const char *xpath = "./match-condition[condition='interface']"; + const char *xpath = + "./match-condition[condition='frr-route-map:interface']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -222,11 +172,13 @@ DEFPY_YANG( "IP access-list number (expanded range)\n" "IP Access-list name\n") { - const char *xpath = "./match-condition[condition='ipv4-address-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv4-address-list']"; char xpath_value[XPATH_MAXLEN + 32]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/list-name", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); return nb_cli_apply_changes(vty, NULL); @@ -243,7 +195,8 @@ DEFPY_YANG( "IP access-list number (expanded range)\n" "IP Access-list name\n") { - const char *xpath = "./match-condition[condition='ipv4-address-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv4-address-list']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -260,11 +213,13 @@ DEFPY_YANG( "Match entries of prefix-lists\n" "IP prefix-list name\n") { - const char *xpath = "./match-condition[condition='ipv4-prefix-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv4-prefix-list']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/list-name", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); return nb_cli_apply_changes(vty, NULL); @@ -280,7 +235,8 @@ DEFPY_YANG( "Match entries of prefix-lists\n" "IP prefix-list name\n") { - const char *xpath = "./match-condition[condition='ipv4-prefix-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv4-prefix-list']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -297,11 +253,13 @@ DEFPY_YANG( "IP access-list number (expanded range)\n" "IP Access-list name\n") { - const char *xpath = "./match-condition[condition='ipv4-next-hop-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv4-next-hop-list']"; char xpath_value[XPATH_MAXLEN + 32]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/list-name", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); return nb_cli_apply_changes(vty, NULL); @@ -318,7 +276,8 @@ DEFPY_YANG( "IP access-list number (expanded range)\n" "IP Access-list name\n") { - const char *xpath = "./match-condition[condition='ipv4-next-hop-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv4-next-hop-list']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -336,11 +295,12 @@ DEFPY_YANG( "IP prefix-list name\n") { const char *xpath = - "./match-condition[condition='ipv4-next-hop-prefix-list']"; + "./match-condition[condition='frr-route-map:ipv4-next-hop-prefix-list']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/list-name", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); return nb_cli_apply_changes(vty, NULL); @@ -358,7 +318,7 @@ DEFPY_YANG( "IP prefix-list name\n") { const char *xpath = - "./match-condition[condition='ipv4-next-hop-prefix-list']"; + "./match-condition[condition='frr-route-map:ipv4-next-hop-prefix-list']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -374,12 +334,13 @@ DEFPY_YANG( "Match entries by type\n" "Blackhole\n") { - const char *xpath = "./match-condition[condition='ipv4-next-hop-type']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv4-next-hop-type']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-next-hop-type", - xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/ipv4-next-hop-type", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type); return nb_cli_apply_changes(vty, NULL); @@ -393,7 +354,8 @@ DEFPY_YANG( "Match entries by type\n" "Blackhole\n") { - const char *xpath = "./match-condition[condition='ipv4-next-hop-type']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv4-next-hop-type']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -408,11 +370,13 @@ DEFPY_YANG( "Match IPv6 address of route\n" "IPv6 access-list name\n") { - const char *xpath = "./match-condition[condition='ipv6-address-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-address-list']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/list-name", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); return nb_cli_apply_changes(vty, NULL); @@ -427,7 +391,8 @@ DEFPY_YANG( "Match IPv6 address of route\n" "IPv6 access-list name\n") { - const char *xpath = "./match-condition[condition='ipv6-address-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-address-list']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -443,11 +408,13 @@ DEFPY_YANG( "Match entries of prefix-lists\n" "IP prefix-list name\n") { - const char *xpath = "./match-condition[condition='ipv6-prefix-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-prefix-list']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/list-name", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/list-name", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, name); return nb_cli_apply_changes(vty, NULL); @@ -464,7 +431,8 @@ DEFPY_YANG( "Match entries of prefix-lists\n" "IP prefix-list name\n") { - const char *xpath = "./match-condition[condition='ipv6-prefix-list']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-prefix-list']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -479,12 +447,13 @@ DEFPY_YANG( "Match entries by type\n" "Blackhole\n") { - const char *xpath = "./match-condition[condition='ipv6-next-hop-type']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-next-hop-type']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-next-hop-type", - xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/ipv6-next-hop-type", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, type); return nb_cli_apply_changes(vty, NULL); @@ -498,7 +467,8 @@ DEFPY_YANG( "Match entries by type\n" "Blackhole\n") { - const char *xpath = "./match-condition[condition='ipv6-next-hop-type']"; + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-next-hop-type']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -512,11 +482,13 @@ DEFPY_YANG( "Match metric of route\n" "Metric value\n") { - const char *xpath = "./match-condition[condition='metric']"; + const char *xpath = + "./match-condition[condition='frr-route-map:match-metric']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/metric", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/metric", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, metric_str); return nb_cli_apply_changes(vty, NULL); @@ -530,7 +502,8 @@ DEFPY_YANG( "Match metric of route\n" "Metric value\n") { - const char *xpath = "./match-condition[condition='metric']"; + const char *xpath = + "./match-condition[condition='frr-route-map:match-metric']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -544,11 +517,13 @@ DEFPY_YANG( "Match tag of route\n" "Tag value\n") { - const char *xpath = "./match-condition[condition='tag']"; + const char *xpath = + "./match-condition[condition='frr-route-map:match-tag']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/tag", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str); return nb_cli_apply_changes(vty, NULL); @@ -562,7 +537,8 @@ DEFPY_YANG( "Match tag of route\n" "Tag value\n") { - const char *xpath = "./match-condition[condition='tag']"; + const char *xpath = + "./match-condition[condition='frr-route-map:match-tag']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -572,78 +548,259 @@ DEFPY_YANG( void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - int condition = yang_dnode_get_enum(dnode, "./condition"); + const char *condition = yang_dnode_get_string(dnode, "./condition"); + struct lyd_node *ln; + const char *acl; - switch (condition) { - case 0: /* interface */ + if (IS_MATCH_INTERFACE(condition)) { vty_out(vty, " match interface %s\n", - yang_dnode_get_string(dnode, "./interface")); - break; - case 1: /* ipv4-address-list */ - case 3: /* ipv4-next-hop-list */ - switch (condition) { - case 1: - vty_out(vty, " match ip address %s\n", - yang_dnode_get_string(dnode, "./list-name")); - break; - case 3: - vty_out(vty, " match ip next-hop %s\n", - yang_dnode_get_string(dnode, "./list-name")); - break; - } - break; - case 2: /* ipv4-prefix-list */ + yang_dnode_get_string( + dnode, "./rmap-match-condition/interface")); + } else if (IS_MATCH_IPv4_ADDRESS_LIST(condition) + || IS_MATCH_IPv4_NEXTHOP_LIST(condition)) { + acl = NULL; + if ((ln = yang_dnode_get(dnode, + "./rmap-match-condition/list-name")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + + assert(acl); + + if (IS_MATCH_IPv4_ADDRESS_LIST(condition)) + vty_out(vty, " match ip address %s\n", acl); + else + vty_out(vty, " match ip next-hop %s\n", acl); + } else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) { vty_out(vty, " match ip address prefix-list %s\n", - yang_dnode_get_string(dnode, "./list-name")); - break; - case 4: /* ipv4-next-hop-prefix-list */ + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); + } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) { vty_out(vty, " match ip next-hop prefix-list %s\n", - yang_dnode_get_string(dnode, "./list-name")); - break; - case 5: /* ipv4-next-hop-type */ - vty_out(vty, " match ip next-hop type %s\n", - yang_dnode_get_string(dnode, "./ipv4-next-hop-type")); - break; - case 6: /* ipv6-address-list */ + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); + } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) { vty_out(vty, " match ipv6 address %s\n", - yang_dnode_get_string(dnode, "./list-name")); - break; - case 7: /* ipv6-prefix-list */ + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); + } else if (IS_MATCH_IPv6_PREFIX_LIST(condition)) { vty_out(vty, " match ipv6 address prefix-list %s\n", - yang_dnode_get_string(dnode, "./list-name")); - break; - case 8: /* ipv6-next-hop-type */ + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); + } else if (IS_MATCH_IPv4_NEXTHOP_TYPE(condition)) { + vty_out(vty, " match ip next-hop type %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/ipv4-next-hop-type")); + } else if (IS_MATCH_IPv6_NEXTHOP_TYPE(condition)) { vty_out(vty, " match ipv6 next-hop type %s\n", - yang_dnode_get_string(dnode, "./ipv6-next-hop-type")); - break; - case 9: /* metric */ + yang_dnode_get_string( + dnode, + "./rmap-match-condition/ipv6-next-hop-type")); + } else if (IS_MATCH_METRIC(condition)) { vty_out(vty, " match metric %s\n", - yang_dnode_get_string(dnode, "./metric")); - break; - case 10: /* tag */ + yang_dnode_get_string(dnode, + "./rmap-match-condition/metric")); + } else if (IS_MATCH_TAG(condition)) { vty_out(vty, " match tag %s\n", - yang_dnode_get_string(dnode, "./tag")); - break; - case 100: /* ipv4-prefix-length */ + yang_dnode_get_string(dnode, + "./rmap-match-condition/tag")); + } else if (IS_MATCH_IPv4_PREFIX_LEN(condition)) { vty_out(vty, " match ip address prefix-len %s\n", - yang_dnode_get_string(dnode,"./frr-zebra:ipv4-prefix-length")); - break; - case 101: /* ipv6-prefix-length */ + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length")); + } else if (IS_MATCH_IPv6_PREFIX_LEN(condition)) { vty_out(vty, " match ipv6 address prefix-len %s\n", - yang_dnode_get_string(dnode, "./frr-zebra:ipv6-prefix-length")); - break; - case 102: /* ipv4-next-hop-prefix-length */ + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length")); + } else if (IS_MATCH_IPv4_NH_PREFIX_LEN(condition)) { vty_out(vty, " match ip next-hop prefix-len %s\n", - yang_dnode_get_string(dnode, "./frr-zebra:ipv4-prefix-length")); - break; - case 103: /* source-protocol */ + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length")); + } else if (IS_MATCH_SRC_PROTO(condition)) { vty_out(vty, " match source-protocol %s\n", - yang_dnode_get_string(dnode, "./frr-zebra:source-protocol")); - break; - case 104: /* source-instance */ + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-zebra-route-map:source-protocol")); + } else if (IS_MATCH_SRC_INSTANCE(condition)) { vty_out(vty, " match source-instance %s\n", - yang_dnode_get_string(dnode, "./frr-zebra:source-instance")); - break; + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-zebra-route-map:source-instance")); + } else if (IS_MATCH_LOCAL_PREF(condition)) { + vty_out(vty, " match local-preference %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:local-preference")); + } else if (IS_MATCH_ORIGIN(condition)) { + vty_out(vty, " match origin %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:origin")); + } else if (IS_MATCH_RPKI(condition)) { + vty_out(vty, " match rpki %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:rpki")); + } else if (IS_MATCH_PROBABILITY(condition)) { + vty_out(vty, " match probability %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:probability")); + } else if (IS_MATCH_SRC_VRF(condition)) { + vty_out(vty, " match source-vrf %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:source-vrf")); + } else if (IS_MATCH_PEER(condition)) { + acl = NULL; + if ((ln = yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:peer-ipv4-address")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + else if ( + (ln = yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:peer-ipv6-address")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + else if ( + (ln = yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:peer-interface")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + else if (yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:peer-local") + != NULL) + acl = "local"; + + vty_out(vty, " match peer %s\n", acl); + } else if (IS_MATCH_AS_LIST(condition)) { + vty_out(vty, " match as-path %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:list-name")); + } else if (IS_MATCH_EVPN_ROUTE_TYPE(condition)) { + vty_out(vty, " match evpn route-type %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:evpn-route-type")); + } else if (IS_MATCH_EVPN_DEFAULT_ROUTE(condition)) { + vty_out(vty, " match evpn default-route\n"); + } else if (IS_MATCH_EVPN_VNI(condition)) { + vty_out(vty, " match evpn vni %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:evpn-vni")); + } else if (IS_MATCH_EVPN_DEFAULT_ROUTE(condition)) { + vty_out(vty, " match evpn default-route %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:evpn-default-route")); + } else if (IS_MATCH_EVPN_RD(condition)) { + vty_out(vty, " match evpn rd %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:route-distinguisher")); + } else if (IS_MATCH_MAC_LIST(condition)) { + vty_out(vty, " match mac address %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:list-name")); + } else if (IS_MATCH_ROUTE_SRC(condition)) { + acl = NULL; + if ((ln = yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:list-name")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + + assert(acl); + + vty_out(vty, " match ip route-source %s\n", acl); + } else if (IS_MATCH_ROUTE_SRC_PL(condition)) { + vty_out(vty, " match ip route-source prefix-list %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:list-name")); + } else if (IS_MATCH_ROUTE_SRC(condition)) { + acl = NULL; + if ((ln = yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:list-name")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + + assert(acl); + + vty_out(vty, " match ip route-source %s\n", acl); + } else if (IS_MATCH_COMMUNITY(condition)) { + acl = NULL; + if ((ln = yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")) + != NULL) { + acl = yang_dnode_get_string(ln, NULL); + + if (true + == yang_dnode_get_bool( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) + vty_out(vty, + " match community %s exact-match\n", + acl); + else + vty_out(vty, " match community %s\n", acl); + } + + assert(acl); + } else if (IS_MATCH_LCOMMUNITY(condition)) { + acl = NULL; + if ((ln = yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")) + != NULL) { + acl = yang_dnode_get_string(ln, NULL); + + if (true + == yang_dnode_get_bool( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) + vty_out(vty, + " match large-community %s exact-match\n", + acl); + else + vty_out(vty, " match large-community %s\n", + acl); + } + + assert(acl); + } else if (IS_MATCH_EXTCOMMUNITY(condition)) { + acl = NULL; + if ((ln = yang_dnode_get( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + + assert(acl); + + vty_out(vty, " match extcommunity %s\n", acl); + } else if (IS_MATCH_IPV4_NH(condition)) { + vty_out(vty, " match ip next-hop %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:ipv4-address")); + } else if (IS_MATCH_IPV6_NH(condition)) { + vty_out(vty, " match ipv6 next-hop %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:ipv6-address")); } } @@ -655,11 +812,13 @@ DEFPY_YANG( "Next hop address\n" "IP address of next hop\n") { - const char *xpath = "./set-action[action='ipv4-next-hop']"; + const char *xpath = + "./set-action[action='frr-route-map:ipv4-next-hop']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/ipv4-address", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/ipv4-address", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str); return nb_cli_apply_changes(vty, NULL); @@ -674,7 +833,8 @@ DEFPY_YANG( "Next hop address\n" "IP address of next hop\n") { - const char *xpath = "./set-action[action='ipv4-next-hop']"; + const char *xpath = + "./set-action[action='frr-route-map:ipv4-next-hop']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -690,11 +850,13 @@ DEFPY_YANG( "IPv6 local address\n" "IPv6 address of next hop\n") { - const char *xpath = "./set-action[action='ipv6-next-hop']"; + const char *xpath = + "./set-action[action='frr-route-map:ipv6-next-hop']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/ipv6-address", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/ipv6-address", xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addr_str); return nb_cli_apply_changes(vty, NULL); @@ -710,7 +872,8 @@ DEFPY_YANG( "IPv6 local address\n" "IPv6 address of next hop\n") { - const char *xpath = "./set-action[action='ipv6-next-hop']"; + const char *xpath = + "./set-action[action='frr-route-map:ipv6-next-hop']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -727,33 +890,34 @@ DEFPY_YANG( "Add round trip time\n" "Subtract round trip time\n") { - const char *xpath = "./set-action[action='metric']"; + const char *xpath = "./set-action[action='frr-route-map:set-metric']"; char xpath_value[XPATH_MAXLEN]; char value[64]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); if (rtt) { snprintf(xpath_value, sizeof(xpath_value), - "%s/use-round-trip-time", xpath); + "%s/rmap-set-action/use-round-trip-time", xpath); snprintf(value, sizeof(value), "true"); } else if (artt) { snprintf(xpath_value, sizeof(xpath_value), - "%s/add-round-trip-time", xpath); + "%s/rmap-set-action/add-round-trip-time", xpath); snprintf(value, sizeof(value), "true"); } else if (srtt) { snprintf(xpath_value, sizeof(xpath_value), - "%s/subtract-round-trip-time", xpath); + "%s/rmap-set-action/subtract-round-trip-time", xpath); snprintf(value, sizeof(value), "true"); } else if (metric_str && metric_str[0] == '+') { - snprintf(xpath_value, sizeof(xpath_value), "%s/add-metric", - xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/add-metric", xpath); snprintf(value, sizeof(value), "%s", ++metric_str); } else if (metric_str && metric_str[0] == '-') { - snprintf(xpath_value, sizeof(xpath_value), "%s/subtract-metric", - xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/subtract-metric", xpath); snprintf(value, sizeof(value), "%s", ++metric_str); } else { - snprintf(xpath_value, sizeof(xpath_value), "%s/value", xpath); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/value", xpath); snprintf(value, sizeof(value), "%s", metric_str); } nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, value); @@ -769,7 +933,7 @@ DEFPY_YANG( "Metric value for destination routing protocol\n" "Metric value\n") { - const char *xpath = "./set-action[action='metric']"; + const char *xpath = "./set-action[action='frr-route-map:set-metric']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -782,11 +946,12 @@ DEFPY_YANG( "Tag value for routing protocol\n" "Tag value\n") { - const char *xpath = "./set-action[action='tag']"; + const char *xpath = "./set-action[action='frr-route-map:set-tag']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), "%s/tag", xpath); + snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-set-action/tag", + xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, tag_str); return nb_cli_apply_changes(vty, NULL); @@ -800,58 +965,289 @@ DEFPY_YANG( "Tag value for routing protocol\n" "Tag value\n") { - const char *xpath = "./set-action[action='tag']"; + const char *xpath = "./set-action[action='frr-route-map:set-tag']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (set_srte_color, + set_srte_color_cmd, + "set sr-te color (1-4294967295)", + SET_STR + SRTE_STR + SRTE_COLOR_STR + "Color of the SR-TE Policies to match with\n") +{ + const char *xpath = + "./set-action[action='frr-route-map:set-sr-te-color']"; + char xpath_value[XPATH_MAXLEN]; + int idx = 0; + + char *arg = argv_find(argv, argc, "(1-4294967295)", &idx) + ? argv[idx]->arg + : NULL; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/policy", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, arg); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_set_srte_color, + no_set_srte_color_cmd, + "no set sr-te color [(1-4294967295)]", + NO_STR + SET_STR + SRTE_STR + SRTE_COLOR_STR + "Color of the SR-TE Policies to match with\n") +{ + const char *xpath = + "./set-action[action='frr-route-map:set-sr-te-color']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } + void route_map_action_show(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { - int action = yang_dnode_get_enum(dnode, "./action"); + const char *action = yang_dnode_get_string(dnode, "./action"); + struct lyd_node *ln; + const char *acl; - switch (action) { - case 0: /* ipv4-next-hop */ + if (IS_SET_IPv4_NH(action)) { vty_out(vty, " set ip next-hop %s\n", - yang_dnode_get_string(dnode, "./ipv4-address")); - break; - case 1: /* ipv6-next-hop */ + yang_dnode_get_string( + dnode, "./rmap-set-action/ipv4-address")); + } else if (IS_SET_IPv6_NH(action)) { vty_out(vty, " set ipv6 next-hop local %s\n", - yang_dnode_get_string(dnode, "./ipv6-address")); - break; - case 2: /* metric */ - if (yang_dnode_get(dnode, "./use-round-trip-time")) { + yang_dnode_get_string( + dnode, "./rmap-set-action/ipv6-address")); + } else if (IS_SET_METRIC(action)) { + if (yang_dnode_get(dnode, + "./rmap-set-action/use-round-trip-time")) { vty_out(vty, " set metric rtt\n"); - } else if (yang_dnode_get(dnode, "./add-round-trip-time")) { + } else if (yang_dnode_get( + dnode, + "./rmap-set-action/add-round-trip-time")) { vty_out(vty, " set metric +rtt\n"); - } else if (yang_dnode_get(dnode, "./subtract-round-trip-time")) { + } else if ( + yang_dnode_get( + dnode, + "./rmap-set-action/subtract-round-trip-time")) { vty_out(vty, " set metric -rtt\n"); - } else if (yang_dnode_get(dnode, "./add-metric")) { + } else if (yang_dnode_get(dnode, + "./rmap-set-action/add-metric")) { vty_out(vty, " set metric +%s\n", - yang_dnode_get_string(dnode, "./add-metric")); - } else if (yang_dnode_get(dnode, "./subtract-metric")) { + yang_dnode_get_string( + dnode, "./rmap-set-action/add-metric")); + } else if (yang_dnode_get( + dnode, + "./rmap-set-action/subtract-metric")) { vty_out(vty, " set metric -%s\n", - yang_dnode_get_string(dnode, - "./subtract-metric")); + yang_dnode_get_string( + dnode, + "./rmap-set-action/subtract-metric")); } else { vty_out(vty, " set metric %s\n", - yang_dnode_get_string(dnode, "./value")); + yang_dnode_get_string( + dnode, "./rmap-set-action/value")); } - break; - case 3: /* tag */ + } else if (IS_SET_TAG(action)) { vty_out(vty, " set tag %s\n", - yang_dnode_get_string(dnode, "./tag")); - break; - case 100: /* source */ - if (yang_dnode_exists(dnode, "./frr-zebra:source-v4")) + yang_dnode_get_string(dnode, "./rmap-set-action/tag")); + } else if (IS_SET_SR_TE_COLOR(action)) { + vty_out(vty, " set sr-te color %s\n", + yang_dnode_get_string(dnode, + "./rmap-set-action/policy")); + } else if (IS_SET_SRC(action)) { + if (yang_dnode_exists( + dnode, + "./rmap-set-action/frr-zebra-route-map:ipv4-src-address")) vty_out(vty, " set src %s\n", - yang_dnode_get_string(dnode, "./frr-zebra:source-v4")); + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-zebra-route-map:ipv4-src-address")); else vty_out(vty, " set src %s\n", - yang_dnode_get_string(dnode, "./frr-zebra:source-v6")); - break; + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-zebra-route-map:ipv6-src-address")); + } else if (IS_SET_METRIC_TYPE(action)) { + vty_out(vty, " set metric-type %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-ospf-route-map:metric-type")); + } else if (IS_SET_FORWARDING_ADDR(action)) { + vty_out(vty, " set forwarding-address %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-ospf6-route-map:ipv6-address")); + } else if (IS_SET_WEIGHT(action)) { + vty_out(vty, " set weight %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:weight")); + } else if (IS_SET_TABLE(action)) { + vty_out(vty, " set table %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:table")); + } else if (IS_SET_LOCAL_PREF(action)) { + vty_out(vty, " set local-preference %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:local-pref")); + } else if (IS_SET_LABEL_INDEX(action)) { + vty_out(vty, " set label-index %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:label-index")); + } else if (IS_SET_DISTANCE(action)) { + vty_out(vty, " set distance %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:distance")); + } else if (IS_SET_ORIGIN(action)) { + vty_out(vty, " set origin %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:origin")); + } else if (IS_SET_ATOMIC_AGGREGATE(action)) { + vty_out(vty, " set atomic-aggregate\n"); + } else if (IS_SET_ORIGINATOR_ID(action)) { + vty_out(vty, " set originator-id %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:originator-id")); + } else if (IS_SET_COMM_LIST_DEL(action)) { + acl = NULL; + if ((ln = yang_dnode_get( + dnode, + "./rmap-set-action/frr-bgp-route-map:comm-list-name")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + + assert(acl); + + vty_out(vty, " set comm-list %s delete\n", acl); + } else if (IS_SET_LCOMM_LIST_DEL(action)) { + acl = NULL; + if ((ln = yang_dnode_get( + dnode, + "./rmap-set-action/frr-bgp-route-map:comm-list-name")) + != NULL) + acl = yang_dnode_get_string(ln, NULL); + + assert(acl); + + vty_out(vty, " set large-comm-list %s delete\n", acl); + } else if (IS_SET_LCOMMUNITY(action)) { + if (yang_dnode_exists( + dnode, + "./rmap-set-action/frr-bgp-route-map:large-community-string")) + vty_out(vty, " set large-community %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:large-community-string")); + else { + if (true + == yang_dnode_get_bool( + dnode, + "./rmap-set-action/frr-bgp-route-map:large-community-none")) + vty_out(vty, " set large-community none\n"); + } + } else if (IS_SET_COMMUNITY(action)) { + if (yang_dnode_exists( + dnode, + "./rmap-set-action/frr-bgp-route-map:community-string")) + vty_out(vty, " set community %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:community-string")); + else { + if (true + == yang_dnode_get_bool( + dnode, + "./rmap-set-action/frr-bgp-route-map:community-none")) + vty_out(vty, " set community none\n"); + } + } else if (IS_SET_EXTCOMMUNITY_RT(action)) { + vty_out(vty, " set extcommunity rt %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:extcommunity-rt")); + } else if (IS_SET_EXTCOMMUNITY_SOO(action)) { + vty_out(vty, " set extcommunity soo %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:extcommunity-soo")); + } else if (IS_SET_AGGREGATOR(action)) { + vty_out(vty, " set aggregator as %s %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn"), + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address")); + } else if (IS_SET_AS_EXCLUDE(action)) { + vty_out(vty, " set as-path exclude %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:exclude-as-path")); + } else if (IS_SET_AS_PREPEND(action)) { + if (yang_dnode_exists( + dnode, + "./rmap-set-action/frr-bgp-route-map:prepend-as-path")) + vty_out(vty, " set as-path prepend %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:prepend-as-path")); + else { + vty_out(vty, " set as-path prepend last-as %u\n", + yang_dnode_get_uint8( + dnode, + "./rmap-set-action/frr-bgp-route-map:last-as")); + } + } else if (IS_SET_IPV6_NH_GLOBAL(action)) { + vty_out(vty, " set ipv6 next-hop global %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:ipv6-address")); + } else if (IS_SET_IPV6_VPN_NH(action)) { + vty_out(vty, " set ipv6 vpn next-hop %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:ipv6-address")); + } else if (IS_SET_IPV6_PEER_ADDR(action)) { + if (true + == yang_dnode_get_bool( + dnode, + "./rmap-set-action/frr-bgp-route-map:preference")) + vty_out(vty, " set ipv6 next-hop peer-address\n"); + } else if (IS_SET_IPV6_PREFER_GLOBAL(action)) { + if (true + == yang_dnode_get_bool( + dnode, + "./rmap-set-action/frr-bgp-route-map:preference")) + vty_out(vty, " set ipv6 next-hop prefer-global\n"); + } else if (IS_SET_IPV4_VPN_NH(action)) { + vty_out(vty, " set ipv4 vpn next-hop %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:ipv4-address")); + } else if (IS_SET_BGP_IPV4_NH(action)) { + vty_out(vty, " set ip next-hop %s\n", + yang_dnode_get_string( + dnode, + "./rmap-set-action/frr-bgp-route-map:ipv4-nexthop")); } } @@ -1114,4 +1510,7 @@ void route_map_cli_init(void) install_element(RMAP_NODE, &set_tag_cmd); install_element(RMAP_NODE, &no_set_tag_cmd); + + install_element(RMAP_NODE, &set_srte_color_cmd); + install_element(RMAP_NODE, &no_set_srte_color_cmd); } diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 597a6b1ecf..410eb51f5e 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -45,8 +45,9 @@ int lib_route_map_entry_match_destroy(struct nb_cb_destroy_args *args) if (rhc->rhc_mhook == NULL) return NB_OK; - rv = rhc->rhc_mhook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL, - rhc->rhc_event); + rv = rhc->rhc_mhook(rhc->rhc_rmi, rhc->rhc_rule, NULL, + rhc->rhc_event, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) return NB_ERR_INCONSISTENCY; @@ -65,7 +66,8 @@ int lib_route_map_entry_set_destroy(struct nb_cb_destroy_args *args) if (rhc->rhc_shook == NULL) return NB_OK; - rv = rhc->rhc_shook(NULL, rhc->rhc_rmi, rhc->rhc_rule, NULL); + rv = rhc->rhc_shook(rhc->rhc_rmi, rhc->rhc_rule, NULL, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) return NB_ERR_INCONSISTENCY; @@ -498,9 +500,10 @@ static int lib_route_map_entry_match_condition_interface_modify( rhc->rhc_rule = "interface"; rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; - rv = rmap_match_set_hook.match_interface(NULL, rhc->rhc_rmi, + rv = rmap_match_set_hook.match_interface(rhc->rhc_rmi, "interface", ifname, - RMAP_EVENT_MATCH_ADDED); + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) { rhc->rhc_mhook = NULL; return NB_ERR_INCONSISTENCY; @@ -523,7 +526,7 @@ static int lib_route_map_entry_match_condition_list_name_modify( { struct routemap_hook_context *rhc; const char *acl; - int condition; + const char *condition; int rv; if (args->event != NB_EV_APPLY) @@ -532,19 +535,19 @@ static int lib_route_map_entry_match_condition_list_name_modify( /* Check for hook installation, otherwise we can just stop. */ acl = yang_dnode_get_string(args->dnode, NULL); rhc = nb_running_get_entry(args->dnode, NULL, true); - condition = yang_dnode_get_enum(args->dnode, "../condition"); - switch (condition) { - case 1: /* ipv4-address-list */ + condition = yang_dnode_get_string(args->dnode, "../../condition"); + + if (IS_MATCH_IPv4_ADDRESS_LIST(condition)) { if (rmap_match_set_hook.match_ip_address == NULL) return NB_OK; rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address; rhc->rhc_rule = "ip address"; rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; rv = rmap_match_set_hook.match_ip_address( - NULL, rhc->rhc_rmi, "ip address", acl, - RMAP_EVENT_FILTER_ADDED); - break; - case 2: /* ipv4-prefix-list */ + rhc->rhc_rmi, "ip address", acl, + RMAP_EVENT_FILTER_ADDED, + args->errmsg, args->errmsg_len); + } else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) { if (rmap_match_set_hook.match_ip_address_prefix_list == NULL) return NB_OK; rhc->rhc_mhook = @@ -552,20 +555,20 @@ static int lib_route_map_entry_match_condition_list_name_modify( rhc->rhc_rule = "ip address prefix-list"; rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; rv = rmap_match_set_hook.match_ip_address_prefix_list( - NULL, rhc->rhc_rmi, "ip address prefix-list", acl, - RMAP_EVENT_PLIST_ADDED); - break; - case 3: /* ipv4-next-hop-list */ + rhc->rhc_rmi, "ip address prefix-list", acl, + RMAP_EVENT_PLIST_ADDED, + args->errmsg, args->errmsg_len); + } else if (IS_MATCH_IPv4_NEXTHOP_LIST(condition)) { if (rmap_match_set_hook.match_ip_next_hop == NULL) return NB_OK; rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop; rhc->rhc_rule = "ip next-hop"; rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; rv = rmap_match_set_hook.match_ip_next_hop( - NULL, rhc->rhc_rmi, "ip next-hop", acl, - RMAP_EVENT_FILTER_ADDED); - break; - case 4: /* ipv4-next-hop-prefix-list */ + rhc->rhc_rmi, "ip next-hop", acl, + RMAP_EVENT_FILTER_ADDED, + args->errmsg, args->errmsg_len); + } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) { if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL) return NB_OK; rhc->rhc_mhook = @@ -573,20 +576,20 @@ static int lib_route_map_entry_match_condition_list_name_modify( rhc->rhc_rule = "ip next-hop prefix-list"; rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; rv = rmap_match_set_hook.match_ip_next_hop_prefix_list( - NULL, rhc->rhc_rmi, "ip next-hop prefix-list", acl, - RMAP_EVENT_PLIST_ADDED); - break; - case 6: /* ipv6-address-list */ + rhc->rhc_rmi, "ip next-hop prefix-list", acl, + RMAP_EVENT_PLIST_ADDED, + args->errmsg, args->errmsg_len); + } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) { if (rmap_match_set_hook.match_ipv6_address == NULL) return NB_OK; rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_address; rhc->rhc_rule = "ipv6 address"; rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; rv = rmap_match_set_hook.match_ipv6_address( - NULL, rhc->rhc_rmi, "ipv6 address", acl, - RMAP_EVENT_FILTER_ADDED); - break; - case 7: /* ipv6-prefix-list */ + rhc->rhc_rmi, "ipv6 address", acl, + RMAP_EVENT_FILTER_ADDED, + args->errmsg, args->errmsg_len); + } else if (IS_MATCH_IPv6_PREFIX_LIST(condition)) { if (rmap_match_set_hook.match_ipv6_address_prefix_list == NULL) return NB_OK; rhc->rhc_mhook = @@ -594,13 +597,12 @@ static int lib_route_map_entry_match_condition_list_name_modify( rhc->rhc_rule = "ipv6 address prefix-list"; rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; rv = rmap_match_set_hook.match_ipv6_address_prefix_list( - NULL, rhc->rhc_rmi, "ipv6 address prefix-list", acl, - RMAP_EVENT_PLIST_ADDED); - break; - default: + rhc->rhc_rmi, "ipv6 address prefix-list", acl, + RMAP_EVENT_PLIST_ADDED, + args->errmsg, args->errmsg_len); + } else rv = CMD_ERR_NO_MATCH; - break; - } + if (rv != CMD_SUCCESS) { rhc->rhc_mhook = NULL; return NB_ERR_INCONSISTENCY; @@ -642,8 +644,9 @@ static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify( rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; rv = rmap_match_set_hook.match_ip_next_hop_type( - NULL, rhc->rhc_rmi, "ip next-hop type", type, - RMAP_EVENT_MATCH_ADDED); + rhc->rhc_rmi, "ip next-hop type", type, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) { rhc->rhc_mhook = NULL; return NB_ERR_INCONSISTENCY; @@ -685,8 +688,9 @@ static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify( rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; rv = rmap_match_set_hook.match_ipv6_next_hop_type( - NULL, rhc->rhc_rmi, "ipv6 next-hop type", type, - RMAP_EVENT_MATCH_ADDED); + rhc->rhc_rmi, "ipv6 next-hop type", type, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) { rhc->rhc_mhook = NULL; return NB_ERR_INCONSISTENCY; @@ -727,8 +731,9 @@ static int lib_route_map_entry_match_condition_metric_modify( rhc->rhc_rule = "metric"; rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; - rv = rmap_match_set_hook.match_metric(NULL, rhc->rhc_rmi, "metric", - type, RMAP_EVENT_MATCH_ADDED); + rv = rmap_match_set_hook.match_metric(rhc->rhc_rmi, "metric", + type, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) { rhc->rhc_mhook = NULL; return NB_ERR_INCONSISTENCY; @@ -769,8 +774,9 @@ lib_route_map_entry_match_condition_tag_modify(struct nb_cb_modify_args *args) rhc->rhc_rule = "tag"; rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; - rv = rmap_match_set_hook.match_tag(NULL, rhc->rhc_rmi, "tag", tag, - RMAP_EVENT_MATCH_ADDED); + rv = rmap_match_set_hook.match_tag(rhc->rhc_rmi, "tag", tag, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) { rhc->rhc_mhook = NULL; return NB_ERR_INCONSISTENCY; @@ -850,8 +856,9 @@ static int lib_route_map_entry_set_action_ipv4_address_modify( rhc->rhc_shook = rmap_match_set_hook.no_set_ip_nexthop; rhc->rhc_rule = "ip next-hop"; - rv = rmap_match_set_hook.set_ip_nexthop(NULL, rhc->rhc_rmi, - "ip next-hop", address); + rv = rmap_match_set_hook.set_ip_nexthop(rhc->rhc_rmi, "ip next-hop", + address, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) { rhc->rhc_shook = NULL; return NB_ERR_INCONSISTENCY; @@ -909,7 +916,8 @@ static int lib_route_map_entry_set_action_ipv6_address_modify( rhc->rhc_rule = "ipv6 next-hop local"; rv = rmap_match_set_hook.set_ipv6_nexthop_local( - NULL, rhc->rhc_rmi, "ipv6 next-hop local", address); + rhc->rhc_rmi, "ipv6 next-hop local", address, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) { rhc->rhc_shook = NULL; return NB_ERR_INCONSISTENCY; @@ -928,7 +936,8 @@ static int lib_route_map_entry_set_action_ipv6_address_destroy( * XPath: /frr-route-map:lib/route-map/entry/set-action/value */ static int set_action_modify(enum nb_event event, const struct lyd_node *dnode, - union nb_resource *resource, const char *value) + union nb_resource *resource, const char *value, + char *errmsg, size_t errmsg_len) { struct routemap_hook_context *rhc; int rv; @@ -952,8 +961,10 @@ static int set_action_modify(enum nb_event event, const struct lyd_node *dnode, rhc->rhc_shook = rmap_match_set_hook.no_set_metric; rhc->rhc_rule = "metric"; - rv = rmap_match_set_hook.set_metric(NULL, rhc->rhc_rmi, "metric", - value); + rv = rmap_match_set_hook.set_metric(rhc->rhc_rmi, "metric", + value, + errmsg, errmsg_len + ); if (rv != CMD_SUCCESS) { rhc->rhc_shook = NULL; return NB_ERR_INCONSISTENCY; @@ -968,7 +979,7 @@ lib_route_map_entry_set_action_value_modify(struct nb_cb_modify_args *args) const char *metric = yang_dnode_get_string(args->dnode, NULL); return set_action_modify(args->event, args->dnode, args->resource, - metric); + metric, args->errmsg, args->errmsg_len); } static int @@ -995,7 +1006,8 @@ lib_route_map_entry_set_action_add_metric_modify(struct nb_cb_modify_args *args) snprintf(metric_str, sizeof(metric_str), "+%s", yang_dnode_get_string(args->dnode, NULL)); return set_action_modify(args->event, args->dnode, args->resource, - metric_str); + metric_str, + args->errmsg, args->errmsg_len); } static int lib_route_map_entry_set_action_add_metric_destroy( @@ -1022,7 +1034,8 @@ static int lib_route_map_entry_set_action_subtract_metric_modify( snprintf(metric_str, sizeof(metric_str), "-%s", yang_dnode_get_string(args->dnode, NULL)); return set_action_modify(args->event, args->dnode, args->resource, - metric_str); + metric_str, + args->errmsg, args->errmsg_len); } static int lib_route_map_entry_set_action_subtract_metric_destroy( @@ -1038,7 +1051,8 @@ static int lib_route_map_entry_set_action_use_round_trip_time_modify( struct nb_cb_modify_args *args) { return set_action_modify(args->event, args->dnode, args->resource, - "rtt"); + "rtt", + args->errmsg, args->errmsg_len); } static int lib_route_map_entry_set_action_use_round_trip_time_destroy( @@ -1054,7 +1068,8 @@ static int lib_route_map_entry_set_action_add_round_trip_time_modify( struct nb_cb_modify_args *args) { return set_action_modify(args->event, args->dnode, args->resource, - "+rtt"); + "+rtt", + args->errmsg, args->errmsg_len); } static int lib_route_map_entry_set_action_add_round_trip_time_destroy( @@ -1070,7 +1085,7 @@ static int lib_route_map_entry_set_action_subtract_round_trip_time_modify( struct nb_cb_modify_args *args) { return set_action_modify(args->event, args->dnode, args->resource, - "-rtt"); + "-rtt", args->errmsg, args->errmsg_len); } static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy( @@ -1109,7 +1124,8 @@ lib_route_map_entry_set_action_tag_modify(struct nb_cb_modify_args *args) rhc->rhc_shook = rmap_match_set_hook.no_set_tag; rhc->rhc_rule = "tag"; - rv = rmap_match_set_hook.set_tag(NULL, rhc->rhc_rmi, "tag", tag); + rv = rmap_match_set_hook.set_tag(rhc->rhc_rmi, "tag", tag, + args->errmsg, args->errmsg_len); if (rv != CMD_SUCCESS) { rhc->rhc_shook = NULL; return NB_ERR_INCONSISTENCY; @@ -1124,6 +1140,52 @@ lib_route_map_entry_set_action_tag_destroy(struct nb_cb_destroy_args *args) return lib_route_map_entry_set_destroy(args); } +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/policy + */ +static int +lib_route_map_entry_set_action_policy_modify(struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *policy; + int rv; + + /* + * NOTE: validate if 'action' is 'tag', currently it is not + * necessary because this is the only implemented action. Other + * actions might have different validations. + */ + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* Check for hook function. */ + if (rmap_match_set_hook.set_srte_color == NULL) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + policy = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = rmap_match_set_hook.no_set_tag; + rhc->rhc_rule = "sr-te color"; + + rv = rmap_match_set_hook.set_tag(rhc->rhc_rmi, "sr-te color", policy, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +static int +lib_route_map_entry_set_action_policy_destroy(struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_destroy(args); +} + /* clang-format off */ const struct frr_yang_module_info frr_route_map_info = { .name = "frr-route-map", @@ -1140,6 +1202,7 @@ const struct frr_yang_module_info frr_route_map_info = { .cbs = { .create = lib_route_map_entry_create, .destroy = lib_route_map_entry_destroy, + .cli_cmp = route_map_instance_cmp, .cli_show = route_map_instance_show, .cli_show_end = route_map_instance_show_end, } @@ -1189,42 +1252,42 @@ const struct frr_yang_module_info frr_route_map_info = { } }, { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/interface", + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/interface", .cbs = { .modify = lib_route_map_entry_match_condition_interface_modify, .destroy = lib_route_map_entry_match_condition_interface_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/list-name", + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/list-name", .cbs = { .modify = lib_route_map_entry_match_condition_list_name_modify, .destroy = lib_route_map_entry_match_condition_list_name_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type", + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv4-next-hop-type", .cbs = { .modify = lib_route_map_entry_match_condition_ipv4_next_hop_type_modify, .destroy = lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type", + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv6-next-hop-type", .cbs = { .modify = lib_route_map_entry_match_condition_ipv6_next_hop_type_modify, .destroy = lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/metric", + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/metric", .cbs = { .modify = lib_route_map_entry_match_condition_metric_modify, .destroy = lib_route_map_entry_match_condition_metric_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/tag", + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/tag", .cbs = { .modify = lib_route_map_entry_match_condition_tag_modify, .destroy = lib_route_map_entry_match_condition_tag_destroy, @@ -1239,69 +1302,77 @@ const struct frr_yang_module_info frr_route_map_info = { } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv4-address", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv4-address", .cbs = { .modify = lib_route_map_entry_set_action_ipv4_address_modify, .destroy = lib_route_map_entry_set_action_ipv4_address_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/ipv6-address", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv6-address", .cbs = { .modify = lib_route_map_entry_set_action_ipv6_address_modify, .destroy = lib_route_map_entry_set_action_ipv6_address_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/value", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/value", .cbs = { .modify = lib_route_map_entry_set_action_value_modify, .destroy = lib_route_map_entry_set_action_value_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-metric", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-metric", .cbs = { .modify = lib_route_map_entry_set_action_add_metric_modify, .destroy = lib_route_map_entry_set_action_add_metric_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-metric", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-metric", .cbs = { .modify = lib_route_map_entry_set_action_subtract_metric_modify, .destroy = lib_route_map_entry_set_action_subtract_metric_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/use-round-trip-time", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/use-round-trip-time", .cbs = { .modify = lib_route_map_entry_set_action_use_round_trip_time_modify, .destroy = lib_route_map_entry_set_action_use_round_trip_time_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/add-round-trip-time", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-round-trip-time", .cbs = { .modify = lib_route_map_entry_set_action_add_round_trip_time_modify, .destroy = lib_route_map_entry_set_action_add_round_trip_time_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-round-trip-time", .cbs = { .modify = lib_route_map_entry_set_action_subtract_round_trip_time_modify, .destroy = lib_route_map_entry_set_action_subtract_round_trip_time_destroy, } }, { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/tag", + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/tag", .cbs = { .modify = lib_route_map_entry_set_action_tag_modify, .destroy = lib_route_map_entry_set_action_tag_destroy, } }, { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/policy", + .cbs = { + .modify = lib_route_map_entry_set_action_policy_modify, + .destroy = lib_route_map_entry_set_action_policy_destroy, + } + }, + + { .xpath = NULL, }, } diff --git a/lib/routing_nb.h b/lib/routing_nb.h index ffba631a10..bdd12b262b 100644 --- a/lib/routing_nb.h +++ b/lib/routing_nb.h @@ -24,7 +24,7 @@ int routing_control_plane_protocols_control_plane_protocol_destroy( * callbacks for routing to handle configuration events * based on the control plane protocol */ -DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)) +DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)); void routing_control_plane_protocols_register_vrf_dependency(void); diff --git a/lib/routing_nb_config.c b/lib/routing_nb_config.c index 17698d2b87..f66f32015d 100644 --- a/lib/routing_nb_config.c +++ b/lib/routing_nb_config.c @@ -24,7 +24,7 @@ #include "routing_nb.h" -DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)) +DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)); /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol diff --git a/lib/skiplist.c b/lib/skiplist.c index b79dfa6772..fc42857418 100644 --- a/lib/skiplist.c +++ b/lib/skiplist.c @@ -63,8 +63,8 @@ #include "lib_errors.h" #include "network.h" -DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List") -DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node") +DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List"); +DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node"); #define BitsInRandom 31 diff --git a/lib/smux.h b/lib/smux.h index 57128b7928..74447341d8 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -152,12 +152,13 @@ extern void oid2in_addr(oid[], int, struct in_addr *); extern void oid2in6_addr(oid oid[], struct in6_addr *addr); extern void oid2int(oid oid[], int *dest); extern void *oid_copy(void *, const void *, size_t); -extern void oid_copy_addr(oid[], const struct in_addr *, int); +extern void oid_copy_in_addr(oid[], const struct in_addr *); +extern void oid_copy_in6_addr(oid[], const struct in6_addr *); extern void oid_copy_int(oid oid[], int *val); extern void oid2string(oid oid[], int len, char *string); extern void oid_copy_str(oid oid[], const char *string, int len); -DECLARE_HOOK(agentx_enabled, (), ()) +DECLARE_HOOK(agentx_enabled, (), ()); #ifdef __cplusplus } diff --git a/lib/snmp.c b/lib/snmp.c index 17a4ed4a1d..23d3f38b31 100644 --- a/lib/snmp.c +++ b/lib/snmp.c @@ -88,13 +88,24 @@ void oid2int(oid oid[], int *dest) *dest = ntohl(network_dest); } -void oid_copy_addr(oid oid[], const struct in_addr *addr, int len) +void oid_copy_in_addr(oid oid[], const struct in_addr *addr) { int i; const uint8_t *pnt; + int len = sizeof(struct in_addr); - if (len == 0) - return; + pnt = (uint8_t *)addr; + + for (i = 0; i < len; i++) + oid[i] = *pnt++; +} + + +void oid_copy_in6_addr(oid oid[], const struct in6_addr *addr) +{ + int i; + const uint8_t *pnt; + int len = sizeof(struct in6_addr); pnt = (uint8_t *)addr; diff --git a/lib/sockunion.c b/lib/sockunion.c index c701da1e03..e6340a1743 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -29,7 +29,7 @@ #include "lib_errors.h" #include "printfrr.h" -DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union") +DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union"); const char *inet_sutop(const union sockunion *su, char *str) { @@ -664,54 +664,76 @@ void sockunion_init(union sockunion *su) } printfrr_ext_autoreg_p("SU", printfrr_psu) -static ssize_t printfrr_psu(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_psu(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const union sockunion *su = ptr; - struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 }; - bool include_port = false; + bool include_port = false, include_scope = false; bool endflags = false; - ssize_t consumed = 2; - - if (su) { - while (!endflags) { - switch (fmt[consumed++]) { - case 'p': - include_port = true; - break; - default: - consumed--; - endflags = true; - break; - } - }; - - switch (sockunion_family(su)) { - case AF_UNSPEC: - bprintfrr(&fb, "(unspec)"); - break; - case AF_INET: - inet_ntop(AF_INET, &su->sin.sin_addr, buf, bsz); - fb.pos += strlen(fb.buf); - if (include_port) - bprintfrr(&fb, ":%d", su->sin.sin_port); + ssize_t ret = 0; + char cbuf[INET6_ADDRSTRLEN]; + + if (!su) + return bputs(buf, "(null)"); + + while (!endflags) { + switch (*ea->fmt) { + case 'p': + ea->fmt++; + include_port = true; break; - case AF_INET6: - inet_ntop(AF_INET6, &su->sin6.sin6_addr, buf, bsz); - fb.pos += strlen(fb.buf); - if (include_port) - bprintfrr(&fb, ":%d", su->sin6.sin6_port); + case 's': + ea->fmt++; + include_scope = true; break; default: - bprintfrr(&fb, "(af %d)", sockunion_family(su)); + endflags = true; + break; } + } - fb.pos[0] = '\0'; - } else { - strlcpy(buf, "NULL", bsz); + switch (sockunion_family(su)) { + case AF_UNSPEC: + ret += bputs(buf, "(unspec)"); + break; + case AF_INET: + inet_ntop(AF_INET, &su->sin.sin_addr, cbuf, sizeof(cbuf)); + ret += bputs(buf, cbuf); + if (include_port) + ret += bprintfrr(buf, ":%d", ntohs(su->sin.sin_port)); + break; + case AF_INET6: + if (include_port) + ret += bputch(buf, '['); + inet_ntop(AF_INET6, &su->sin6.sin6_addr, cbuf, sizeof(cbuf)); + ret += bputs(buf, cbuf); + if (include_scope && su->sin6.sin6_scope_id) + ret += bprintfrr(buf, "%%%u", + (unsigned int)su->sin6.sin6_scope_id); + if (include_port) + ret += bprintfrr(buf, "]:%d", + ntohs(su->sin6.sin6_port)); + break; + case AF_UNIX: { + int len; +#ifdef __linux__ + if (su->sun.sun_path[0] == '\0' && su->sun.sun_path[1]) { + len = strnlen(su->sun.sun_path + 1, + sizeof(su->sun.sun_path) - 1); + ret += bprintfrr(buf, "@%*pSE", len, + su->sun.sun_path + 1); + break; + } +#endif + len = strnlen(su->sun.sun_path, sizeof(su->sun.sun_path)); + ret += bprintfrr(buf, "%*pSE", len, su->sun.sun_path); + break; + } + default: + ret += bprintfrr(buf, "(af %d)", sockunion_family(su)); } - return consumed; + return ret; } int sockunion_is_null(const union sockunion *su) @@ -730,3 +752,49 @@ int sockunion_is_null(const union sockunion *su) return 0; } } + +printfrr_ext_autoreg_i("PF", printfrr_pf) +static ssize_t printfrr_pf(struct fbuf *buf, struct printfrr_eargs *ea, + uintmax_t val) +{ + switch (val) { + case AF_INET: + return bputs(buf, "AF_INET"); + case AF_INET6: + return bputs(buf, "AF_INET6"); + case AF_UNIX: + return bputs(buf, "AF_UNIX"); +#ifdef AF_PACKET + case AF_PACKET: + return bputs(buf, "AF_PACKET"); +#endif +#ifdef AF_NETLINK + case AF_NETLINK: + return bputs(buf, "AF_NETLINK"); +#endif + } + return bprintfrr(buf, "AF_(%ju)", val); +} + +printfrr_ext_autoreg_i("SO", printfrr_so) +static ssize_t printfrr_so(struct fbuf *buf, struct printfrr_eargs *ea, + uintmax_t val) +{ + switch (val) { + case SOCK_STREAM: + return bputs(buf, "SOCK_STREAM"); + case SOCK_DGRAM: + return bputs(buf, "SOCK_DGRAM"); + case SOCK_SEQPACKET: + return bputs(buf, "SOCK_SEQPACKET"); +#ifdef SOCK_RAW + case SOCK_RAW: + return bputs(buf, "SOCK_RAW"); +#endif +#ifdef SOCK_PACKET + case SOCK_PACKET: + return bputs(buf, "SOCK_PACKET"); +#endif + } + return bprintfrr(buf, "SOCK_(%ju)", val); +} diff --git a/lib/sockunion.h b/lib/sockunion.h index 5e80ba1090..2cc80bb70f 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -24,6 +24,7 @@ #include "privs.h" #include "if.h" +#include <sys/un.h> #ifdef __OpenBSD__ #include <netmpls/mpls.h> #endif @@ -36,6 +37,7 @@ union sockunion { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_in6 sin6; + struct sockaddr_un sun; #ifdef __OpenBSD__ struct sockaddr_mpls smpls; struct sockaddr_rtlabel rtlabel; @@ -106,6 +108,16 @@ extern int sockunion_is_null(const union sockunion *su); #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pSU" (union sockunion *) +#pragma FRR printfrr_ext "%pSU" (struct sockaddr *) +#pragma FRR printfrr_ext "%pSU" (struct sockaddr_storage *) +#pragma FRR printfrr_ext "%pSU" (struct sockaddr_in *) +#pragma FRR printfrr_ext "%pSU" (struct sockaddr_in6 *) +#pragma FRR printfrr_ext "%pSU" (struct sockaddr_un *) + +/* AF_INET/PF_INET & co., using "PF" to avoid confusion with AFI/SAFI */ +#pragma FRR printfrr_ext "%dPF" (int) +/* SOCK_STREAM & co. */ +#pragma FRR printfrr_ext "%dSO" (int) #endif #ifdef __cplusplus diff --git a/lib/spf_backoff.c b/lib/spf_backoff.c index ac6dd29f06..a273e93463 100644 --- a/lib/spf_backoff.c +++ b/lib/spf_backoff.c @@ -33,8 +33,8 @@ #include "thread.h" #include "vty.h" -DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff") -DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name") +DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff"); +DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name"); static bool debug_spf_backoff = false; #define backoff_debug(...) \ diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c index ef82b7ac01..d2e0682e95 100644 --- a/lib/srcdest_table.c +++ b/lib/srcdest_table.c @@ -30,7 +30,7 @@ #include "table.h" #include "printfrr.h" -DEFINE_MTYPE_STATIC(LIB, ROUTE_SRC_NODE, "Route source node") +DEFINE_MTYPE_STATIC(LIB, ROUTE_SRC_NODE, "Route source node"); /* ----- functions to manage rnodes _with_ srcdest table ----- */ struct srcdest_rnode { @@ -307,20 +307,20 @@ const char *srcdest_rnode2str(const struct route_node *rn, char *str, int size) } printfrr_ext_autoreg_p("RN", printfrr_rn) -static ssize_t printfrr_rn(char *buf, size_t bsz, const char *fmt, - int prec, const void *ptr) +static ssize_t printfrr_rn(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) { const struct route_node *rn = ptr; const struct prefix *dst_p, *src_p; + char cbuf[PREFIX_STRLEN * 2 + 6]; - if (rn) { - srcdest_rnode_prefixes(rn, &dst_p, &src_p); - srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, buf, bsz); - } else { - strlcpy(buf, "NULL", bsz); - } + if (!rn) + return bputs(buf, "(null)"); - return 2; + srcdest_rnode_prefixes(rn, &dst_p, &src_p); + srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, + cbuf, sizeof(cbuf)); + return bputs(buf, cbuf); } struct route_table *srcdest_srcnode_table(struct route_node *rn) diff --git a/lib/stream.c b/lib/stream.c index ef73c2fdc9..904ee73b10 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -31,8 +31,8 @@ #include "frr_pthread.h" #include "lib_errors.h" -DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream") -DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO") +DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream"); +DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO"); /* Tests whether a position is valid */ #define GETP_VALID(S, G) ((G) <= (S)->endp) diff --git a/lib/strformat.c b/lib/strformat.c new file mode 100644 index 0000000000..431e573a0c --- /dev/null +++ b/lib/strformat.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2019 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "compiler.h" + +#include <string.h> +#include <ctype.h> + +#include "printfrr.h" + +printfrr_ext_autoreg_p("HX", printfrr_hexdump) +static ssize_t printfrr_hexdump(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + ssize_t ret = 0; + ssize_t input_len = printfrr_ext_len(ea); + char sep = ' '; + const uint8_t *pos, *end; + + if (ea->fmt[0] == 'c') { + ea->fmt++; + sep = ':'; + } else if (ea->fmt[0] == 'n') { + ea->fmt++; + sep = '\0'; + } + + if (input_len < 0) + return 0; + + for (pos = ptr, end = pos + input_len; pos < end; pos++) { + if (sep && pos != ptr) + ret += bputch(buf, sep); + ret += bputhex(buf, *pos); + } + + return ret; +} + +/* string analog for hexdumps / the "this." in ("74 68 69 73 0a |this.|") */ + +printfrr_ext_autoreg_p("HS", printfrr_hexdstr) +static ssize_t printfrr_hexdstr(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + ssize_t ret = 0; + ssize_t input_len = printfrr_ext_len(ea); + const uint8_t *pos, *end; + + if (input_len < 0) + return 0; + + for (pos = ptr, end = pos + input_len; pos < end; pos++) { + if (*pos >= 0x20 && *pos < 0x7f) + ret += bputch(buf, *pos); + else + ret += bputch(buf, '.'); + } + + return ret; +} + +enum escape_flags { + ESC_N_R_T = (1 << 0), /* use \n \r \t instead of \x0a ...*/ + ESC_SPACE = (1 << 1), /* \ */ + ESC_BACKSLASH = (1 << 2), /* \\ */ + ESC_DBLQUOTE = (1 << 3), /* \" */ + ESC_SGLQUOTE = (1 << 4), /* \' */ + ESC_BACKTICK = (1 << 5), /* \` */ + ESC_DOLLAR = (1 << 6), /* \$ */ + ESC_CLBRACKET = (1 << 7), /* \] for RFC5424 syslog */ + ESC_OTHER = (1 << 8), /* remaining non-alpha */ + + ESC_ALL = ESC_N_R_T | ESC_SPACE | ESC_BACKSLASH | ESC_DBLQUOTE + | ESC_SGLQUOTE | ESC_DOLLAR | ESC_OTHER, + ESC_QUOTSTRING = ESC_N_R_T | ESC_BACKSLASH | ESC_DBLQUOTE, + /* if needed: ESC_SHELL = ... */ +}; + +static ssize_t bquote(struct fbuf *buf, const uint8_t *pos, size_t len, + unsigned int flags) +{ + ssize_t ret = 0; + const uint8_t *end = pos + len; + + for (; pos < end; pos++) { + /* here's to hoping this might be a bit faster... */ + if (__builtin_expect(!!isalnum(*pos), 1)) { + ret += bputch(buf, *pos); + continue; + } + + switch (*pos) { + case '%': + case '+': + case ',': + case '-': + case '.': + case '/': + case ':': + case '@': + case '_': + ret += bputch(buf, *pos); + continue; + + case '\r': + if (!(flags & ESC_N_R_T)) + break; + ret += bputch(buf, '\\'); + ret += bputch(buf, 'r'); + continue; + case '\n': + if (!(flags & ESC_N_R_T)) + break; + ret += bputch(buf, '\\'); + ret += bputch(buf, 'n'); + continue; + case '\t': + if (!(flags & ESC_N_R_T)) + break; + ret += bputch(buf, '\\'); + ret += bputch(buf, 't'); + continue; + + case ' ': + if (flags & ESC_SPACE) + ret += bputch(buf, '\\'); + ret += bputch(buf, *pos); + continue; + + case '\\': + if (flags & ESC_BACKSLASH) + ret += bputch(buf, '\\'); + ret += bputch(buf, *pos); + continue; + + case '"': + if (flags & ESC_DBLQUOTE) + ret += bputch(buf, '\\'); + ret += bputch(buf, *pos); + continue; + + case '\'': + if (flags & ESC_SGLQUOTE) + ret += bputch(buf, '\\'); + ret += bputch(buf, *pos); + continue; + + case '`': + if (flags & ESC_BACKTICK) + ret += bputch(buf, '\\'); + ret += bputch(buf, *pos); + continue; + + case '$': + if (flags & ESC_DOLLAR) + ret += bputch(buf, '\\'); + ret += bputch(buf, *pos); + continue; + + case ']': + if (flags & ESC_CLBRACKET) + ret += bputch(buf, '\\'); + ret += bputch(buf, *pos); + continue; + + /* remaining: !#&'()*;<=>?[^{|}~ */ + + default: + if (*pos >= 0x20 && *pos < 0x7f) { + if (flags & ESC_OTHER) + ret += bputch(buf, '\\'); + ret += bputch(buf, *pos); + continue; + } + } + ret += bputch(buf, '\\'); + ret += bputch(buf, 'x'); + ret += bputhex(buf, *pos); + } + + return ret; +} + +printfrr_ext_autoreg_p("SE", printfrr_escape) +static ssize_t printfrr_escape(struct fbuf *buf, struct printfrr_eargs *ea, + const void *vptr) +{ + ssize_t len = printfrr_ext_len(ea); + const uint8_t *ptr = vptr; + bool null_is_empty = false; + + if (ea->fmt[0] == 'n') { + null_is_empty = true; + ea->fmt++; + } + + if (!ptr) { + if (null_is_empty) + return 0; + return bputs(buf, "(null)"); + } + + if (len < 0) + len = strlen((const char *)ptr); + + return bquote(buf, ptr, len, ESC_ALL); +} + +printfrr_ext_autoreg_p("SQ", printfrr_quote) +static ssize_t printfrr_quote(struct fbuf *buf, struct printfrr_eargs *ea, + const void *vptr) +{ + ssize_t len = printfrr_ext_len(ea); + const uint8_t *ptr = vptr; + ssize_t ret = 0; + bool null_is_empty = false; + bool do_quotes = false; + unsigned int flags = ESC_QUOTSTRING; + + while (ea->fmt[0]) { + switch (ea->fmt[0]) { + case 'n': + null_is_empty = true; + ea->fmt++; + continue; + case 'q': + do_quotes = true; + ea->fmt++; + continue; + case 's': + flags |= ESC_CLBRACKET; + flags &= ~ESC_N_R_T; + ea->fmt++; + continue; + } + break; + } + + if (!ptr) { + if (null_is_empty) + return bputs(buf, do_quotes ? "\"\"" : ""); + return bputs(buf, "(null)"); + } + + if (len < 0) + len = strlen((const char *)ptr); + + if (do_quotes) + ret += bputch(buf, '"'); + ret += bquote(buf, ptr, len, flags); + if (do_quotes) + ret += bputch(buf, '"'); + return ret; +} diff --git a/lib/strlcat.c b/lib/strlcat.c index 39773d9ac8..a046822a94 100644 --- a/lib/strlcat.c +++ b/lib/strlcat.c @@ -64,10 +64,8 @@ size_t strlcat(char *__restrict dest, (which the static_assert checks), then by the pigeonhole principle, the two input strings must overlap, which is undefined. */ -#if __STDC_VERSION__ >= 201112L _Static_assert(sizeof(uintptr_t) == sizeof(size_t), "theoretical maximum object size covers address space"); -#endif return dest_length + src_length; } #endif /* HAVE_STRLCAT */ diff --git a/lib/subdir.am b/lib/subdir.am index 38d1a3f773..0853d4bb2b 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -90,6 +90,7 @@ lib_libfrr_la_SOURCES = \ lib/spf_backoff.c \ lib/srcdest_table.c \ lib/stream.c \ + lib/strformat.c \ lib/strlcat.c \ lib/strlcpy.c \ lib/systemd.c \ @@ -313,7 +314,7 @@ if SNMP lib_LTLIBRARIES += lib/libfrrsnmp.la endif -lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0 lib_libfrrsnmp_la_LIBADD = $(SNMP_LIBS) lib_libfrrsnmp_la_SOURCES = \ diff --git a/lib/table.c b/lib/table.c index 89e32182b5..dfd92c6189 100644 --- a/lib/table.c +++ b/lib/table.c @@ -29,8 +29,8 @@ #include "sockunion.h" #include "libfrr_trace.h" -DEFINE_MTYPE_STATIC(LIB, ROUTE_TABLE, "Route table") -DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node") +DEFINE_MTYPE_STATIC(LIB, ROUTE_TABLE, "Route table"); +DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node"); static void route_table_free(struct route_table *); @@ -41,7 +41,7 @@ static int route_table_hash_cmp(const struct route_node *a, } DECLARE_HASH(rn_hash_node, struct route_node, nodehash, route_table_hash_cmp, - prefix_hash_key) + prefix_hash_key); /* * route_table_init_with_delegate */ diff --git a/lib/table.h b/lib/table.h index 5d620d332b..7e383dce80 100644 --- a/lib/table.h +++ b/lib/table.h @@ -31,7 +31,7 @@ extern "C" { #endif -DECLARE_MTYPE(ROUTE_NODE) +DECLARE_MTYPE(ROUTE_NODE); /* * Forward declarations. @@ -59,7 +59,7 @@ struct route_table_delegate_t_ { route_table_destroy_node_func_t destroy_node; }; -PREDECL_HASH(rn_hash_node) +PREDECL_HASH(rn_hash_node); /* Routing table top structure. */ struct route_table { diff --git a/lib/termtable.c b/lib/termtable.c index b22a1ad387..ddf8822853 100644 --- a/lib/termtable.c +++ b/lib/termtable.c @@ -24,7 +24,7 @@ #include "memory.h" #include "termtable.h" -DEFINE_MTYPE_STATIC(LIB, TTABLE, "ASCII table") +DEFINE_MTYPE_STATIC(LIB, TTABLE, "ASCII table"); /* clang-format off */ const struct ttable_style ttable_styles[] = { diff --git a/lib/thread.c b/lib/thread.c index af01c75a44..866090341e 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -38,12 +38,12 @@ #include "libfrr_trace.h" #include "libfrr.h" -DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread") -DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master") -DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info") -DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats") +DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread"); +DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master"); +DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info"); +DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats"); -DECLARE_LIST(thread_list, struct thread, threaditem) +DECLARE_LIST(thread_list, struct thread, threaditem); struct cancel_req { int flags; @@ -68,7 +68,7 @@ static int thread_timer_cmp(const struct thread *a, const struct thread *b) return 0; } -DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp) +DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp); #if defined(__APPLE__) #include <mach/mach.h> diff --git a/lib/thread.h b/lib/thread.h index cdef531ad4..af68331131 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -41,8 +41,8 @@ struct rusage_t { #define GETRUSAGE(X) thread_getrusage(X) -PREDECL_LIST(thread_list) -PREDECL_HEAP(thread_timer_list) +PREDECL_LIST(thread_list); +PREDECL_HEAP(thread_timer_list); struct fd_handler { /* number of pfd that fit in the allocated space of pfds. This is a diff --git a/lib/typerb.h b/lib/typerb.h index fca45e20d1..60e6d09016 100644 --- a/lib/typerb.h +++ b/lib/typerb.h @@ -65,7 +65,8 @@ struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe); #define _PREDECL_RBTREE(prefix) \ struct prefix ## _head { struct typed_rb_root rr; }; \ -struct prefix ## _item { struct typed_rb_entry re; }; +struct prefix ## _item { struct typed_rb_entry re; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_RBTREE_UNIQ(var) { } #define INIT_RBTREE_NONUNIQ(var) { } @@ -140,7 +141,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->rr.count; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ #define PREDECL_RBTREE_UNIQ(prefix) \ _PREDECL_RBTREE(prefix) @@ -161,8 +162,8 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \ } \ TYPESAFE_FIND(prefix, type) \ \ -_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp) \ -/* ... */ +_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp); \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define PREDECL_RBTREE_NONUNIQ(prefix) \ _PREDECL_RBTREE(prefix) @@ -188,8 +189,8 @@ macro_inline int prefix ## __cmp_uq(const struct typed_rb_entry *a, \ return 0; \ } \ \ -_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp_uq) \ -/* ... */ +_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp_uq); \ +MACRO_REQUIRE_SEMICOLON() /* end */ #ifdef __cplusplus } diff --git a/lib/typesafe.c b/lib/typesafe.c index 69796e2d81..76705fad0d 100644 --- a/lib/typesafe.c +++ b/lib/typesafe.c @@ -25,9 +25,9 @@ #include "memory.h" #include "network.h" -DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket") -DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow") -DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array") +DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket"); +DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow"); +DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array"); #if 0 static void hash_consistency_check(struct thash_head *head) diff --git a/lib/typesafe.h b/lib/typesafe.h index e134316dd9..27e7be1286 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -105,15 +105,16 @@ static inline void typesafe_list_add(struct slist_head *head, /* use as: * - * PREDECL_LIST(namelist) + * PREDECL_LIST(namelist); * struct name { * struct namelist_item nlitem; * } - * DECLARE_LIST(namelist, struct name, nlitem) + * DECLARE_LIST(namelist, struct name, nlitem); */ #define PREDECL_LIST(prefix) \ struct prefix ## _head { struct slist_head sh; }; \ -struct prefix ## _item { struct slist_item si; }; +struct prefix ## _item { struct slist_item si; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_LIST(var) { .sh = { .last_next = &var.sh.first, }, } @@ -191,7 +192,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ /* don't use these structs directly */ struct dlist_item { @@ -218,7 +219,8 @@ static inline void typesafe_dlist_add(struct dlist_head *head, */ #define PREDECL_DLIST(prefix) \ struct prefix ## _head { struct dlist_head dh; }; \ -struct prefix ## _item { struct dlist_item di; }; +struct prefix ## _item { struct dlist_item di; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_DLIST(var) { .dh = { \ .hitem = { &var.dh.hitem, &var.dh.hitem }, }, } @@ -295,7 +297,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->dh.count; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ /* note: heap currently caps out at 4G items */ @@ -319,7 +321,8 @@ struct heap_head { #define PREDECL_HEAP(prefix) \ struct prefix ## _head { struct heap_head hh; }; \ -struct prefix ## _item { struct heap_item hi; }; +struct prefix ## _item { struct heap_item hi; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_HEAP(var) { } @@ -402,7 +405,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ extern void typesafe_heap_resize(struct heap_head *head, bool grow); extern void typesafe_heap_pushdown(struct heap_head *head, uint32_t index, @@ -438,7 +441,8 @@ struct ssort_head { */ #define _PREDECL_SORTLIST(prefix) \ struct prefix ## _head { struct ssort_head sh; }; \ -struct prefix ## _item { struct ssort_item si; }; +struct prefix ## _item { struct ssort_item si; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_SORTLIST_UNIQ(var) { } #define INIT_SORTLIST_NONUNIQ(var) { } @@ -537,10 +541,10 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ #define DECLARE_SORTLIST_UNIQ(prefix, type, field, cmpfn) \ - _DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn) \ + _DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn); \ \ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \ const type *item) \ @@ -555,7 +559,7 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \ return container_of(sitem, type, field.si); \ } \ TYPESAFE_FIND(prefix, type) \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ #define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \ macro_inline int _ ## prefix ## _cmp(const type *a, const type *b) \ @@ -569,8 +573,8 @@ macro_inline int _ ## prefix ## _cmp(const type *a, const type *b) \ return 1; \ return 0; \ } \ - _DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp) \ -/* ... */ + _DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp); \ +MACRO_REQUIRE_SEMICOLON() /* end */ /* hash, "sorted" by hash value @@ -616,7 +620,8 @@ extern void typesafe_hash_shrink(struct thash_head *head); */ #define PREDECL_HASH(prefix) \ struct prefix ## _head { struct thash_head hh; }; \ -struct prefix ## _item { struct thash_item hi; }; +struct prefix ## _item { struct thash_item hi; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_HASH(var) { } @@ -734,7 +739,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ /* skiplist, sorted. * can be used as priority queue with add / pop @@ -769,7 +774,8 @@ struct sskip_head { */ #define _PREDECL_SKIPLIST(prefix) \ struct prefix ## _head { struct sskip_head sh; }; \ -struct prefix ## _item { struct sskip_item si; }; +struct prefix ## _item { struct sskip_item si; }; \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define INIT_SKIPLIST_UNIQ(var) { } #define INIT_SKIPLIST_NONUNIQ(var) { } @@ -840,7 +846,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ -/* ... */ +MACRO_REQUIRE_SEMICOLON() /* end */ #define PREDECL_SKIPLIST_UNIQ(prefix) \ _PREDECL_SKIPLIST(prefix) @@ -862,8 +868,8 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \ TYPESAFE_FIND(prefix, type) \ \ _DECLARE_SKIPLIST(prefix, type, field, \ - prefix ## __cmp, prefix ## __cmp) \ -/* ... */ + prefix ## __cmp, prefix ## __cmp); \ +MACRO_REQUIRE_SEMICOLON() /* end */ #define PREDECL_SKIPLIST_NONUNIQ(prefix) \ _PREDECL_SKIPLIST(prefix) @@ -890,8 +896,8 @@ macro_inline int prefix ## __cmp_uq(const struct sskip_item *a, \ } \ \ _DECLARE_SKIPLIST(prefix, type, field, \ - prefix ## __cmp, prefix ## __cmp_uq) \ -/* ... */ + prefix ## __cmp, prefix ## __cmp_uq); \ +MACRO_REQUIRE_SEMICOLON() /* end */ extern struct sskip_item *typesafe_skiplist_add(struct sskip_head *head, diff --git a/lib/vector.c b/lib/vector.c index 0631e836f6..565c49fd59 100644 --- a/lib/vector.c +++ b/lib/vector.c @@ -23,8 +23,8 @@ #include "vector.h" #include "memory.h" -DEFINE_MTYPE_STATIC(LIB, VECTOR, "Vector") -DEFINE_MTYPE_STATIC(LIB, VECTOR_INDEX, "Vector index") +DEFINE_MTYPE_STATIC(LIB, VECTOR, "Vector"); +DEFINE_MTYPE_STATIC(LIB, VECTOR_INDEX, "Vector index"); /* Initialize vector : allocate memory and return vector. */ vector vector_init(unsigned int size) @@ -42,10 +42,10 @@ /* default VRF name value used when VRF backend is not NETNS */ #define VRF_DEFAULT_NAME_INTERNAL "default" -DEFINE_MTYPE_STATIC(LIB, VRF, "VRF") -DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map") +DEFINE_MTYPE_STATIC(LIB, VRF, "VRF"); +DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map"); -DEFINE_QOBJ_TYPE(vrf) +DEFINE_QOBJ_TYPE(vrf); static __inline int vrf_id_compare(const struct vrf *, const struct vrf *); static __inline int vrf_name_compare(const struct vrf *, const struct vrf *); @@ -1110,7 +1110,7 @@ static int lib_vrf_create(struct nb_cb_create_args *args) vrfp = vrf_get(VRF_UNKNOWN, vrfname); - vrf_set_user_cfged(vrfp); + SET_FLAG(vrfp->status, VRF_CONFIGURED); nb_running_set_entry(args->dnode, vrfp); return NB_OK; @@ -1136,7 +1136,7 @@ static int lib_vrf_destroy(struct nb_cb_destroy_args *args) vrfp = nb_running_unset_entry(args->dnode); /* Clear configured flag and invoke delete. */ - vrf_reset_user_cfged(vrfp); + UNSET_FLAG(vrfp->status, VRF_CONFIGURED); vrf_delete(vrfp); break; } @@ -95,13 +95,13 @@ struct vrf { /* Back pointer to namespace context */ void *ns_ctxt; - QOBJ_FIELDS + QOBJ_FIELDS; }; RB_HEAD(vrf_id_head, vrf); RB_PROTOTYPE(vrf_id_head, vrf, id_entry, vrf_id_compare) RB_HEAD(vrf_name_head, vrf); RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare) -DECLARE_QOBJ_TYPE(vrf) +DECLARE_QOBJ_TYPE(vrf); /* Allow VRF with netns as backend */ enum vrf_backend_type { @@ -159,18 +159,6 @@ static inline int vrf_is_user_cfged(struct vrf *vrf) return vrf && CHECK_FLAG(vrf->status, VRF_CONFIGURED); } -/* Mark that VRF has user configuration */ -static inline void vrf_set_user_cfged(struct vrf *vrf) -{ - SET_FLAG(vrf->status, VRF_CONFIGURED); -} - -/* Mark that VRF no longer has any user configuration */ -static inline void vrf_reset_user_cfged(struct vrf *vrf) -{ - UNSET_FLAG(vrf->status, VRF_CONFIGURED); -} - static inline uint32_t vrf_interface_count(struct vrf *vrf) { uint32_t count = 0; @@ -56,9 +56,9 @@ #include "lib/vty_clippy.c" #endif -DEFINE_MTYPE_STATIC(LIB, VTY, "VTY") -DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer") -DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history") +DEFINE_MTYPE_STATIC(LIB, VTY, "VTY"); +DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer"); +DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history"); /* Vty events */ enum event { @@ -159,6 +159,8 @@ int vty_out(struct vty *vty, const char *format, ...) char buf[1024]; char *p = NULL; char *filtered; + /* format string may contain %m, keep errno intact for printfrr */ + int saved_errno = errno; if (vty->frame_pos) { vty->frame_pos = 0; @@ -166,6 +168,7 @@ int vty_out(struct vty *vty, const char *format, ...) } va_start(args, format); + errno = saved_errno; p = vasnprintfrr(MTYPE_VTY_OUT_BUF, buf, sizeof(buf), format, args); va_end(args); diff --git a/lib/wheel.c b/lib/wheel.c index 5bdd6292f9..1a0469b256 100644 --- a/lib/wheel.c +++ b/lib/wheel.c @@ -24,8 +24,8 @@ #include "wheel.h" #include "log.h" -DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel") -DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List") +DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel"); +DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List"); static int debug_timer_wheel = 0; diff --git a/lib/workqueue.c b/lib/workqueue.c index 8eabdf52e7..2a8326c056 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -28,9 +28,9 @@ #include "command.h" #include "log.h" -DEFINE_MTYPE(LIB, WORK_QUEUE, "Work queue") -DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_ITEM, "Work queue item") -DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_NAME, "Work queue name string") +DEFINE_MTYPE(LIB, WORK_QUEUE, "Work queue"); +DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_ITEM, "Work queue item"); +DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_NAME, "Work queue name string"); /* master list of work_queues */ static struct list _work_queues; diff --git a/lib/workqueue.h b/lib/workqueue.h index 7c610f5dd6..b076ed0d28 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -30,7 +30,7 @@ extern "C" { #endif -DECLARE_MTYPE(WORK_QUEUE) +DECLARE_MTYPE(WORK_QUEUE); /* Hold time for the initial schedule of a queue run, in millisec */ #define WORK_QUEUE_DEFAULT_HOLD 50 diff --git a/lib/xref.c b/lib/xref.c index 40efe51363..a41f91a228 100644 --- a/lib/xref.c +++ b/lib/xref.c @@ -93,8 +93,6 @@ static void xref_add_one(const struct xref *xref) q = memrchr(filename, '/', p - filename); if (q) filename = q + 1; - else - filename = p + 1; } SHA256_Init(&sha); diff --git a/lib/xref.h b/lib/xref.h index b3243fa058..b1cb172b41 100644 --- a/lib/xref.h +++ b/lib/xref.h @@ -162,7 +162,7 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL; xref_block_add(&_xref_block); \ } \ asm(XREF_NOTE); \ - /* end */ + MACRO_REQUIRE_SEMICOLON() /* end */ /* the following blurb emits an ELF note indicating start and end of the xref * array in the binary. This is technically the "correct" entry point for diff --git a/lib/yang.c b/lib/yang.c index 383dc9f5eb..df3b07fb09 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -27,8 +27,8 @@ #include <libyang/user_types.h> -DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module") -DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure") +DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module"); +DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure"); /* libyang container. */ struct ly_ctx *ly_native_ctx; diff --git a/lib/yang_translator.c b/lib/yang_translator.c index 1f64675d6a..5b1d96f24c 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -26,9 +26,9 @@ #include "yang_translator.h" #include "frrstr.h" -DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR, "YANG Translator") -DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MODULE, "YANG Translator Module") -DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MAPPING, "YANG Translator Mapping") +DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR, "YANG Translator"); +DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MODULE, "YANG Translator Module"); +DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MAPPING, "YANG Translator Mapping"); /* Generate the yang_translators tree. */ static inline int yang_translator_compare(const struct yang_translator *a, diff --git a/lib/zassert.h b/lib/zassert.h index e6b254ee8d..527282c4f2 100644 --- a/lib/zassert.h +++ b/lib/zassert.h @@ -28,14 +28,7 @@ extern void _zlog_assert_failed(const char *assertion, const char *file, __attribute__((noreturn)); #undef __ASSERT_FUNCTION - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #define __ASSERT_FUNCTION __func__ -#elif defined(__GNUC__) -#define __ASSERT_FUNCTION __FUNCTION__ -#else -#define __ASSERT_FUNCTION NULL -#endif #define zassert(EX) \ ((void)((EX) ? 0 : (_zlog_assert_failed(#EX, __FILE__, __LINE__, \ diff --git a/lib/zclient.c b/lib/zclient.c index c5e844933c..c78937c1ec 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -42,8 +42,8 @@ #include "srte.h" #include "printfrr.h" -DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient") -DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs") +DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient"); +DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs"); /* Zebra client events. */ enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT }; diff --git a/lib/zclient.h b/lib/zclient.h index 43197534a8..bd952ea1e6 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -213,6 +213,8 @@ typedef enum { ZEBRA_NHG_ADD, ZEBRA_NHG_DEL, ZEBRA_NHG_NOTIFY_OWNER, + ZEBRA_EVPN_REMOTE_NH_ADD, + ZEBRA_EVPN_REMOTE_NH_DEL, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -1132,7 +1134,7 @@ int zapi_opaque_reg_decode(struct stream *msg, */ enum zapi_opaque_registry { /* Request link-state database dump, at restart for example */ - LINK_STATE_REQUEST = 1, + LINK_STATE_SYNC = 1, /* Update containing link-state db info */ LINK_STATE_UPDATE = 2, /* Request LDP-SYNC state from LDP */ diff --git a/lib/zebra.h b/lib/zebra.h index ded44ac636..5c3d91ba74 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -80,21 +80,6 @@ /* misc include group */ #include <stdarg.h> -#if !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) -/* Not C99; do we need to define va_copy? */ -#ifndef va_copy -#ifdef __va_copy -#define va_copy(DST,SRC) __va_copy(DST,SRC) -#else -/* Now we are desperate; this should work on many typical platforms. - But this is slightly dangerous, because the standard does not require - va_copy to be a macro. */ -#define va_copy(DST,SRC) memcpy(&(DST), &(SRC), sizeof(va_list)) -#warning "Not C99 and no va_copy macro available, falling back to memcpy" -#endif /* __va_copy */ -#endif /* !va_copy */ -#endif /* !C99 */ - #ifdef HAVE_LCAPS #include <sys/capability.h> diff --git a/lib/zlog.c b/lib/zlog.c index 51509e24f4..f546709328 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -54,20 +54,22 @@ #include "zlog.h" #include "libfrr_trace.h" -DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message") -DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer") +DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message"); +DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer"); DEFINE_HOOK(zlog_init, (const char *progname, const char *protoname, unsigned short instance, uid_t uid, gid_t gid), - (progname, protoname, instance, uid, gid)) -DEFINE_KOOH(zlog_fini, (), ()) + (progname, protoname, instance, uid, gid)); +DEFINE_KOOH(zlog_fini, (), ()); DEFINE_HOOK(zlog_aux_init, (const char *prefix, int prio_min), - (prefix, prio_min)) + (prefix, prio_min)); char zlog_prefix[128]; size_t zlog_prefixsz; int zlog_tmpdirfd = -1; +static atomic_bool zlog_ec = true, zlog_xid = true; + /* these are kept around because logging is initialized (and directories * & files created) before zprivs code switches to the FRR user; therefore * we need to chown() things so we don't get permission errors later when @@ -530,12 +532,54 @@ const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen) { if (!msg->text) { va_list args; + bool do_xid, do_ec; + size_t need = 0, hdrlen; + struct fbuf fb = { + .buf = msg->stackbuf, + .pos = msg->stackbuf, + .len = msg->stackbufsz, + }; + + do_ec = atomic_load_explicit(&zlog_ec, memory_order_relaxed); + do_xid = atomic_load_explicit(&zlog_xid, memory_order_relaxed); + + if (msg->xref && do_xid && msg->xref->xref.xrefdata->uid[0]) { + need += bputch(&fb, '['); + need += bputs(&fb, msg->xref->xref.xrefdata->uid); + need += bputch(&fb, ']'); + } + if (msg->xref && do_ec && msg->xref->ec) + need += bprintfrr(&fb, "[EC %u]", msg->xref->ec); + if (need) + need += bputch(&fb, ' '); + + hdrlen = need; + assert(hdrlen < msg->stackbufsz); va_copy(args, msg->args); - msg->text = vasnprintfrr(MTYPE_LOG_MESSAGE, msg->stackbuf, - msg->stackbufsz, msg->fmt, args); - msg->textlen = strlen(msg->text); + need += vbprintfrr(&fb, msg->fmt, args); va_end(args); + + msg->textlen = need; + need += bputch(&fb, '\0'); + + if (need <= msg->stackbufsz) + msg->text = msg->stackbuf; + else { + msg->text = XMALLOC(MTYPE_LOG_MESSAGE, need); + + memcpy(msg->text, msg->stackbuf, hdrlen); + + fb.buf = msg->text; + fb.len = need; + fb.pos = msg->text + hdrlen; + + va_copy(args, msg->args); + vbprintfrr(&fb, msg->fmt, args); + va_end(args); + + bputch(&fb, '\0'); + } } if (textlen) *textlen = msg->textlen; @@ -619,6 +663,26 @@ size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz, } } +void zlog_set_prefix_ec(bool enable) +{ + atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed); +} + +bool zlog_get_prefix_ec(void) +{ + return atomic_load_explicit(&zlog_ec, memory_order_relaxed); +} + +void zlog_set_prefix_xid(bool enable) +{ + atomic_store_explicit(&zlog_xid, enable, memory_order_relaxed); +} + +bool zlog_get_prefix_xid(void) +{ + return atomic_load_explicit(&zlog_xid, memory_order_relaxed); +} + /* setup functions */ struct zlog_target *zlog_target_clone(struct memtype *mt, diff --git a/lib/zlog.h b/lib/zlog.h index 4fdb47bb95..66d8f1e5d7 100644 --- a/lib/zlog.h +++ b/lib/zlog.h @@ -85,31 +85,6 @@ static inline void zlog_ref(const struct xref_logmsg *xref, va_end(ap); } -#define _zlog_ref(prio, msg, ...) \ - do { \ - static struct xrefdata _xrefdata = { \ - .xref = NULL, \ - .uid = {}, \ - .hashstr = (msg), \ - .hashu32 = {(prio), 0}, \ - }; \ - static const struct xref_logmsg _xref __attribute__( \ - (used)) = { \ - .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \ - .fmtstring = (msg), \ - .priority = (prio), \ - .args = (#__VA_ARGS__), \ - }; \ - XREF_LINK(_xref.xref); \ - zlog_ref(&_xref, (msg), ##__VA_ARGS__); \ - } while (0) - -#define zlog_err(...) _zlog_ref(LOG_ERR, __VA_ARGS__) -#define zlog_warn(...) _zlog_ref(LOG_WARNING, __VA_ARGS__) -#define zlog_info(...) _zlog_ref(LOG_INFO, __VA_ARGS__) -#define zlog_notice(...) _zlog_ref(LOG_NOTICE, __VA_ARGS__) -#define zlog_debug(...) _zlog_ref(LOG_DEBUG, __VA_ARGS__) - #define _zlog_ecref(ec_, prio, msg, ...) \ do { \ static struct xrefdata _xrefdata = { \ @@ -127,18 +102,22 @@ static inline void zlog_ref(const struct xref_logmsg *xref, .args = (#__VA_ARGS__), \ }; \ XREF_LINK(_xref.xref); \ - zlog_ref(&_xref, "[EC %u] " msg, ec_, ##__VA_ARGS__); \ + zlog_ref(&_xref, (msg), ##__VA_ARGS__); \ } while (0) +#define zlog_err(...) _zlog_ecref(0, LOG_ERR, __VA_ARGS__) +#define zlog_warn(...) _zlog_ecref(0, LOG_WARNING, __VA_ARGS__) +#define zlog_info(...) _zlog_ecref(0, LOG_INFO, __VA_ARGS__) +#define zlog_notice(...) _zlog_ecref(0, LOG_NOTICE, __VA_ARGS__) +#define zlog_debug(...) _zlog_ecref(0, LOG_DEBUG, __VA_ARGS__) + #define flog_err(ferr_id, format, ...) \ _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__) #define flog_warn(ferr_id, format, ...) \ _zlog_ecref(ferr_id, LOG_WARNING, format, ## __VA_ARGS__) #define flog_err_sys(ferr_id, format, ...) \ - flog_err(ferr_id, format, ##__VA_ARGS__) -#define flog(priority, ferr_id, format, ...) \ - zlog(priority, "[EC %u] " format, ferr_id, ##__VA_ARGS__) + _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__) extern void zlog_sigsafe(const char *text, size_t len); @@ -203,7 +182,7 @@ extern size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz, * additional options. It MUST be the first field in that larger struct. */ -PREDECL_ATOMLIST(zlog_targets) +PREDECL_ATOMLIST(zlog_targets); struct zlog_target { struct zlog_targets_item head; @@ -247,17 +226,22 @@ extern void zlog_init(const char *progname, const char *protoname, unsigned short instance, uid_t uid, gid_t gid); DECLARE_HOOK(zlog_init, (const char *progname, const char *protoname, unsigned short instance, uid_t uid, gid_t gid), - (progname, protoname, instance, uid, gid)) + (progname, protoname, instance, uid, gid)); extern void zlog_fini(void); -DECLARE_KOOH(zlog_fini, (), ()) +DECLARE_KOOH(zlog_fini, (), ()); + +extern void zlog_set_prefix_ec(bool enable); +extern bool zlog_get_prefix_ec(void); +extern void zlog_set_prefix_xid(bool enable); +extern bool zlog_get_prefix_xid(void); /* for tools & test programs, i.e. anything not a daemon. * (no cleanup needed at exit) */ extern void zlog_aux_init(const char *prefix, int prio_min); DECLARE_HOOK(zlog_aux_init, (const char *prefix, int prio_min), - (prefix, prio_min)) + (prefix, prio_min)); extern void zlog_startup_end(void); diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c index 8f4c2a46a8..f258a8fbbd 100644 --- a/lib/zlog_targets.c +++ b/lib/zlog_targets.c @@ -31,13 +31,13 @@ * absolute end. */ -DECLARE_MGROUP(LOG) -DEFINE_MGROUP_ACTIVEATEXIT(LOG, "logging subsystem") +DECLARE_MGROUP(LOG); +DEFINE_MGROUP_ACTIVEATEXIT(LOG, "logging subsystem"); -DEFINE_MTYPE_STATIC(LOG, LOG_FD, "log file target") -DEFINE_MTYPE_STATIC(LOG, LOG_FD_NAME, "log file name") -DEFINE_MTYPE_STATIC(LOG, LOG_FD_ROTATE, "log file rotate helper") -DEFINE_MTYPE_STATIC(LOG, LOG_SYSL, "syslog target") +DEFINE_MTYPE_STATIC(LOG, LOG_FD, "log file target"); +DEFINE_MTYPE_STATIC(LOG, LOG_FD_NAME, "log file name"); +DEFINE_MTYPE_STATIC(LOG, LOG_FD_ROTATE, "log file rotate helper"); +DEFINE_MTYPE_STATIC(LOG, LOG_SYSL, "syslog target"); struct zlt_fd { struct zlog_target zt; diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4 index d383ad5c6d..b7872d9870 100644 --- a/m4/ax_pthread.m4 +++ b/m4/ax_pthread.m4 @@ -219,7 +219,7 @@ for flag in $ax_pthread_flags; do # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h> - static void routine(void *a) { a = 0; } + static void routine(void *a) { if (a) a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); diff --git a/nhrpd/debug.h b/nhrpd/debug.h index db4bac7916..e9428fa90a 100644 --- a/nhrpd/debug.h +++ b/nhrpd/debug.h @@ -18,26 +18,8 @@ extern unsigned int debug_flags; -#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L - #define debugf(level, ...) \ do { \ if (unlikely(debug_flags & level)) \ zlog_debug(__VA_ARGS__); \ } while (0) - -#elif defined __GNUC__ - -#define debugf(level, _args...) \ - do { \ - if (unlikely(debug_flags & level)) \ - zlog_debug(_args); \ - } while (0) - -#else - -static inline void debugf(int level, const char *format, ...) -{ -} - -#endif diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c index cb298b1a09..bcf0e2168c 100644 --- a/nhrpd/nhrp_cache.c +++ b/nhrpd/nhrp_cache.c @@ -15,8 +15,8 @@ #include "netlink.h" -DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry") -DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE_CONFIG, "NHRP cache config entry") +DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry"); +DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE_CONFIG, "NHRP cache config entry"); unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES]; @@ -212,7 +212,8 @@ static int nhrp_cache_do_timeout(struct thread *t) c->t_timeout = NULL; if (c->cur.type != NHRP_CACHE_INVALID) - nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); + nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL, + NULL); return 0; } @@ -301,7 +302,8 @@ static void nhrp_cache_peer_notifier(struct notifier_block *n, case NOTIFY_PEER_DOWN: case NOTIFY_PEER_IFCONFIG_CHANGED: notifier_call(&c->notifier_list, NOTIFY_CACHE_DOWN); - nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); + nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL, + NULL); break; case NOTIFY_PEER_NBMA_CHANGING: if (c->cur.type == NHRP_CACHE_DYNAMIC) @@ -422,7 +424,8 @@ static void nhrp_cache_newpeer_notifier(struct notifier_block *n, int nhrp_cache_update_binding(struct nhrp_cache *c, enum nhrp_cache_type type, int holding_time, struct nhrp_peer *p, - uint32_t mtu, union sockunion *nbma_oa) + uint32_t mtu, union sockunion *nbma_oa, + union sockunion *nbma_claimed) { char buf[2][SU_ADDRSTRLEN]; @@ -464,6 +467,12 @@ int nhrp_cache_update_binding(struct nhrp_cache *c, enum nhrp_cache_type type, memset(&c->cur.remote_nbma_natoa, 0, sizeof(c->cur.remote_nbma_natoa)); + if (nbma_claimed) + c->cur.remote_nbma_claimed = *nbma_claimed; + else + memset(&c->cur.remote_nbma_claimed, 0, + sizeof(c->cur.remote_nbma_claimed)); + nhrp_peer_unref(p); } else { debugf(NHRP_DEBUG_COMMON, @@ -474,9 +483,13 @@ int nhrp_cache_update_binding(struct nhrp_cache *c, enum nhrp_cache_type type, c->new.type = type; c->new.peer = p; c->new.mtu = mtu; + c->new.holding_time = holding_time; if (nbma_oa) c->new.remote_nbma_natoa = *nbma_oa; + if (nbma_claimed) + c->new.remote_nbma_claimed = *nbma_claimed; + if (holding_time > 0) c->new.expires = monotime(NULL) + holding_time; else if (holding_time < 0) diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index b348cc0def..a6880054fd 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -21,7 +21,7 @@ #include "os.h" #include "netlink.h" -DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface") +DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface"); static void nhrp_interface_update_cache_config(struct interface *ifp, bool available, @@ -255,7 +255,7 @@ static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, nc = nhrp_cache_get(ifp, &if_ad->addr, 0); if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, -1, - NULL, 0, NULL); + NULL, 0, NULL, NULL); } debugf(NHRP_DEBUG_KERNEL, "%s: IPv%d address changed to %s", ifp->name, @@ -267,7 +267,7 @@ static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, nc = nhrp_cache_get(ifp, &addr, 1); if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, 0, NULL, - 0, NULL); + 0, NULL, NULL); } notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED); @@ -364,7 +364,7 @@ static void interface_config_update_nhrp_map(struct nhrp_cache_config *cc, if (c && c->map) { nhrp_cache_update_binding( c, c->cur.type, -1, - nhrp_peer_get(ifp, &nbma_addr), 0, NULL); + nhrp_peer_get(ifp, &nbma_addr), 0, NULL, NULL); } return; } @@ -375,11 +375,11 @@ static void interface_config_update_nhrp_map(struct nhrp_cache_config *cc, c->map = 1; if (cc->type == NHRP_CACHE_LOCAL) nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0, - NULL); + NULL, NULL); else { nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0, nhrp_peer_get(ifp, &cc->nbma), 0, - NULL); + NULL, NULL); } } diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 49a4900bf8..5c819017f4 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -29,7 +29,7 @@ #include "netlink.h" #include "nhrp_errors.h" -DEFINE_MGROUP(NHRPD, "NHRP") +DEFINE_MGROUP(NHRPD, "NHRP"); unsigned int debug_flags = 0; @@ -128,7 +128,8 @@ FRR_DAEMON_INFO(nhrpd, NHRP, .vty_port = NHRP_VTY_PORT, .signals = sighandlers, .n_signals = array_size(sighandlers), .privs = &nhrpd_privs, .yang_modules = nhrpd_yang_modules, - .n_yang_modules = array_size(nhrpd_yang_modules), ) + .n_yang_modules = array_size(nhrpd_yang_modules), +); int main(int argc, char **argv) { diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index ae5737d736..b78bf92784 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -14,8 +14,8 @@ #include "nhrpd.h" #include "nhrp_protocol.h" -DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server") -DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries") +DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server"); +DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries"); static int nhrp_nhs_resolve(struct thread *t); static int nhrp_reg_send_req(struct thread *t); @@ -32,7 +32,9 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) struct nhrp_cie_header *cie; struct nhrp_cache *c; struct zbuf extpl; - union sockunion cie_nbma, cie_proto, *proto; + union sockunion cie_nbma, cie_nbma_nhs, cie_proto, cie_proto_nhs, + *proto; + char buf[64]; int ok = 0, holdtime; unsigned short mtu = 0; @@ -66,6 +68,7 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) /* Parse extensions */ sockunion_family(&nifp->nat_nbma) = AF_UNSPEC; + sockunion_family(&cie_nbma_nhs) = AF_UNSPEC; while ((ext = nhrp_ext_pull(&p->extensions, &extpl)) != NULL) { switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { case NHRP_EXTENSION_NAT_ADDRESS: @@ -75,10 +78,17 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) &cie_proto)) { nifp->nat_nbma = cie_nbma; debugf(NHRP_DEBUG_IF, - "%s: NAT detected, real NBMA address: %pSU", - ifp->name, &nifp->nbma); + "%s: NAT detected, real NBMA address: %s", + ifp->name, + sockunion2str(&nifp->nbma, buf, + sizeof(buf))); } break; + case NHRP_EXTENSION_RESPONDER_ADDRESS: + /* NHS adds its own record as responder address */ + nhrp_cie_pull(&extpl, p->hdr, &cie_nbma_nhs, + &cie_proto_nhs); + break; } } @@ -96,7 +106,8 @@ static void nhrp_reg_reply(struct nhrp_reqid *reqid, void *arg) c = nhrp_cache_get(ifp, &p->dst_proto, 1); if (c) nhrp_cache_update_binding(c, NHRP_CACHE_NHS, holdtime, - nhrp_peer_ref(r->peer), mtu, NULL); + nhrp_peer_ref(r->peer), mtu, NULL, + &cie_nbma_nhs); } static int nhrp_reg_timeout(struct thread *t) @@ -111,7 +122,7 @@ static int nhrp_reg_timeout(struct thread *t) c = nhrp_cache_get(r->nhs->ifp, &r->proto_addr, 0); if (c) nhrp_cache_update_binding(c, NHRP_CACHE_NHS, -1, NULL, - 0, NULL); + 0, NULL, NULL); sockunion_family(&r->proto_addr) = AF_UNSPEC; } @@ -162,7 +173,7 @@ static int nhrp_reg_send_req(struct thread *t) struct interface *ifp = nhs->ifp; struct nhrp_interface *nifp = ifp->info; struct nhrp_afi_data *if_ad = &nifp->afi[nhs->afi]; - union sockunion *dst_proto; + union sockunion *dst_proto, nhs_proto; struct zbuf *zb; struct nhrp_packet_header *hdr; struct nhrp_extension_header *ext; @@ -207,17 +218,34 @@ static int nhrp_reg_send_req(struct thread *t) /* FIXME: push CIE for each local protocol address */ cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL); /* RFC2332 5.2.1 if unique is set then prefix length must be 0xff */ - cie->prefix_length = (if_ad->flags & NHRP_IFF_REG_NO_UNIQUE) ? 8 * sockunion_get_addrlen(dst_proto) : 0xff; + cie->prefix_length = (if_ad->flags & NHRP_IFF_REG_NO_UNIQUE) + ? 8 * sockunion_get_addrlen(dst_proto) + : 0xff; cie->holding_time = htons(if_ad->holdtime); cie->mtu = htons(if_ad->mtu); nhrp_ext_request(zb, hdr, ifp); /* Cisco NAT detection extension */ + if (sockunion_family(&r->proto_addr) != AF_UNSPEC) { + nhs_proto = r->proto_addr; + } else if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC) { + nhs_proto = nhs->proto_addr; + } else { + /* cisco magic: If NHS is not known then use all 0s as + * client protocol address in NAT Extension header + */ + memset(&nhs_proto, 0, sizeof(nhs_proto)); + sockunion_family(&nhs_proto) = afi2family(nhs->afi); + } + hdr->flags |= htons(NHRP_FLAG_REGISTRATION_NAT); ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); - cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nbma, &if_ad->addr); + /* push NHS details */ + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &r->peer->vc->remote.nbma, + &nhs_proto); cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr); + cie->mtu = htons(if_ad->mtu); nhrp_ext_complete(zb, ext); nhrp_packet_complete(zb, hdr); @@ -442,3 +470,29 @@ void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, cb(nhs, 0, ctx); } } + +int nhrp_nhs_match_ip(union sockunion *in_ip, struct nhrp_interface *nifp) +{ + int i; + struct nhrp_nhs *nhs; + struct nhrp_registration *reg; + + for (i = 0; i < AFI_MAX; i++) { + list_for_each_entry(nhs, &nifp->afi[i].nhslist_head, + nhslist_entry) + { + if (!list_empty(&nhs->reglist_head)) { + list_for_each_entry(reg, &nhs->reglist_head, + reglist_entry) + { + if (!sockunion_cmp( + in_ip, + ®->peer->vc->remote + .nbma)) + return 1; + } + } + } + } + return 0; +} diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c index a983aa71bc..fd77533c89 100644 --- a/nhrpd/nhrp_packet.c +++ b/nhrpd/nhrp_packet.c @@ -268,6 +268,7 @@ int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, &ad->addr); if (!cie) goto err; + cie->mtu = htons(ad->mtu); cie->holding_time = htons(ad->holdtime); break; default: diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 0d589e3056..199f3332d2 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -22,7 +22,7 @@ #include "nhrp_protocol.h" #include "os.h" -DEFINE_MTYPE_STATIC(NHRPD, NHRP_PEER, "NHRP peer entry") +DEFINE_MTYPE_STATIC(NHRPD, NHRP_PEER, "NHRP peer entry"); struct ipv6hdr { uint8_t priority_version; @@ -47,6 +47,7 @@ static void nhrp_peer_check_delete(struct nhrp_peer *p) p->ref, &p->vc->remote.nbma, &p->vc->local.nbma); THREAD_OFF(p->t_fallback); + THREAD_OFF(p->t_timer); hash_release(nifp->peer_hash, p); nhrp_interface_notify_del(p->ifp, &p->ifp_notifier); nhrp_vc_notify_del(p->vc, &p->vc_notifier); @@ -182,8 +183,7 @@ static void *nhrp_peer_create(void *data) .ref = 0, .ifp = key->ifp, .vc = key->vc, - .notifier_list = - NOTIFIER_LIST_INITIALIZER(&p->notifier_list), + .notifier_list = NOTIFIER_LIST_INITIALIZER(&p->notifier_list), }; nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify); nhrp_interface_notify_add(p->ifp, &p->ifp_notifier, @@ -283,6 +283,30 @@ static int nhrp_peer_request_timeout(struct thread *t) return 0; } +static int nhrp_peer_defer_vici_request(struct thread *t) +{ + struct nhrp_peer *p = THREAD_ARG(t); + struct nhrp_vc *vc = p->vc; + struct interface *ifp = p->ifp; + struct nhrp_interface *nifp = ifp->info; + + THREAD_OFF(p->t_timer); + + if (p->online) { + debugf(NHRP_DEBUG_COMMON, + "IPsec connection to %pSU already established", + &vc->remote.nbma); + } else { + vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, + &vc->remote.nbma, p->prio); + thread_add_timer( + master, nhrp_peer_request_timeout, p, + (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30, + &p->t_fallback); + } + return 0; +} + int nhrp_peer_check(struct nhrp_peer *p, int establish) { struct nhrp_vc *vc = p->vc; @@ -304,11 +328,25 @@ int nhrp_peer_check(struct nhrp_peer *p, int establish) p->prio = establish > 1; p->requested = 1; - vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, &vc->remote.nbma, - p->prio); - thread_add_timer(master, nhrp_peer_request_timeout, p, - (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30, - &p->t_fallback); + + /* All NHRP registration requests are prioritized */ + if (p->prio) { + vici_request_vc(nifp->ipsec_profile, &vc->local.nbma, + &vc->remote.nbma, p->prio); + thread_add_timer( + master, nhrp_peer_request_timeout, p, + (nifp->ipsec_fallback_profile && !p->prio) ? 15 : 30, + &p->t_fallback); + } else { + /* Maximum timeout is 1 second */ + int r_time_ms = rand() % 1000; + + debugf(NHRP_DEBUG_COMMON, + "Initiating IPsec connection request to %pSU after %d ms:", + &vc->remote.nbma, r_time_ms); + thread_add_timer_msec(master, nhrp_peer_defer_vici_request, + p, r_time_ms, &p->t_timer); + } return 0; } @@ -341,6 +379,60 @@ void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb) zbuf_reset(zb); } +static void nhrp_process_nat_extension(struct nhrp_packet_parser *pp, + union sockunion *proto, + union sockunion *cie_nbma) +{ + union sockunion cie_proto; + struct zbuf payload; + struct nhrp_extension_header *ext; + struct zbuf *extensions; + + if (!cie_nbma) + return; + + sockunion_family(cie_nbma) = AF_UNSPEC; + + if (!proto || sockunion_family(proto) == AF_UNSPEC) + return; + + /* Handle extensions */ + extensions = zbuf_alloc(zbuf_used(&pp->extensions)); + if (extensions) { + zbuf_copy_peek(extensions, &pp->extensions, + zbuf_used(&pp->extensions)); + while ((ext = nhrp_ext_pull(extensions, &payload)) != NULL) { + switch (htons(ext->type) + & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_NAT_ADDRESS: + /* Process the NBMA and proto address in NAT + * extension and update the cache without which + * the neighbor table in the kernel contains the + * source NBMA address which is not reachable + * since it is behind a NAT device + */ + debugf(NHRP_DEBUG_COMMON, + "shortcut res_resp: Processing NAT Extension for %pSU", + proto); + while (nhrp_cie_pull(&payload, pp->hdr, + cie_nbma, &cie_proto)) { + if (sockunion_family(&cie_proto) + == AF_UNSPEC) + continue; + + if (!sockunion_cmp(proto, &cie_proto)) { + debugf(NHRP_DEBUG_COMMON, + "\tcie_nbma for proto %pSU is %pSU", + proto, cie_nbma); + break; + } + } + } + } + zbuf_free(extensions); + } +} + static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) { struct interface *ifp = pp->ifp; @@ -349,12 +441,12 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) struct nhrp_cie_header *cie; struct nhrp_extension_header *ext; struct nhrp_cache *c; - union sockunion cie_nbma, cie_proto, *proto_addr, *nbma_addr; + union sockunion cie_nbma, cie_nbma_nat, cie_proto, *proto_addr, + *nbma_addr, *claimed_nbma_addr; int holdtime, prefix_len, hostprefix_len; struct nhrp_interface *nifp = ifp->info; struct nhrp_peer *peer; size_t paylen; - char buf[SU_ADDRSTRLEN]; if (!(pp->if_ad->flags & NHRP_IFF_SHORTCUT)) { debugf(NHRP_DEBUG_COMMON, "Shortcuts disabled"); @@ -406,9 +498,41 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) proto_addr = (sockunion_family(&cie_proto) == AF_UNSPEC) ? &pp->src_proto : &cie_proto; - nbma_addr = (sockunion_family(&cie_nbma) == AF_UNSPEC) - ? &pp->src_nbma - : &cie_nbma; + + /* Check for this proto_addr in NHRP_NAT_EXTENSION */ + nhrp_process_nat_extension(pp, proto_addr, &cie_nbma_nat); + + if (sockunion_family(&cie_nbma_nat) == AF_UNSPEC) { + /* It may be possible that this resolution reply is + * coming directly from NATTED Spoke and there is not + * NAT Extension present + */ + debugf(NHRP_DEBUG_COMMON, + "shortcut res_rep: No NAT Extension for %pSU", + proto_addr); + + if (!sockunion_same(&pp->src_nbma, + &pp->peer->vc->remote.nbma) + && !nhrp_nhs_match_ip(&pp->peer->vc->remote.nbma, + nifp)) { + cie_nbma_nat = pp->peer->vc->remote.nbma; + debugf(NHRP_DEBUG_COMMON, + "shortcut res_rep: NAT detected using %pSU as cie_nbma", + &cie_nbma_nat); + } + } + + if (sockunion_family(&cie_nbma_nat) != AF_UNSPEC) + nbma_addr = &cie_nbma_nat; + else if (sockunion_family(&cie_nbma) != AF_UNSPEC) + nbma_addr = &cie_nbma; + else + nbma_addr = &pp->src_nbma; + + if (sockunion_family(&cie_nbma) != AF_UNSPEC) + claimed_nbma_addr = &cie_nbma; + else + claimed_nbma_addr = &pp->src_nbma; holdtime = htons(cie->holding_time); debugf(NHRP_DEBUG_COMMON, @@ -424,15 +548,14 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) cie->code = NHRP_CODE_INSUFFICIENT_RESOURCES; continue; } - if (nbma_addr) - sockunion2str(nbma_addr, buf, sizeof(buf)); debugf(NHRP_DEBUG_COMMON, - "shortcut res_rep: updating binding for nmba addr %s", - nbma_addr ? buf : "(NULL)"); - if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime, - nhrp_peer_ref(pp->peer), - htons(cie->mtu), nbma_addr)) { + "shortcut res_rep: updating binding for nmba addr %pSU", + nbma_addr); + if (!nhrp_cache_update_binding( + c, NHRP_CACHE_DYNAMIC, holdtime, + nhrp_peer_get(pp->ifp, nbma_addr), htons(cie->mtu), + nbma_addr, claimed_nbma_addr)) { cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED; continue; } @@ -468,17 +591,23 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) while ((ext = nhrp_ext_pull(&pp->extensions, &payload)) != NULL) { switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { case NHRP_EXTENSION_NAT_ADDRESS: - if (sockunion_family(&nifp->nat_nbma) == AF_UNSPEC) - break; ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); if (!ext) goto err; - cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, - &nifp->nat_nbma, &pp->if_ad->addr); - if (!cie) - goto err; - nhrp_ext_complete(zb, ext); + if (sockunion_family(&nifp->nat_nbma) != AF_UNSPEC) { + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, + &nifp->nat_nbma, + &pp->if_ad->addr); + if (!cie) + goto err; + cie->prefix_length = + 8 * sockunion_get_addrlen( + &pp->if_ad->addr); + + cie->mtu = htons(pp->if_ad->mtu); + nhrp_ext_complete(zb, ext); + } break; default: if (nhrp_ext_reply(zb, hdr, ifp, ext, &payload) < 0) @@ -486,7 +615,6 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) break; } } - nhrp_packet_complete(zb, hdr); nhrp_peer_send(peer, zb); err: @@ -559,7 +687,11 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) : &cie_nbma; nbma_natoa = NULL; if (natted) { - nbma_natoa = nbma_addr; + nbma_natoa = + (sockunion_family(&p->peer->vc->remote.nbma) + == AF_UNSPEC) + ? nbma_addr + : &p->peer->vc->remote.nbma; } holdtime = htons(cie->holding_time); @@ -574,7 +706,8 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) if (!nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holdtime, nhrp_peer_ref(p->peer), - htons(cie->mtu), nbma_natoa)) { + htons(cie->mtu), nbma_natoa, + nbma_addr)) { cie->code = NHRP_CODE_ADMINISTRATIVELY_PROHIBITED; continue; } @@ -592,9 +725,13 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) goto err; zbuf_copy(zb, &payload, zbuf_used(&payload)); if (natted) { - nhrp_cie_push(zb, NHRP_CODE_SUCCESS, - &p->peer->vc->remote.nbma, - &p->src_proto); + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, + &p->peer->vc->remote.nbma, + &p->src_proto); + cie->prefix_length = + 8 * sockunion_get_addrlen( + &p->if_ad->addr); + cie->mtu = htons(p->if_ad->mtu); } nhrp_ext_complete(zb, ext); break; @@ -794,20 +931,23 @@ static struct { static void nhrp_peer_forward(struct nhrp_peer *p, struct nhrp_packet_parser *pp) { - struct zbuf *zb, extpl; + struct zbuf *zb, *zb_copy, extpl; struct nhrp_packet_header *hdr; struct nhrp_extension_header *ext, *dst; struct nhrp_cie_header *cie; struct nhrp_interface *nifp = pp->ifp->info; struct nhrp_afi_data *if_ad = pp->if_ad; - union sockunion cie_nbma, cie_protocol; + union sockunion cie_nbma, cie_protocol, cie_protocol_mandatory, *proto; uint16_t type, len; + struct nhrp_cache *c; if (pp->hdr->hop_count == 0) return; /* Create forward packet - copy header */ zb = zbuf_alloc(1500); + zb_copy = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, pp->hdr->type, &pp->src_nbma, &pp->src_proto, &pp->dst_proto); hdr->flags = pp->hdr->flags; @@ -815,8 +955,13 @@ static void nhrp_peer_forward(struct nhrp_peer *p, hdr->u.request_id = pp->hdr->u.request_id; /* Copy payload */ + zbuf_copy_peek(zb_copy, &pp->payload, zbuf_used(&pp->payload)); zbuf_copy(zb, &pp->payload, zbuf_used(&pp->payload)); + /* Get CIE Extension from Mandatory part */ + sockunion_family(&cie_protocol_mandatory) = AF_UNSPEC; + nhrp_cie_pull(zb_copy, pp->hdr, &cie_nbma, &cie_protocol_mandatory); + /* Copy extensions */ while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) { type = htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY; @@ -848,19 +993,82 @@ static void nhrp_peer_forward(struct nhrp_peer *p, &nifp->nbma, &if_ad->addr); if (!cie) goto err; + cie->mtu = htons(if_ad->mtu); cie->holding_time = htons(if_ad->holdtime); } break; + case NHRP_EXTENSION_NAT_ADDRESS: + c = NULL; + proto = NULL; + + /* If NAT extension is empty then attempt to populate + * it with cached NBMA information + */ + if (len == 0) { + if (packet_types[hdr->type].type + == PACKET_REQUEST) { + debugf(NHRP_DEBUG_COMMON, + "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the request packet"); + proto = &pp->src_proto; + } else if (packet_types[hdr->type].type + == PACKET_REPLY) { + debugf(NHRP_DEBUG_COMMON, + "Processing NHRP_EXTENSION_NAT_ADDRESS while forwarding the reply packet"); + /* For reply packet use protocol + * specified in CIE of mandatory part + * for cache lookup + */ + if (sockunion_family( + &cie_protocol_mandatory) + != AF_UNSPEC) + proto = &cie_protocol_mandatory; + } + } + + if (proto) { + debugf(NHRP_DEBUG_COMMON, "Proto is %pSU", + proto); + c = nhrp_cache_get(nifp->ifp, proto, 0); + } + + if (c) { + debugf(NHRP_DEBUG_COMMON, + "c->cur.remote_nbma_natoa is %pSU", + &c->cur.remote_nbma_natoa); + if (sockunion_family(&c->cur.remote_nbma_natoa) + != AF_UNSPEC) { + cie = nhrp_cie_push( + zb, + NHRP_CODE_SUCCESS, + &c->cur.remote_nbma_natoa, + proto); + if (!cie) + goto err; + } + } else { + if (proto) + debugf(NHRP_DEBUG_COMMON, + "No cache entry for proto %pSU", + proto); + /* Copy existing NAT extension to new packet if + * either it was already not-empty, or we do not + * have valid cache information + */ + zbuf_put(zb, extpl.head, len); + } + break; default: if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY) /* FIXME: RFC says to just copy, but not - * append our selves to the transit NHS list */ + * append our selves to the transit NHS list + */ goto err; /* fallthru */ case NHRP_EXTENSION_RESPONDER_ADDRESS: /* Supported compulsory extensions, and any * non-compulsory that is not explicitly handled, - * should be just copied. */ + * should be just copied. + */ zbuf_copy(zb, &extpl, len); break; } @@ -870,10 +1078,12 @@ static void nhrp_peer_forward(struct nhrp_peer *p, nhrp_packet_complete(zb, hdr); nhrp_peer_send(p, zb); zbuf_free(zb); + zbuf_free(zb_copy); return; err: nhrp_packet_debug(pp->pkt, "FWD-FAIL"); zbuf_free(zb); + zbuf_free(zb_copy); } static void nhrp_packet_debug(struct zbuf *zb, const char *dir) diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 737772dbc7..7a4c57b5d4 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -18,7 +18,7 @@ #include "log.h" #include "zclient.h" -DEFINE_MTYPE_STATIC(NHRPD, NHRP_ROUTE, "NHRP routing entry") +DEFINE_MTYPE_STATIC(NHRPD, NHRP_ROUTE, "NHRP routing entry"); static struct zclient *zclient; static struct route_table *zebra_rib[AFI_MAX]; diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index ef3be82ca9..56861551ea 100644 --- a/nhrpd/nhrp_shortcut.c +++ b/nhrpd/nhrp_shortcut.c @@ -18,7 +18,7 @@ #include "log.h" #include "nhrp_protocol.h" -DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut") +DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut"); static struct route_table *shortcut_rib[AFI_MAX]; @@ -203,17 +203,18 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, void *arg) { struct nhrp_packet_parser *pp = arg; + struct interface *ifp = pp->ifp; + struct nhrp_interface *nifp = ifp->info; struct nhrp_shortcut *s = container_of(reqid, struct nhrp_shortcut, reqid); struct nhrp_shortcut *ps; struct nhrp_extension_header *ext; struct nhrp_cie_header *cie; struct nhrp_cache *c = NULL; - struct nhrp_cache *c_dst_proto = NULL; + struct nhrp_cache *c_dst = NULL; union sockunion *proto, cie_proto, *nbma, cie_nbma, nat_nbma; struct prefix prefix, route_prefix; struct zbuf extpl; - char buf[4][SU_ADDRSTRLEN]; int holding_time = pp->if_ad->holdtime; nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid); @@ -235,16 +236,6 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, return; } - /* Parse extensions */ - memset(&nat_nbma, 0, sizeof(nat_nbma)); - while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) { - switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { - case NHRP_EXTENSION_NAT_ADDRESS: - nhrp_cie_pull(&extpl, pp->hdr, &nat_nbma, &cie_proto); - break; - } - } - /* Minor sanity check */ prefix2sockunion(s->p, &cie_proto); if (!sockunion_same(&cie_proto, &pp->dst_proto)) { @@ -280,16 +271,58 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, prefix.prefixlen = route_prefix.prefixlen; } - debugf(NHRP_DEBUG_COMMON, - "Shortcut: %pFX is at proto %pSU dst_proto %pSU cie-nbma %pSU nat-nbma %pSU cie-holdtime %d", - &prefix, proto, &pp->dst_proto, &cie_nbma, &nat_nbma, - htons(cie->holding_time)); + /* Parse extensions */ + memset(&nat_nbma, 0, sizeof(nat_nbma)); + while ((ext = nhrp_ext_pull(&pp->extensions, &extpl)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_NAT_ADDRESS: { + struct nhrp_cie_header *cie_nat; + + do { + union sockunion cie_nat_proto, cie_nat_nbma; + + sockunion_family(&cie_nat_proto) = AF_UNSPEC; + sockunion_family(&cie_nat_nbma) = AF_UNSPEC; + cie_nat = nhrp_cie_pull(&extpl, pp->hdr, + &cie_nat_nbma, + &cie_nat_proto); + /* We are interested only in peer CIE */ + if (cie_nat + && sockunion_same(&cie_nat_proto, proto)) { + nat_nbma = cie_nat_nbma; + } + } while (cie_nat); + } break; + default: + break; + } + } /* Update cache entry for the protocol to nbma binding */ - if (sockunion_family(&nat_nbma) != AF_UNSPEC) + if (sockunion_family(&nat_nbma) != AF_UNSPEC) { + debugf(NHRP_DEBUG_COMMON, + "Shortcut: NAT detected (NAT extension) proto %pSU NBMA %pSU claimed-NBMA %pSU", + proto, &nat_nbma, &cie_nbma); nbma = &nat_nbma; - else + } + /* For NHRP resolution reply the cie_nbma in mandatory part is the + * address of the actual address of the sender + */ + else if (!sockunion_same(&cie_nbma, &pp->peer->vc->remote.nbma) + && !nhrp_nhs_match_ip(&pp->peer->vc->remote.nbma, nifp)) { + debugf(NHRP_DEBUG_COMMON, + "Shortcut: NAT detected (no NAT Extension) proto %pSU NBMA %pSU claimed-NBMA %pSU", + proto, &pp->peer->vc->remote.nbma, &cie_nbma); + nbma = &pp->peer->vc->remote.nbma; + nat_nbma = *nbma; + } else { nbma = &cie_nbma; + } + + debugf(NHRP_DEBUG_COMMON, + "Shortcut: %pFX is at proto %pSU dst_proto %pSU NBMA %pSU cie-holdtime %d", + &prefix, proto, &pp->dst_proto, nbma, + htons(cie->holding_time)); if (sockunion_family(nbma)) { c = nhrp_cache_get(pp->ifp, proto, 1); @@ -299,25 +332,31 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid, nhrp_cache_update_binding(c, NHRP_CACHE_DYNAMIC, holding_time, nhrp_peer_get(pp->ifp, nbma), - htons(cie->mtu), nbma); + htons(cie->mtu), + nbma, + &cie_nbma); } else { debugf(NHRP_DEBUG_COMMON, - "Shortcut: no cache for nbma %s", buf[2]); + "Shortcut: no cache for proto %pSU", proto); } /* Update cache binding for dst_proto as well */ - if (proto != &pp->dst_proto) { - c_dst_proto = nhrp_cache_get(pp->ifp, &pp->dst_proto, 1); - if (c_dst_proto) { + if (sockunion_cmp(proto, &pp->dst_proto)) { + c_dst = nhrp_cache_get(pp->ifp, &pp->dst_proto, 1); + if (c_dst) { debugf(NHRP_DEBUG_COMMON, - "Shortcut: cache found, update binding"); - nhrp_cache_update_binding(c_dst_proto, NHRP_CACHE_DYNAMIC, + "Shortcut: cache found, update binding"); + nhrp_cache_update_binding(c_dst, + NHRP_CACHE_DYNAMIC, holding_time, nhrp_peer_get(pp->ifp, nbma), - htons(cie->mtu), nbma); + htons(cie->mtu), + nbma, + &cie_nbma); } else { debugf(NHRP_DEBUG_COMMON, - "Shortcut: no cache for nbma %s", buf[2]); + "Shortcut: no cache for proto %pSU", + &pp->dst_proto); } } } @@ -356,6 +395,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) struct nhrp_afi_data *if_ad; struct nhrp_peer *peer; struct nhrp_cie_header *cie; + struct nhrp_extension_header *ext; if (nhrp_route_address(NULL, &s->addr, NULL, &peer) != NHRP_ROUTE_NBMA_NEXTHOP) @@ -399,7 +439,14 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) /* Cisco NAT detection extension */ hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT); - nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); + ext = nhrp_ext_push(zb, hdr, NHRP_EXTENSION_NAT_ADDRESS); + if (sockunion_family(&nifp->nat_nbma) != AF_UNSPEC) { + cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, &nifp->nat_nbma, + &if_ad->addr); + cie->prefix_length = 8 * sockunion_get_addrlen(&if_ad->addr); + cie->mtu = htons(if_ad->mtu); + nhrp_ext_complete(zb, ext); + } nhrp_packet_complete(zb, hdr); diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c index d538163e90..b3b657f3fa 100644 --- a/nhrpd/nhrp_vc.c +++ b/nhrpd/nhrp_vc.c @@ -17,7 +17,7 @@ #include "nhrpd.h" #include "os.h" -DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection") +DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection"); struct child_sa { uint32_t id; diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 1ea4c5e64f..4358605e2b 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -525,11 +525,11 @@ DEFUN(if_nhrp_map, if_nhrp_map_cmd, c->map = 1; if (type == NHRP_CACHE_LOCAL) nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0, - NULL); + NULL, NULL); else nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0, nhrp_peer_get(ifp, &nbma_addr), 0, - NULL); + NULL, NULL); return CMD_SUCCESS; } @@ -565,7 +565,8 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd, return CMD_SUCCESS; nhrp_cache_update_binding(c, c->cur.type, -1, - nhrp_peer_get(ifp, &nbma_addr), 0, NULL); + nhrp_peer_get(ifp, &nbma_addr), 0, NULL, + NULL); return CMD_SUCCESS; } @@ -629,7 +630,7 @@ static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx) { struct info_ctx *ctx = pctx; struct vty *vty = ctx->vty; - char buf[2][SU_ADDRSTRLEN]; + char buf[3][SU_ADDRSTRLEN]; struct json_object *json = NULL; if (ctx->afi != family2afi(sockunion_family(&c->remote_addr))) @@ -637,17 +638,42 @@ static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx) if (!ctx->count && !ctx->json) { - vty_out(vty, "%-8s %-8s %-24s %-24s %-6s %s\n", "Iface", "Type", - "Protocol", "NBMA", "Flags", "Identity"); + vty_out(vty, "%-8s %-8s %-24s %-24s %-24s %-6s %s\n", "Iface", + "Type", "Protocol", "NBMA", "Claimed NBMA", "Flags", + "Identity"); } ctx->count++; sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])); - if (c->cur.peer) - sockunion2str(&c->cur.peer->vc->remote.nbma, - buf[1], sizeof(buf[1])); - else - snprintf(buf[1], sizeof(buf[1]), "-"); + if (c->cur.type == NHRP_CACHE_LOCAL) { + struct nhrp_interface *nifp = c->ifp->info; + + if (sockunion_family(&nifp->nbma) != AF_UNSPEC) { + sockunion2str(&nifp->nbma, buf[1], sizeof(buf[1])); + sockunion2str(&nifp->nbma, buf[2], sizeof(buf[2])); + } else { + snprintf(buf[1], sizeof(buf[1]), "-"); + snprintf(buf[2], sizeof(buf[2]), "-"); + } + + /* if we are behind NAT then update NBMA field */ + if (sockunion_family(&nifp->nat_nbma) != AF_UNSPEC) + sockunion2str(&nifp->nat_nbma, buf[1], sizeof(buf[1])); + } else { + if (c->cur.peer) + sockunion2str(&c->cur.peer->vc->remote.nbma, + buf[1], sizeof(buf[1])); + else + snprintf(buf[1], sizeof(buf[1]), "-"); + + if (c->cur.peer + && sockunion_family(&c->cur.remote_nbma_claimed) + != AF_UNSPEC) + sockunion2str(&c->cur.remote_nbma_claimed, + buf[2], sizeof(buf[2])); + else + snprintf(buf[2], sizeof(buf[2]), "-"); + } if (ctx->json) { json = json_object_new_object(); @@ -656,6 +682,7 @@ static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx) nhrp_cache_type_str[c->cur.type]); json_object_string_add(json, "protocol", buf[0]); json_object_string_add(json, "nbma", buf[1]); + json_object_string_add(json, "claimed_nbma", buf[2]); if (c->used) json_object_boolean_true_add(json, "used"); @@ -681,9 +708,10 @@ static void show_ip_nhrp_cache(struct nhrp_cache *c, void *pctx) json_object_array_add(ctx->json, json); return; } - vty_out(ctx->vty, "%-8s %-8s %-24s %-24s %c%c%c %s\n", c->ifp->name, + vty_out(ctx->vty, "%-8s %-8s %-24s %-24s %-24s %c%c%c %s\n", + c->ifp->name, nhrp_cache_type_str[c->cur.type], - buf[0], buf[1], + buf[0], buf[1], buf[2], c->used ? 'U' : ' ', c->t_timeout ? 'T' : ' ', c->t_auth ? 'A' : ' ', c->cur.peer ? c->cur.peer->vc->remote.id : "-"); @@ -970,7 +998,8 @@ static void clear_nhrp_cache(struct nhrp_cache *c, void *data) { struct info_ctx *ctx = data; if (c->cur.type <= NHRP_CACHE_DYNAMIC) { - nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); + nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL, + NULL); ctx->count++; } } diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 3655463152..e4afb22f80 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -18,7 +18,7 @@ #include "memory.h" #include "resolver.h" -DECLARE_MGROUP(NHRPD) +DECLARE_MGROUP(NHRPD); #define NHRPD_DEFAULT_HOLDTIME 7200 @@ -156,6 +156,7 @@ struct nhrp_peer { struct nhrp_vc *vc; struct thread *t_fallback; struct notifier_block vc_notifier, ifp_notifier; + struct thread *t_timer; }; struct nhrp_packet_parser { @@ -225,9 +226,11 @@ struct nhrp_cache { struct { enum nhrp_cache_type type; union sockunion remote_nbma_natoa; + union sockunion remote_nbma_claimed; struct nhrp_peer *peer; time_t expires; uint32_t mtu; + int holding_time; } cur, new; }; @@ -383,7 +386,8 @@ void nhrp_cache_config_foreach(struct interface *ifp, void nhrp_cache_set_used(struct nhrp_cache *, int); int nhrp_cache_update_binding(struct nhrp_cache *, enum nhrp_cache_type type, int holding_time, struct nhrp_peer *p, - uint32_t mtu, union sockunion *nbma_natoa); + uint32_t mtu, union sockunion *nbma_natoa, + union sockunion *claimed_nbma); void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *, notifier_fn_t); void nhrp_cache_notify_del(struct nhrp_cache *c, struct notifier_block *); @@ -465,4 +469,6 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb); void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb); void nhrp_peer_send_indication(struct interface *ifp, uint16_t, struct zbuf *); +int nhrp_nhs_match_ip(union sockunion *in_ip, struct nhrp_interface *nifp); + #endif diff --git a/nhrpd/zbuf.c b/nhrpd/zbuf.c index 7f1475cc69..a23526af48 100644 --- a/nhrpd/zbuf.c +++ b/nhrpd/zbuf.c @@ -21,7 +21,7 @@ #define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR)) -DEFINE_MTYPE_STATIC(NHRPD, ZBUF_DATA, "NHRPD zbuf data") +DEFINE_MTYPE_STATIC(NHRPD, ZBUF_DATA, "NHRPD zbuf data"); struct zbuf *zbuf_alloc(size_t size) { @@ -230,3 +230,15 @@ void zbuf_copy(struct zbuf *zdst, struct zbuf *zsrc, size_t len) return; memcpy(dst, src, len); } + +void zbuf_copy_peek(struct zbuf *zdst, struct zbuf *zsrc, size_t len) +{ + const void *src; + void *dst; + + dst = zbuf_pushn(zdst, len); + src = zbuf_pulln(zsrc, 0); + if (!dst || !src) + return; + memcpy(dst, src, len); +} diff --git a/nhrpd/zbuf.h b/nhrpd/zbuf.h index e6f7101d63..d4a7c15a95 100644 --- a/nhrpd/zbuf.h +++ b/nhrpd/zbuf.h @@ -190,6 +190,7 @@ static inline void zbuf_put_be32(struct zbuf *zb, uint32_t val) } void zbuf_copy(struct zbuf *zb, struct zbuf *src, size_t len); +void zbuf_copy_peek(struct zbuf *zdst, struct zbuf *zsrc, size_t len); void zbufq_init(struct zbuf_queue *); void zbufq_reset(struct zbuf_queue *); diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index f6a246500b..27d4f0755e 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -46,6 +46,7 @@ #include "ospf6_flood.h" #include "ospf6_intra.h" +#include "ospf6_asbr.h" #include "ospf6_abr.h" #include "ospf6d.h" @@ -646,10 +647,24 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o) struct listnode *node, *nnode; struct ospf6_area *oa; struct ospf6_route *def, *route; + struct ospf6_redist *red; + int type = DEFAULT_ROUTE; + struct prefix_ipv6 p = {}; if (!o->backbone) return; + red = ospf6_redist_lookup(o, type, 0); + if (!red) + return; + + p.family = AF_INET6; + p.prefixlen = 0; + + route = ospf6_route_lookup((struct prefix *)&p, o->external_table); + if (!route) + return; + def = ospf6_route_create(); def->type = OSPF6_DEST_TYPE_NETWORK; def->prefix.family = AF_INET6; @@ -659,6 +674,8 @@ void ospf6_abr_defaults_to_stub(struct ospf6 *o) def->path.type = OSPF6_PATH_TYPE_INTER; def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT; def->path.area_id = o->backbone->area_id; + def->path.metric_type = metric_type(o, type, 0); + def->path.cost = metric_value(o, type, 0); for (ALL_LIST_ELEMENTS(o->area_list, node, nnode, oa)) { if (!IS_AREA_STUB(oa)) { @@ -1209,7 +1226,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) */ if (old_entry_updated == false) { if ((old == NULL) || (old->type != route->type) - || (old->path.type != route->path.type)) + || (old->path.type != route->path.type) + || (old->path.cost != route->path.cost)) add_route = true; } diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index cf33069c9f..6bf61b4804 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -46,7 +46,8 @@ #include "ospf6d.h" #include "lib/json.h" -DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name") +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name"); int ospf6_area_cmp(void *va, void *vb) { diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 977d810be5..ffd6dc22c3 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -30,6 +30,7 @@ #include "plist.h" #include "thread.h" #include "linklist.h" +#include "lib/northbound_cli.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" @@ -37,6 +38,7 @@ #include "ospf6_route.h" #include "ospf6_zebra.h" #include "ospf6_message.h" +#include "ospf6_spf.h" #include "ospf6_top.h" #include "ospf6_area.h" @@ -49,10 +51,18 @@ #include "ospf6d.h" #include "lib/json.h" +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments"); + static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id); static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6, struct ospf6_redist *red, int type); +#ifndef VTYSH_EXTRACT_PL +#include "ospf6d/ospf6_asbr_clippy.c" +#endif + unsigned char conf_debug_ospf6_asbr = 0; #define ZROUTE_NAME(x) zebra_route_string(x) @@ -1043,6 +1053,7 @@ static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type, ROUTEMAP(red) = NULL; listnode_add(ospf6->redist[type], red); + ospf6->redistribute++; return red; } @@ -1056,6 +1067,7 @@ static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red, list_delete(&ospf6->redist[type]); } XFREE(MTYPE_OSPF6_REDISTRIBUTE, red); + ospf6->redistribute--; } } @@ -1092,8 +1104,10 @@ void ospf6_asbr_send_externals_to_area(struct ospf6_area *oa) for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) { if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) { - zlog_debug("%s: Flooding AS-External LSA %s", - __func__, lsa->name); + if (IS_OSPF6_DEBUG_ASBR) + zlog_debug("%s: Flooding AS-External LSA %s", + __func__, lsa->name); + ospf6_flood_area(NULL, lsa, oa); } } @@ -1116,6 +1130,7 @@ void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa) /* if router is only in a stub area then purge AS-External LSAs */ iterend = ospf6_lsdb_head(ospf6->lsdb, 0, 0, 0, &lsa); while (lsa != NULL) { + assert(lsa->lock > 1); lsanext = ospf6_lsdb_next(iterend, lsa); if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) ospf6_lsdb_remove(lsa, ospf6->lsdb); @@ -1123,6 +1138,35 @@ void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa) } } +/* Update ASBR status. */ +static void ospf6_asbr_status_update(struct ospf6 *ospf6, uint8_t status) +{ + struct listnode *lnode, *lnnode; + struct ospf6_area *oa; + + zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status); + + if (status) { + if (IS_OSPF6_ASBR(ospf6)) { + zlog_info("ASBR[%s:Status:%d]: Already ASBR", + ospf6->name, status); + return; + } + SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR); + } else { + if (!IS_OSPF6_ASBR(ospf6)) { + zlog_info("ASBR[%s:Status:%d]: Already non ASBR", + ospf6->name, status); + return; + } + UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR); + } + + ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE); + for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa)) + OSPF6_ROUTER_LSA_SCHEDULE(oa); +} + void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct prefix *prefix, unsigned int nexthop_num, @@ -1137,8 +1181,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct prefix prefix_id; struct route_node *node; char ibuf[16]; - struct listnode *lnode, *lnnode; - struct ospf6_area *oa; struct ospf6_redist *red; red = ospf6_redist_lookup(ospf6, type, 0); @@ -1146,7 +1188,8 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, if (!red) return; - if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id)) + if ((type != DEFAULT_ROUTE) + && !ospf6_zebra_is_redistribute(type, ospf6->vrf_id)) return; memset(&troute, 0, sizeof(troute)); @@ -1199,7 +1242,11 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, sizeof(struct in6_addr)); info->tag = tinfo.tag; } else { - /* If there is no route-map, simply update the tag */ + /* If there is no route-map, simply update the tag and + * metric fields + */ + match->path.metric_type = metric_type(ospf6, type, 0); + match->path.cost = metric_value(ospf6, type, 0); info->tag = tag; } @@ -1227,6 +1274,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, match->path.origin.id = htonl(info->id); ospf6_as_external_lsa_originate(match, ospf6); + ospf6_asbr_status_update(ospf6, ospf6->redistribute); return; } @@ -1251,7 +1299,11 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, sizeof(struct in6_addr)); info->tag = tinfo.tag; } else { - /* If there is no route-map, simply set the tag */ + /* If there is no route-map, simply update the tag and metric + * fields + */ + route->path.metric_type = metric_type(ospf6, type, 0); + route->path.cost = metric_value(ospf6, type, 0); info->tag = tag; } @@ -1280,10 +1332,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, route->path.origin.id = htonl(info->id); ospf6_as_external_lsa_originate(route, ospf6); - - /* Router-Bit (ASBR Flag) may have to be updated */ - for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa)) - OSPF6_ROUTER_LSA_SCHEDULE(oa); + ospf6_asbr_status_update(ospf6, ospf6->redistribute); } void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, @@ -1295,8 +1344,6 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, struct ospf6_lsa *lsa; struct prefix prefix_id; char ibuf[16]; - struct listnode *lnode, *lnnode; - struct ospf6_area *oa; match = ospf6_route_lookup(prefix, ospf6->external_table); if (match == NULL) { @@ -1337,9 +1384,7 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex, ospf6_route_remove(match, ospf6->external_table); XFREE(MTYPE_OSPF6_EXTERNAL_INFO, info); - /* Router-Bit (ASBR Flag) may have to be updated */ - for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa)) - OSPF6_ROUTER_LSA_SCHEDULE(oa); + ospf6_asbr_status_update(ospf6, ospf6->redistribute); } DEFUN (ospf6_redistribute, @@ -1529,6 +1574,140 @@ static void ospf6_redistribute_show_config(struct vty *vty, struct ospf6 *ospf6, vty_out(vty, "Total %d routes\n", total); } +static void ospf6_redistribute_default_set(struct ospf6 *ospf6, int originate) +{ + struct prefix_ipv6 p = {}; + struct in6_addr nexthop = {}; + int cur_originate = ospf6->default_originate; + + p.family = AF_INET6; + p.prefixlen = 0; + + ospf6->default_originate = originate; + + switch (cur_originate) { + case DEFAULT_ORIGINATE_NONE: + break; + case DEFAULT_ORIGINATE_ZEBRA: + zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, + zclient, AFI_IP6, ospf6->vrf_id); + ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0, + (struct prefix *)&p, ospf6); + + break; + case DEFAULT_ORIGINATE_ALWAYS: + ospf6_asbr_redistribute_remove(DEFAULT_ROUTE, 0, + (struct prefix *)&p, ospf6); + break; + } + + switch (originate) { + case DEFAULT_ORIGINATE_NONE: + break; + case DEFAULT_ORIGINATE_ZEBRA: + zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD, + zclient, AFI_IP6, ospf6->vrf_id); + + break; + case DEFAULT_ORIGINATE_ALWAYS: + ospf6_asbr_redistribute_add(DEFAULT_ROUTE, 0, + (struct prefix *)&p, 0, &nexthop, 0, + ospf6); + break; + } +} + +/* Default Route originate. */ +DEFPY (ospf6_default_route_originate, + ospf6_default_route_originate_cmd, + "default-information originate [{always$always|metric (0-16777214)$mval|metric-type (1-2)$mtype|route-map WORD$rtmap}]", + "Control distribution of default route\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPFv3 default metric\n" + "OSPFv3 metric\n" + "OSPFv3 metric type for default routes\n" + "Set OSPFv3 External Type 1/2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + int default_originate = DEFAULT_ORIGINATE_ZEBRA; + struct ospf6_redist *red; + bool sameRtmap = false; + + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + int cur_originate = ospf6->default_originate; + + OSPF6_CMD_CHECK_RUNNING(ospf6); + + red = ospf6_redist_add(ospf6, DEFAULT_ROUTE, 0); + + if (always != NULL) + default_originate = DEFAULT_ORIGINATE_ALWAYS; + + if (mval_str == NULL) + mval = -1; + + if (mtype_str == NULL) + mtype = -1; + + /* To check ,if user is providing same route map */ + if ((rtmap == ROUTEMAP_NAME(red)) + || (rtmap && ROUTEMAP_NAME(red) + && (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0))) + sameRtmap = true; + + /* Don't allow if the same lsa is aleardy originated. */ + if ((sameRtmap) && (red->dmetric.type == mtype) + && (red->dmetric.value == mval) + && (cur_originate == default_originate)) + return CMD_SUCCESS; + + /* Updating Metric details */ + red->dmetric.type = mtype; + red->dmetric.value = mval; + + /* updating route map details */ + if (rtmap) + ospf6_asbr_routemap_set(red, rtmap); + else + ospf6_asbr_routemap_unset(red); + + ospf6_redistribute_default_set(ospf6, default_originate); + return CMD_SUCCESS; +} + +DEFPY (no_ospf6_default_information_originate, + no_ospf6_default_information_originate_cmd, + "no default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}]", + NO_STR + "Control distribution of default information\n" + "Distribute a default route\n" + "Always advertise default route\n" + "OSPFv3 default metric\n" + "OSPFv3 metric\n" + "OSPFv3 metric type for default routes\n" + "Set OSPFv3 External Type 1/2 metrics\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + struct ospf6_redist *red; + + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + OSPF6_CMD_CHECK_RUNNING(ospf6); + + red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0); + if (!red) + return CMD_SUCCESS; + + ospf6_asbr_routemap_unset(red); + ospf6_redist_del(ospf6, red, DEFAULT_ROUTE); + + ospf6_redistribute_default_set(ospf6, DEFAULT_ORIGINATE_NONE); + return CMD_SUCCESS; +} /* Routemap Functions */ static enum route_map_cmd_result_t @@ -1746,99 +1925,83 @@ ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p, void *object) return RMAP_OKAY; } -static const struct route_map_rule_cmd - ospf6_routemap_rule_set_tag_cmd = { +static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = { "tag", ospf6_routemap_rule_set_tag, route_map_rule_tag_compile, route_map_rule_tag_free, }; -static int route_map_command_status(struct vty *vty, enum rmap_compile_rets ret) -{ - switch (ret) { - case RMAP_RULE_MISSING: - vty_out(vty, "OSPF6 Can't find rule.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_ERROR: - vty_out(vty, "OSPF6 Argument is malformed.\n"); - return CMD_WARNING_CONFIG_FAILED; - case RMAP_COMPILE_SUCCESS: - break; - } - - return CMD_SUCCESS; -} - /* add "set metric-type" */ -DEFUN (ospf6_routemap_set_metric_type, - ospf6_routemap_set_metric_type_cmd, - "set metric-type <type-1|type-2>", - "Set value\n" - "Type of metric\n" - "OSPF6 external type 1 metric\n" - "OSPF6 external type 2 metric\n") +DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd, + "set metric-type <type-1|type-2>", + "Set value\n" + "Type of metric\n" + "OSPF6 external type 1 metric\n" + "OSPF6 external type 2 metric\n") { - VTY_DECLVAR_CONTEXT(route_map_index, route_map_index); - int idx_external = 2; - enum rmap_compile_rets ret = route_map_add_set(route_map_index, - "metric-type", - argv[idx_external]->arg); + char *ext = argv[2]->text; + + const char *xpath = + "./set-action[action='frr-ospf-route-map:metric-type']"; + char xpath_value[XPATH_MAXLEN]; - return route_map_command_status(vty, ret); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext); + return nb_cli_apply_changes(vty, NULL); } /* delete "set metric-type" */ -DEFUN (ospf6_routemap_no_set_metric_type, - ospf6_routemap_no_set_metric_type_cmd, - "no set metric-type [<type-1|type-2>]", - NO_STR - "Set value\n" - "Type of metric\n" - "OSPF6 external type 1 metric\n" - "OSPF6 external type 2 metric\n") +DEFUN_YANG (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd, + "no set metric-type [<type-1|type-2>]", + NO_STR + "Set value\n" + "Type of metric\n" + "OSPF6 external type 1 metric\n" + "OSPF6 external type 2 metric\n") { - VTY_DECLVAR_CONTEXT(route_map_index, route_map_index); - char *ext = (argc == 4) ? argv[3]->text : NULL; - enum rmap_compile_rets ret = route_map_delete_set(route_map_index, - "metric-type", ext); + const char *xpath = + "./set-action[action='frr-ospf-route-map:metric-type']"; - return route_map_command_status(vty, ret); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } /* add "set forwarding-address" */ -DEFUN (ospf6_routemap_set_forwarding, - ospf6_routemap_set_forwarding_cmd, - "set forwarding-address X:X::X:X", - "Set value\n" - "Forwarding Address\n" - "IPv6 Address\n") -{ - VTY_DECLVAR_CONTEXT(route_map_index, route_map_index); +DEFUN_YANG (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd, + "set forwarding-address X:X::X:X", + "Set value\n" + "Forwarding Address\n" + "IPv6 Address\n") +{ int idx_ipv6 = 2; - enum rmap_compile_rets ret = route_map_add_set(route_map_index, - "forwarding-address", - argv[idx_ipv6]->arg); - - return route_map_command_status(vty, ret); + const char *xpath = + "./set-action[action='frr-ospf6-route-map:forwarding-address']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-ospf6-route-map:ipv6-address", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[idx_ipv6]->arg); + return nb_cli_apply_changes(vty, NULL); } /* delete "set forwarding-address" */ -DEFUN (ospf6_routemap_no_set_forwarding, - ospf6_routemap_no_set_forwarding_cmd, - "no set forwarding-address X:X::X:X", - NO_STR - "Set value\n" - "Forwarding Address\n" - "IPv6 Address\n") +DEFUN_YANG (ospf6_routemap_no_set_forwarding, ospf6_routemap_no_set_forwarding_cmd, + "no set forwarding-address [X:X::X:X]", + NO_STR + "Set value\n" + "Forwarding Address\n" + "IPv6 Address\n") { - VTY_DECLVAR_CONTEXT(route_map_index, route_map_index); - int idx_ipv6 = 3; - enum rmap_compile_rets ret = route_map_delete_set(route_map_index, - "forwarding-address", - argv[idx_ipv6]->arg); + const char *xpath = + "./set-action[action='frr-ospf6-route-map:forwarding-address']"; - return route_map_command_status(vty, ret); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } static void ospf6_routemap_init(void) @@ -2111,6 +2274,9 @@ void ospf6_asbr_init(void) install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd); + install_element(OSPF6_NODE, &ospf6_default_route_originate_cmd); + install_element(OSPF6_NODE, + &no_ospf6_default_information_originate_cmd); install_element(OSPF6_NODE, &ospf6_redistribute_cmd); install_element(OSPF6_NODE, &ospf6_redistribute_routemap_cmd); install_element(OSPF6_NODE, &no_ospf6_redistribute_cmd); @@ -2172,6 +2338,39 @@ int config_write_ospf6_debug_asbr(struct vty *vty) return 0; } +int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *ospf6) +{ + struct ospf6_redist *red; + + if (ospf6) { + /* default-route print. */ + if (ospf6->default_originate != DEFAULT_ORIGINATE_NONE) { + vty_out(vty, " default-information originate"); + if (ospf6->default_originate + == DEFAULT_ORIGINATE_ALWAYS) + vty_out(vty, " always"); + + red = ospf6_redist_lookup(ospf6, DEFAULT_ROUTE, 0); + if (red) { + if (red->dmetric.value >= 0) + vty_out(vty, " metric %d", + red->dmetric.value); + + if (red->dmetric.type >= 0) + vty_out(vty, " metric-type %d", + red->dmetric.type); + + if (ROUTEMAP_NAME(red)) + vty_out(vty, " route-map %s", + ROUTEMAP_NAME(red)); + } + + vty_out(vty, "\n"); + } + } + return 0; +} + void install_element_ospf6_debug_asbr(void) { install_element(ENABLE_NODE, &debug_ospf6_asbr_cmd); diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h index e4a4455a5c..4774ac435a 100644 --- a/ospf6d/ospf6_asbr.h +++ b/ospf6d/ospf6_asbr.h @@ -98,6 +98,7 @@ extern void ospf6_asbr_send_externals_to_area(struct ospf6_area *); extern void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa); extern int config_write_ospf6_debug_asbr(struct vty *vty); +extern int ospf6_distribute_config_write(struct vty *vty, struct ospf6 *ospf6); extern void install_element_ospf6_debug_asbr(void); extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old, struct ospf6_route *route, diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 2d896546fa..5f4815fec1 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -463,6 +463,19 @@ static void ospf6_flood_process(struct ospf6_neighbor *from, struct ospf6_area *oa; for (ALL_LIST_ELEMENTS(process->area_list, node, nnode, oa)) { + + /* If unknown LSA and U-bit clear, treat as link local + * flooding scope + */ + if (!OSPF6_LSA_IS_KNOWN(lsa->header->type) + && !(ntohs(lsa->header->type) & OSPF6_LSTYPE_UBIT_MASK) + && (oa != OSPF6_INTERFACE(lsa->lsdb->data)->area)) { + + if (IS_OSPF6_DEBUG_FLOODING) + zlog_debug("Unknown LSA, do not flood"); + continue; + } + if (OSPF6_LSA_SCOPE(lsa->header->type) == OSPF6_SCOPE_AREA && oa != OSPF6_AREA(lsa->lsdb->data)) continue; diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index a5d9138743..158b8dc483 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -45,11 +45,12 @@ #include "ospf6_zebra.h" #include "lib/json.h" -DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names") -DEFINE_QOBJ_TYPE(ospf6_interface) +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF, "OSPF6 interface"); +DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names"); +DEFINE_QOBJ_TYPE(ospf6_interface); DEFINE_HOOK(ospf6_interface_change, (struct ospf6_interface * oi, int state, int old_state), - (oi, state, old_state)) + (oi, state, old_state)); unsigned char conf_debug_ospf6_interface = 0; @@ -1449,6 +1450,12 @@ DEFUN (show_ipv6_ospf6_interface_ifname_prefix, return CMD_WARNING; } + if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { + vty_out(vty, "Interface %s not attached to area\n", + argv[idx_ifname]->arg); + return CMD_WARNING; + } + ospf6_route_table_show(vty, idx_prefix, argc, argv, oi->route_connected, uj); @@ -1482,7 +1489,7 @@ DEFUN (show_ipv6_ospf6_interface_prefix, FOR_ALL_INTERFACES (vrf, ifp) { oi = (struct ospf6_interface *)ifp->info; - if (oi == NULL) + if (oi == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) continue; ospf6_route_table_show(vty, idx_prefix, argc, argv, diff --git a/ospf6d/ospf6_interface.h b/ospf6d/ospf6_interface.h index 6e4692920c..2a5a9ba4a2 100644 --- a/ospf6d/ospf6_interface.h +++ b/ospf6d/ospf6_interface.h @@ -134,9 +134,9 @@ struct ospf6_interface { uint32_t ls_ack_out; uint32_t discarded; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(ospf6_interface) +DECLARE_QOBJ_TYPE(ospf6_interface); /* interface state */ #define OSPF6_INTERFACE_NONE 0 @@ -199,6 +199,6 @@ extern void install_element_ospf6_debug_interface(void); DECLARE_HOOK(ospf6_interface_change, (struct ospf6_interface * oi, int state, int old_state), - (oi, state, old_state)) + (oi, state, old_state)); #endif /* OSPF6_INTERFACE_H */ diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index e1c3b4038c..f5f429b041 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -34,6 +34,8 @@ #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" +#include "ospf6_asbr.h" +#include "ospf6_zebra.h" #include "ospf6_top.h" #include "ospf6_area.h" @@ -43,6 +45,10 @@ #include "ospf6_flood.h" #include "ospf6d.h" +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary"); + vector ospf6_lsa_handler_vector; struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa) @@ -159,6 +165,34 @@ uint8_t ospf6_lstype_debug(uint16_t type) return handler->lh_debug; } +int metric_type(struct ospf6 *ospf6, int type, uint8_t instance) +{ + struct ospf6_redist *red; + + red = ospf6_redist_lookup(ospf6, type, instance); + + return ((!red || red->dmetric.type < 0) ? DEFAULT_METRIC_TYPE + : red->dmetric.type); +} + +int metric_value(struct ospf6 *ospf6, int type, uint8_t instance) +{ + struct ospf6_redist *red; + + red = ospf6_redist_lookup(ospf6, type, instance); + if (!red || red->dmetric.value < 0) { + if (type == DEFAULT_ROUTE) { + if (ospf6->default_originate == DEFAULT_ORIGINATE_ZEBRA) + return DEFAULT_DEFAULT_ORIGINATE_METRIC; + else + return DEFAULT_DEFAULT_ALWAYS_METRIC; + } else + return DEFAULT_DEFAULT_METRIC; + } + + return red->dmetric.value; +} + /* RFC2328: Section 13.2 */ int ospf6_lsa_is_differ(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) { @@ -657,27 +691,29 @@ void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, vty_out(vty, "\n"); } +struct ospf6_lsa *ospf6_lsa_alloc(size_t lsa_length) +{ + struct ospf6_lsa *lsa; + + lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa)); + lsa->header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_length); + + return lsa; +} + /* OSPFv3 LSA creation/deletion function */ struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header) { struct ospf6_lsa *lsa = NULL; - struct ospf6_lsa_header *new_header = NULL; uint16_t lsa_size = 0; /* size of the entire LSA */ lsa_size = ntohs(header->length); /* XXX vulnerable */ - /* allocate memory for this LSA */ - new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_size); + lsa = ospf6_lsa_alloc(lsa_size); /* copy LSA from original header */ - memcpy(new_header, header, lsa_size); - - /* LSA information structure */ - /* allocate memory */ - lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa)); - - lsa->header = new_header; + memcpy(lsa->header, header, lsa_size); /* dump string */ ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name)); @@ -691,20 +727,11 @@ struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header) struct ospf6_lsa *ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header) { struct ospf6_lsa *lsa = NULL; - struct ospf6_lsa_header *new_header = NULL; - /* allocate memory for this LSA */ - new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, - sizeof(struct ospf6_lsa_header)); + lsa = ospf6_lsa_alloc(sizeof(struct ospf6_lsa_header)); - /* copy LSA from original header */ - memcpy(new_header, header, sizeof(struct ospf6_lsa_header)); + memcpy(lsa->header, header, sizeof(struct ospf6_lsa_header)); - /* LSA information structure */ - /* allocate memory */ - lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa)); - - lsa->header = new_header; SET_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY); /* dump string */ @@ -856,11 +883,12 @@ int ospf6_lsa_refresh(struct thread *thread) void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6) { - struct listnode *node; + struct listnode *node, *nnode; struct ospf6_area *oa; struct ospf6_lsa *lsa; const struct route_node *end = NULL; uint32_t type, adv_router; + struct ospf6_interface *oi; ospf6->inst_shutdown = 1; @@ -875,6 +903,19 @@ void ospf6_flush_self_originated_lsas_now(struct ospf6 *ospf6) lsa = ospf6_lsdb_next(end, lsa); } + + for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) { + end = ospf6_lsdb_head(oi->lsdb_self, 0, 0, + ospf6->router_id, &lsa); + while (lsa) { + /* RFC 2328 (14.1): Set MAXAGE */ + lsa->header->age = htons(OSPF_LSA_MAXAGE); + /* Flood MAXAGE LSA*/ + ospf6_flood(NULL, lsa); + + lsa = ospf6_lsdb_next(end, lsa); + } + } } type = htons(OSPF6_LSTYPE_AS_EXTERNAL); diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 7fa9c5fe40..84c3b85631 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -29,6 +29,12 @@ #define OSPF6_LSA_DEBUG_EXAMIN 0x04 #define OSPF6_LSA_DEBUG_FLOOD 0x08 +/* OSPF LSA Default metric values */ +#define DEFAULT_DEFAULT_METRIC 20 +#define DEFAULT_DEFAULT_ORIGINATE_METRIC 10 +#define DEFAULT_DEFAULT_ALWAYS_METRIC 1 +#define DEFAULT_METRIC_TYPE 2 + #define IS_OSPF6_DEBUG_LSA(name) \ (ospf6_lstype_debug(htons(OSPF6_LSTYPE_##name)) & OSPF6_LSA_DEBUG) #define IS_OSPF6_DEBUG_ORIGINATE(name) \ @@ -197,6 +203,8 @@ extern vector ospf6_lsa_handler_vector; extern const char *ospf6_lstype_name(uint16_t type); extern const char *ospf6_lstype_short_name(uint16_t type); extern uint8_t ospf6_lstype_debug(uint16_t type); +extern int metric_type(struct ospf6 *ospf6, int type, uint8_t instance); +extern int metric_value(struct ospf6 *ospf6, int type, uint8_t instance); extern int ospf6_lsa_is_differ(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); extern int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); extern uint16_t ospf6_lsa_age_current(struct ospf6_lsa *); @@ -217,6 +225,7 @@ extern void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa, extern void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, json_object *json, bool use_json); +extern struct ospf6_lsa *ospf6_lsa_alloc(size_t lsa_length); extern struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header); extern struct ospf6_lsa * ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header); diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c index 9636e1a230..18f121e3a2 100644 --- a/ospf6d/ospf6_lsdb.c +++ b/ospf6d/ospf6_lsdb.c @@ -34,6 +34,8 @@ #include "ospf6d.h" #include "bitfield.h" +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSDB, "OSPF6 LSA database"); + struct ospf6_lsdb *ospf6_lsdb_create(void *data) { struct ospf6_lsdb *lsdb; diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 69424f4b46..cf61ca7a62 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -47,6 +47,7 @@ #include "ospf6_lsa.h" #include "ospf6_interface.h" #include "ospf6_zebra.h" +#include "ospf6_routemap_nb.h" /* Default configuration file name for ospf6d. */ #define OSPF6_DEFAULT_CONFIG "ospf6d.conf" @@ -172,6 +173,8 @@ static const struct frr_yang_module_info *const ospf6d_yang_modules[] = { &frr_interface_info, &frr_route_map_info, &frr_vrf_info, + &frr_ospf_route_map_info, + &frr_ospf6_route_map_info, }; FRR_DAEMON_INFO(ospf6d, OSPF6, .vty_port = OSPF6_VTY_PORT, @@ -182,7 +185,8 @@ FRR_DAEMON_INFO(ospf6d, OSPF6, .vty_port = OSPF6_VTY_PORT, .n_signals = array_size(ospf6_signals), .privs = &ospf6d_privs, .yang_modules = ospf6d_yang_modules, - .n_yang_modules = array_size(ospf6d_yang_modules), ) + .n_yang_modules = array_size(ospf6d_yang_modules), +); /* Main routine of ospf6d. Treatment of argument and starting ospf finite state machine is handled here. */ diff --git a/ospf6d/ospf6_memory.c b/ospf6d/ospf6_memory.c deleted file mode 100644 index 6585fc1580..0000000000 --- a/ospf6d/ospf6_memory.c +++ /dev/null @@ -1,47 +0,0 @@ -/* ospf6d memory type definitions - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga 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, or (at your option) any - * later version. - * - * Quagga 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 - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "ospf6_memory.h" - -DEFINE_MGROUP(OSPF6D, "ospf6d") -DEFINE_MTYPE(OSPF6D, OSPF6_TOP, "OSPF6 top") -DEFINE_MTYPE(OSPF6D, OSPF6_AREA, "OSPF6 area") -DEFINE_MTYPE(OSPF6D, OSPF6_IF, "OSPF6 interface") -DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor") -DEFINE_MTYPE(OSPF6D, OSPF6_ROUTE, "OSPF6 route") -DEFINE_MTYPE(OSPF6D, OSPF6_PREFIX, "OSPF6 prefix") -DEFINE_MTYPE(OSPF6D, OSPF6_MESSAGE, "OSPF6 message") -DEFINE_MTYPE(OSPF6D, OSPF6_LSA, "OSPF6 LSA") -DEFINE_MTYPE(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header") -DEFINE_MTYPE(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary") -DEFINE_MTYPE(OSPF6D, OSPF6_LSDB, "OSPF6 LSA database") -DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex") -DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree") -DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop") -DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info") -DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path") -DEFINE_MTYPE(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments") -DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other") -DEFINE_MTYPE(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments") diff --git a/ospf6d/ospf6_memory.h b/ospf6d/ospf6_memory.h deleted file mode 100644 index 57f0abd9a8..0000000000 --- a/ospf6d/ospf6_memory.h +++ /dev/null @@ -1,48 +0,0 @@ -/* ospf6d memory type declarations - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga 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, or (at your option) any - * later version. - * - * Quagga 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 _QUAGGA_OSPF6_MEMORY_H -#define _QUAGGA_OSPF6_MEMORY_H - -#include "memory.h" - -DECLARE_MGROUP(OSPF6D) -DECLARE_MTYPE(OSPF6_TOP) -DECLARE_MTYPE(OSPF6_AREA) -DECLARE_MTYPE(OSPF6_IF) -DECLARE_MTYPE(OSPF6_NEIGHBOR) -DECLARE_MTYPE(OSPF6_ROUTE) -DECLARE_MTYPE(OSPF6_PREFIX) -DECLARE_MTYPE(OSPF6_MESSAGE) -DECLARE_MTYPE(OSPF6_LSA) -DECLARE_MTYPE(OSPF6_LSA_HEADER) -DECLARE_MTYPE(OSPF6_LSA_SUMMARY) -DECLARE_MTYPE(OSPF6_LSDB) -DECLARE_MTYPE(OSPF6_VERTEX) -DECLARE_MTYPE(OSPF6_SPFTREE) -DECLARE_MTYPE(OSPF6_NEXTHOP) -DECLARE_MTYPE(OSPF6_EXTERNAL_INFO) -DECLARE_MTYPE(OSPF6_PATH) -DECLARE_MTYPE(OSPF6_DIST_ARGS) -DECLARE_MTYPE(OSPF6_REDISTRIBUTE) -DECLARE_MTYPE(OSPF6_OTHER) - -#endif /* _QUAGGA_OSPF6_MEMORY_H */ diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index aebe43b9ec..7aedd3df45 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -49,6 +49,8 @@ #include <netinet/ip6.h> +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message"); + unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; static const struct message ospf6_message_type_str[] = { {OSPF6_MESSAGE_TYPE_HELLO, "Hello"}, diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 7a1b96c2b3..485bde4b7b 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -46,9 +46,11 @@ #include "ospf6_zebra.h" #include "lib/json.h" +DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor"); + DEFINE_HOOK(ospf6_neighbor_change, (struct ospf6_neighbor * on, int state, int next_state), - (on, state, next_state)) + (on, state, next_state)); unsigned char conf_debug_ospf6_neighbor = 0; diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index 94300ff2ba..f45b340507 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -166,6 +166,6 @@ extern void install_element_ospf6_debug_neighbor(void); DECLARE_HOOK(ospf6_neighbor_change, (struct ospf6_neighbor * on, int state, int next_state), - (on, state, next_state)) + (on, state, next_state)); #endif /* OSPF6_NEIGHBOR_H */ diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index b77f968179..9770dd0444 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -38,6 +38,10 @@ #include "ospf6d.h" #include "ospf6_zebra.h" +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE, "OSPF6 route"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PATH, "OSPF6 Path"); + unsigned char conf_debug_ospf6_route = 0; static char *ospf6_route_table_name(struct ospf6_route_table *table) diff --git a/ospf6d/ospf6_routemap_nb.c b/ospf6d/ospf6_routemap_nb.c new file mode 100644 index 0000000000..b710fefbdf --- /dev/null +++ b/ospf6d/ospf6_routemap_nb.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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 "lib/northbound.h" +#include "lib/routemap.h" +#include "ospf6_routemap_nb.h" + +/* clang-format off */ +const struct frr_yang_module_info frr_ospf_route_map_info = { + .name = "frr-ospf-route-map", + .nodes = { + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-ospf-route-map:metric-type", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_metric_type_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_metric_type_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; + +const struct frr_yang_module_info frr_ospf6_route_map_info = { + .name = "frr-ospf6-route-map", + .nodes = { + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-ospf6-route-map:ipv6-address", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_ipv6_address_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_ipv6_address_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/ospf6d/ospf6_routemap_nb.h b/ospf6d/ospf6_routemap_nb.h new file mode 100644 index 0000000000..181e71a8c5 --- /dev/null +++ b/ospf6d/ospf6_routemap_nb.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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_OSPF6_ROUTEMAP_NB_H_ +#define _FRR_OSPF6_ROUTEMAP_NB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct frr_yang_module_info frr_ospf_route_map_info; +extern const struct frr_yang_module_info frr_ospf6_route_map_info; + +/* prototypes */ +int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_metric_type_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_metric_type_destroy(struct nb_cb_destroy_args *args); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ospf6d/ospf6_routemap_nb_config.c b/ospf6d/ospf6_routemap_nb_config.c new file mode 100644 index 0000000000..3c7741e473 --- /dev/null +++ b/ospf6d/ospf6_routemap_nb_config.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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 "lib/command.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/routemap.h" +#include "ospf6_routemap_nb.h" + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-ospf-route-map:metric-type + */ +int lib_route_map_entry_set_action_rmap_set_action_metric_type_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "metric-type"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "metric-type", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_metric_type_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-ospf6-route-map:ipv6-address + */ +int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *ipv6_addr; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + ipv6_addr = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "forwarding-address"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "forwarding-address", + ipv6_addr, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 51a3bff2a3..b9d413c3df 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -1418,4 +1418,5 @@ static int ospf6_snmp_module_init(void) FRR_MODULE_SETUP(.name = "ospf6d_snmp", .version = FRR_VERSION, .description = "ospf6d AgentX SNMP module", - .init = ospf6_snmp_module_init, ) + .init = ospf6_snmp_module_init, +); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 121e846843..7652d71c59 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -43,6 +43,8 @@ #include "ospf6d.h" #include "ospf6_abr.h" +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex"); + unsigned char conf_debug_ospf6_spf = 0; static void ospf6_spf_copy_nexthops_to_route(struct ospf6_route *rt, @@ -86,7 +88,7 @@ static int ospf6_vertex_cmp(const struct ospf6_vertex *va, return 0; } DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct ospf6_vertex, pqi, - ospf6_vertex_cmp) + ospf6_vertex_cmp); static int ospf6_vertex_id_cmp(void *a, void *b) { @@ -1021,13 +1023,8 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area, return NULL; } - /* Allocate memory for this LSA */ - new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length); - - /* LSA information structure */ - lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa)); - - lsa->header = (struct ospf6_lsa_header *)new_header; + lsa = ospf6_lsa_alloc(total_lsa_length); + new_header = (uint8_t *)lsa->header; lsa->lsdb = area->temp_router_lsa_lsdb; diff --git a/ospf6d/ospf6_spf.h b/ospf6d/ospf6_spf.h index 36e2b27912..4660bfd05d 100644 --- a/ospf6d/ospf6_spf.h +++ b/ospf6d/ospf6_spf.h @@ -35,7 +35,7 @@ extern unsigned char conf_debug_ospf6_spf; #define IS_OSPF6_DEBUG_SPF(level) \ (conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_##level) -PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue) +PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue); /* Transit Vertex */ struct ospf6_vertex { /* type of this vertex */ @@ -90,6 +90,7 @@ struct ospf6_vertex { #define OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED (1 << 6) #define OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED (1 << 7) #define OSPF6_SPF_FLAGS_CONFIG_CHANGE (1 << 8) +#define OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE (1 << 9) static inline void ospf6_set_spf_reason(struct ospf6 *ospf, unsigned int reason) { diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 3f72ec828e..e2cd5c259d 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -53,12 +53,14 @@ #include "ospf6d.h" #include "lib/json.h" -DEFINE_QOBJ_TYPE(ospf6) +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top"); + +DEFINE_QOBJ_TYPE(ospf6); FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, -) +); /* global ospf6d variable */ static struct ospf6_master ospf6_master; @@ -245,6 +247,8 @@ static struct ospf6 *ospf6_create(const char *name) o->spf_max_holdtime = OSPF_SPF_MAX_HOLDTIME_DEFAULT; o->spf_hold_multiplier = 1; + o->default_originate = DEFAULT_ORIGINATE_NONE; + o->redistribute = 0; /* LSA timers value init */ o->lsa_minarrival = OSPF_MIN_LS_ARRIVAL; @@ -809,7 +813,8 @@ DEFUN (no_ospf6_interface_area, /* Verify Area */ if (oi->area == NULL) { - vty_out(vty, "No such Area-ID: %s\n", argv[idx_ipv4]->arg); + vty_out(vty, "%s not attached to area %s\n", + oi->interface->name, oi->area->name); return CMD_SUCCESS; } @@ -830,7 +835,6 @@ DEFUN (no_ospf6_interface_area, UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE); ospf6_abr_disable_area(oa); } - ospf6_interface_delete(oi); return CMD_SUCCESS; } @@ -1327,6 +1331,7 @@ static int config_write_ospf6(struct vty *vty) ospf6_area_config_write(vty, ospf6); ospf6_spf_config_write(vty, ospf6); ospf6_distance_config_write(vty, ospf6); + ospf6_distribute_config_write(vty, ospf6); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, j, oa)) { for (ALL_LIST_ELEMENTS_RO(oa->if_list, k, oi)) diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 75dff86cd7..08b884f23a 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -40,6 +40,15 @@ enum { struct ospf6_redist { uint8_t instance; + + /* Redistribute metric info. */ + struct { + int type; /* External metric type (E1 or E2). */ + int value; /* Value for static metric (24-bit). + * -1 means metric value is not set. + */ + } dmetric; + /* For redistribute route map. */ struct { char *name; @@ -83,13 +92,18 @@ struct ospf6 { uint32_t external_id; /* OSPF6 redistribute configuration */ - struct list *redist[ZEBRA_ROUTE_MAX]; + struct list *redist[ZEBRA_ROUTE_MAX + 1]; uint8_t flag; + int redistribute; /* Num of redistributed protocols. */ + /* Configuration bitmask, refer to enum above */ uint8_t config_flags; - + int default_originate; /* Default information originate. */ +#define DEFAULT_ORIGINATE_NONE 0 +#define DEFAULT_ORIGINATE_ZEBRA 1 +#define DEFAULT_ORIGINATE_ALWAYS 2 /* LSA timer parameters */ unsigned int lsa_minarrival; /* LSA minimum arrival in milliseconds. */ @@ -132,12 +146,13 @@ struct ospf6 { */ uint16_t max_multipath; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(ospf6) +DECLARE_QOBJ_TYPE(ospf6); #define OSPF6_DISABLED 0x01 #define OSPF6_STUB_ROUTER 0x02 +#define OSPF6_FLAG_ASBR 0x04 /* global pointer for OSPF top data structure */ extern struct ospf6 *ospf6; diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 9b9453ce24..76e7172870 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -42,7 +42,7 @@ #include "ospf6_area.h" #include "lib/json.h" -DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance") +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance"); unsigned char conf_debug_ospf6_zebra = 0; @@ -172,12 +172,23 @@ static int ospf6_zebra_if_address_update_delete(ZAPI_CALLBACK_ARGS) return 0; } +static int is_prefix_default(struct prefix_ipv6 *p) +{ + struct prefix_ipv6 q = {}; + + q.family = AF_INET6; + q.prefixlen = 0; + + return prefix_same((struct prefix *)p, (struct prefix *)&q); +} + static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS) { struct zapi_route api; unsigned long ifindex; struct in6_addr *nexthop; struct ospf6 *ospf6; + struct prefix_ipv6 p; ospf6 = ospf6_lookup_by_vrf_id(vrf_id); @@ -205,6 +216,10 @@ static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS) zebra_route_string(api.type), &api.prefix, nexthop, ifindex, api.tag); + memcpy(&p, &api.prefix, sizeof(p)); + if (is_prefix_default(&p)) + api.type = DEFAULT_ROUTE; + if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD) ospf6_asbr_redistribute_add(api.type, ifindex, &api.prefix, api.nexthop_num, nexthop, api.tag, diff --git a/ospf6d/ospf6_zebra.h b/ospf6d/ospf6_zebra.h index 5f340924b9..a3ccc3d38d 100644 --- a/ospf6d/ospf6_zebra.h +++ b/ospf6d/ospf6_zebra.h @@ -23,6 +23,8 @@ #include "zclient.h" +#define DEFAULT_ROUTE ZEBRA_ROUTE_MAX + /* Debug option */ extern unsigned char conf_debug_ospf6_zebra; #define OSPF6_DEBUG_ZEBRA_SEND 0x01 diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 8d9c85fd08..91d427c78c 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -46,6 +46,8 @@ #include "ospf6_bfd.h" #include "lib/json.h" +DEFINE_MGROUP(OSPF6D, "ospf6d"); + struct route_node *route_prev(struct route_node *node) { struct route_node *end; diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index d85ff40f32..dfac57aa2f 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -23,8 +23,9 @@ #include "libospf.h" #include "thread.h" +#include "memory.h" -#include "ospf6_memory.h" +DECLARE_MGROUP(OSPF6D); /* global variables */ extern struct thread_master *master; @@ -94,6 +95,7 @@ extern struct thread_master *master; return CMD_SUCCESS; \ } +#define IS_OSPF6_ASBR(O) ((O)->flag & OSPF6_FLAG_ASBR) extern struct zebra_privs_t ospf6d_privs; /* Function Prototypes */ diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index ec6e593533..788b532a90 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -34,13 +34,14 @@ ospf6d_libospf6_a_SOURCES = \ ospf6d/ospf6_abr.c \ ospf6d/ospf6_area.c \ ospf6d/ospf6_asbr.c \ + ospf6d/ospf6_routemap_nb.c \ + ospf6d/ospf6_routemap_nb_config.c \ ospf6d/ospf6_bfd.c \ ospf6d/ospf6_flood.c \ ospf6d/ospf6_interface.c \ ospf6d/ospf6_intra.c \ ospf6d/ospf6_lsa.c \ ospf6d/ospf6_lsdb.c \ - ospf6d/ospf6_memory.c \ ospf6d/ospf6_message.c \ ospf6d/ospf6_neighbor.c \ ospf6d/ospf6_network.c \ @@ -62,12 +63,12 @@ noinst_HEADERS += \ ospf6d/ospf6_intra.h \ ospf6d/ospf6_lsa.h \ ospf6d/ospf6_lsdb.h \ - ospf6d/ospf6_memory.h \ ospf6d/ospf6_message.h \ ospf6d/ospf6_neighbor.h \ ospf6d/ospf6_network.h \ ospf6d/ospf6_proto.h \ ospf6d/ospf6_route.h \ + ospf6d/ospf6_routemap_nb.h \ ospf6d/ospf6_spf.h \ ospf6d/ospf6_top.h \ ospf6d/ospf6_zebra.h \ @@ -80,6 +81,15 @@ ospf6d_ospf6d_SOURCES = \ # end ospf6d_ospf6d_snmp_la_SOURCES = ospf6d/ospf6_snmp.c -ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la + +clippy_scan += \ + ospf6d/ospf6_asbr.c \ + # end + +nodist_ospf6d_ospf6d_SOURCES = \ + yang/frr-ospf-route-map.yang.c \ + yang/frr-ospf6-route-map.yang.c \ + # end diff --git a/ospfclient/ospf_apiclient.c b/ospfclient/ospf_apiclient.c index 1b9b66d745..29f1c0807d 100644 --- a/ospfclient/ospf_apiclient.c +++ b/ospfclient/ospf_apiclient.c @@ -58,10 +58,10 @@ #include "ospfd/ospf_dump_api.c" #include "ospfd/ospf_api.c" -XREF_SETUP() +XREF_SETUP(); -DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient") -DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client") +DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient"); +DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client"); /* Backlog for listen */ #define BACKLOG 5 diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index f3c4798906..b5c97eda3c 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -675,7 +675,8 @@ static int ospf_abr_translate_nssa(struct ospf_area *area, struct ospf_lsa *lsa) * originate translated LSA */ - if (ospf_translated_nssa_originate(area->ospf, lsa) == NULL) { + if (ospf_translated_nssa_originate(area->ospf, lsa, old) + == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug( "ospf_abr_translate_nssa(): Could not translate Type-7 for %pI4 to Type-5", diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c index a9bc9069d2..2ab7db68bd 100644 --- a/ospfd/ospf_bfd.c +++ b/ospfd/ospf_bfd.c @@ -23,6 +23,7 @@ #include <zebra.h> #include "command.h" +#include "json.h" #include "linklist.h" #include "memory.h" #include "prefix.h" @@ -44,48 +45,7 @@ #include "ospf_dump.h" #include "ospf_vty.h" -extern struct zclient *zclient; - -/* - * ospf_bfd_info_free - Free BFD info structure - */ -void ospf_bfd_info_free(void **bfd_info) -{ - bfd_info_free((struct bfd_info **)bfd_info); -} - -/* - * ospf_bfd_reg_dereg_nbr - Register/Deregister a neighbor with BFD through - * zebra for starting/stopping the monitoring of - * the neighbor rechahability. - */ -static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command) -{ - struct ospf_interface *oi = nbr->oi; - struct interface *ifp = oi->ifp; - struct ospf_if_params *params; - struct bfd_info *bfd_info; - int cbit; - - /* Check if BFD is enabled */ - params = IF_DEF_PARAMS(ifp); - - /* Check if BFD is enabled */ - if (!params->bfd_info) - return; - bfd_info = (struct bfd_info *)params->bfd_info; - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("%s nbr (%pI4) with BFD. OSPF vrf %s", - bfd_get_command_dbg_str(command), - &nbr->src, - ospf_vrf_id_to_name(oi->ospf->vrf_id)); - - cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON); - - bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->src, NULL, ifp->name, - 0, 0, cbit, command, 0, oi->ospf->vrf_id); -} +DEFINE_MTYPE_STATIC(OSPFD, BFD_CONFIG, "BFD configuration data"); /* * ospf_bfd_trigger_event - Neighbor is registered/deregistered with BFD when @@ -94,293 +54,157 @@ static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command) void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state, int state) { if ((old_state < NSM_TwoWay) && (state >= NSM_TwoWay)) - ospf_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_REGISTER); + bfd_sess_install(nbr->bfd_session); else if ((old_state >= NSM_TwoWay) && (state < NSM_TwoWay)) - ospf_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_DEREGISTER); + bfd_sess_uninstall(nbr->bfd_session); } -/* - * ospf_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated - * with a interface with BFD through - * zebra for starting/stopping the monitoring of - * the neighbor rechahability. - */ -static int ospf_bfd_reg_dereg_all_nbr(struct interface *ifp, int command) +static void ospf_bfd_session_change(struct bfd_session_params *bsp, + const struct bfd_session_status *bss, + void *arg) { - struct ospf_interface *oi; - struct route_table *nbrs; - struct ospf_neighbor *nbr; - struct route_node *irn; - struct route_node *nrn; - - for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) { - if ((oi = irn->info) == NULL) - continue; + struct ospf_neighbor *nbr = arg; - if ((nbrs = oi->nbrs) == NULL) - continue; - - for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) { - if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self) - continue; - - if (command != ZEBRA_BFD_DEST_DEREGISTER) - ospf_bfd_info_nbr_create(oi, nbr); - else - bfd_info_free( - (struct bfd_info **)&nbr->bfd_info); - - if (nbr->state < NSM_TwoWay) - continue; + /* BFD peer went down. */ + if (bss->state == BFD_STATUS_DOWN + && bss->previous_state == BFD_STATUS_UP) { + if (IS_DEBUG_OSPF(bfd, BFD_LIB)) + zlog_debug("%s: NSM[%s:%pI4]: BFD Down", __func__, + IF_NAME(nbr->oi), &nbr->address.u.prefix4); - ospf_bfd_reg_dereg_nbr(nbr, command); - } + OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); } - return 0; + /* BFD peer went up. */ + if (bss->state == BSS_UP && bss->previous_state == BSS_DOWN) + if (IS_DEBUG_OSPF(bfd, BFD_LIB)) + zlog_debug("%s: NSM[%s:%pI4]: BFD Up", __func__, + IF_NAME(nbr->oi), &nbr->address.u.prefix4); } -/* - * ospf_bfd_nbr_replay - Replay all the neighbors that have BFD enabled - * to zebra - */ -static int ospf_bfd_nbr_replay(ZAPI_CALLBACK_ARGS) +void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr) { - struct listnode *inode, *node, *onode; - struct ospf *ospf; - struct ospf_interface *oi; - struct route_table *nbrs; - struct route_node *rn; - struct ospf_neighbor *nbr; - struct ospf_if_params *params; + struct ospf_interface *oi = nbr->oi; + struct ospf_if_params *oip = IF_DEF_PARAMS(oi->ifp); - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) { - zlog_debug("Zebra: BFD Dest replay request"); + /* BFD configuration was removed. */ + if (oip->bfd_config == NULL) { + bfd_sess_free(&nbr->bfd_session); + return; } - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id); - - /* Replay the neighbor, if BFD is enabled in OSPF */ - for (ALL_LIST_ELEMENTS(om->ospf, node, onode, ospf)) { - for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) { - if ((nbrs = oi->nbrs) == NULL) - continue; - - params = IF_DEF_PARAMS(oi->ifp); - if (!params->bfd_info) - continue; - - for (rn = route_top(nbrs); rn; rn = route_next(rn)) { - if ((nbr = rn->info) == NULL - || nbr == oi->nbr_self) - continue; + /* New BFD session. */ + if (nbr->bfd_session == NULL) { + nbr->bfd_session = bfd_sess_new(ospf_bfd_session_change, nbr); + bfd_sess_set_ipv4_addrs(nbr->bfd_session, NULL, &nbr->src); + bfd_sess_set_interface(nbr->bfd_session, oi->ifp->name); + bfd_sess_set_vrf(nbr->bfd_session, oi->ospf->vrf_id); + bfd_sess_enable(nbr->bfd_session, true); + } - if (nbr->state < NSM_TwoWay) - continue; + /* Set new configuration. */ + bfd_sess_set_timers(nbr->bfd_session, + oip->bfd_config->detection_multiplier, + oip->bfd_config->min_rx, oip->bfd_config->min_tx); + bfd_sess_set_profile(nbr->bfd_session, oip->bfd_config->profile); - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("Replaying nbr (%pI4) to BFD", - &nbr->src); + /* Don't start sessions on down OSPF sessions. */ + if (nbr->state < NSM_TwoWay) + return; - ospf_bfd_reg_dereg_nbr(nbr, - ZEBRA_BFD_DEST_UPDATE); - } - } - } - return 0; + bfd_sess_install(nbr->bfd_session); } -/* - * ospf_bfd_interface_dest_update - Find the neighbor for which the BFD status - * has changed and bring down the neighbor - * connectivity if the BFD status changed to - * down. - */ -static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS) +static void ospf_interface_bfd_apply(struct interface *ifp) { - struct interface *ifp; struct ospf_interface *oi; - struct ospf_if_params *params; - struct ospf_neighbor *nbr = NULL; - struct route_node *node; - struct route_node *n_node; - struct prefix p, src_p; - int status; - int old_status; - struct bfd_info *bfd_info; - struct timeval tv; - - ifp = bfd_get_peer_info(zclient->ibuf, &p, &src_p, &status, NULL, - vrf_id); - - if ((ifp == NULL) || (p.family != AF_INET)) - return 0; - - if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) - zlog_debug("Zebra: interface %s bfd destination %pFX %s", - ifp->name, &p, bfd_get_status_str(status)); - - params = IF_DEF_PARAMS(ifp); - if (!params->bfd_info) - return 0; - - for (node = route_top(IF_OIFS(ifp)); node; node = route_next(node)) { - if ((oi = node->info) == NULL) - continue; - - /* 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); - } + struct route_table *nbrs; + struct ospf_neighbor *nbr; + struct route_node *irn; + struct route_node *nrn; - if (!nbr || !nbr->bfd_info) + /* Iterate over all interfaces and set neighbors BFD session. */ + for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) { + if ((oi = irn->info) == NULL) continue; - - bfd_info = (struct bfd_info *)nbr->bfd_info; - if (bfd_info->status == status) + if ((nbrs = oi->nbrs) == NULL) continue; + for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) { + if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self) + continue; - old_status = bfd_info->status; - BFD_SET_CLIENT_STATUS(bfd_info->status, status); - monotime(&tv); - bfd_info->last_update = tv.tv_sec; - - if ((status == BFD_STATUS_DOWN) - && (old_status == BFD_STATUS_UP)) { - if (IS_DEBUG_OSPF(nsm, NSM_EVENTS)) - zlog_debug("NSM[%s:%pI4]: BFD Down", - IF_NAME(nbr->oi), - &nbr->address.u.prefix4); - - OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); - } - if ((status == BFD_STATUS_UP) - && (old_status == BFD_STATUS_DOWN)) { - if (IS_DEBUG_OSPF(nsm, NSM_EVENTS)) - zlog_debug("NSM[%s:%pI4]: BFD Up", - IF_NAME(nbr->oi), - &nbr->address.u.prefix4); + ospf_neighbor_bfd_apply(nbr); } } - - return 0; } -/* - * ospf_bfd_info_nbr_create - Create/update BFD information for a neighbor. - */ -void ospf_bfd_info_nbr_create(struct ospf_interface *oi, - struct ospf_neighbor *nbr) +static void ospf_interface_enable_bfd(struct interface *ifp) { - struct bfd_info *oi_bfd_info; - struct bfd_info *nbr_bfd_info; - struct interface *ifp = oi->ifp; - struct ospf_if_params *params; - - /* Check if BFD is enabled */ - params = IF_DEF_PARAMS(ifp); + struct ospf_if_params *oip = IF_DEF_PARAMS(ifp); - /* Check if BFD is enabled */ - if (!params->bfd_info) + if (oip->bfd_config) return; - oi_bfd_info = (struct bfd_info *)params->bfd_info; - if (!nbr->bfd_info) - nbr->bfd_info = bfd_info_create(); + /* Allocate memory for configurations and set defaults. */ + oip->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*oip->bfd_config)); + oip->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT; + oip->bfd_config->min_rx = BFD_DEF_MIN_RX; + oip->bfd_config->min_tx = BFD_DEF_MIN_TX; +} - nbr_bfd_info = (struct bfd_info *)nbr->bfd_info; - nbr_bfd_info->detect_mult = oi_bfd_info->detect_mult; - nbr_bfd_info->desired_min_tx = oi_bfd_info->desired_min_tx; - nbr_bfd_info->required_min_rx = oi_bfd_info->required_min_rx; +void ospf_interface_disable_bfd(struct interface *ifp, + struct ospf_if_params *oip) +{ + XFREE(MTYPE_BFD_CONFIG, oip->bfd_config); + ospf_interface_bfd_apply(ifp); } /* * ospf_bfd_write_config - Write the interface BFD configuration. */ -void ospf_bfd_write_config(struct vty *vty, struct ospf_if_params *params) - +void ospf_bfd_write_config(struct vty *vty, const struct ospf_if_params *params + __attribute__((unused))) { #if HAVE_BFDD == 0 - struct bfd_info *bfd_info; -#endif /* ! HAVE_BFDD */ - - if (!params->bfd_info) - return; - -#if HAVE_BFDD == 0 - bfd_info = (struct bfd_info *)params->bfd_info; - - if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) - vty_out(vty, " ip ospf bfd %d %d %d\n", bfd_info->detect_mult, - bfd_info->required_min_rx, bfd_info->desired_min_tx); + if (params->bfd_config->detection_multiplier != BFD_DEF_DETECT_MULT + || params->bfd_config->min_rx != BFD_DEF_MIN_RX + || params->bfd_config->min_tx != BFD_DEF_MIN_TX) + vty_out(vty, " ip ospf bfd %d %d %d\n", + params->bfd_config->detection_multiplier, + params->bfd_config->min_rx, params->bfd_config->min_tx); else #endif /* ! HAVE_BFDD */ vty_out(vty, " ip ospf bfd\n"); -} -/* - * ospf_bfd_show_info - Show BFD info structure - */ -void ospf_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj, - bool use_json, int param_only) -{ - if (param_only) - bfd_show_param(vty, (struct bfd_info *)bfd_info, 1, 0, use_json, - json_obj); - else - bfd_show_info(vty, (struct bfd_info *)bfd_info, 0, 1, use_json, - json_obj); + if (params->bfd_config->profile[0]) + vty_out(vty, " ip ospf bfd profile %s\n", + params->bfd_config->profile); } -/* - * ospf_bfd_interface_show - Show the interface BFD configuration. - */ -void ospf_bfd_interface_show(struct vty *vty, struct interface *ifp, - json_object *json_interface_sub, bool use_json) +void ospf_interface_bfd_show(struct vty *vty, const struct interface *ifp, + struct json_object *json) { - struct ospf_if_params *params; - - params = IF_DEF_PARAMS(ifp); + struct ospf_if_params *params = IF_DEF_PARAMS(ifp); + struct bfd_configuration *bfd_config = params->bfd_config; + struct json_object *json_bfd; - ospf_bfd_show_info(vty, params->bfd_info, json_interface_sub, use_json, - 1); -} - -/* - * ospf_bfd_if_param_set - Set the configured BFD paramter values for - * interface. - */ -static void ospf_bfd_if_param_set(struct interface *ifp, uint32_t min_rx, - uint32_t min_tx, uint8_t detect_mult, - int defaults) -{ - struct ospf_if_params *params; - int command = 0; - - params = IF_DEF_PARAMS(ifp); + if (bfd_config == NULL) + return; - bfd_set_param((struct bfd_info **)&(params->bfd_info), min_rx, min_tx, - detect_mult, NULL, defaults, &command); - if (command) - ospf_bfd_reg_dereg_all_nbr(ifp, command); + if (json) { + json_bfd = json_object_new_object(); + json_object_int_add(json_bfd, "detectionMultiplier", + bfd_config->detection_multiplier); + json_object_int_add(json_bfd, "rxMinInterval", + bfd_config->min_rx); + json_object_int_add(json_bfd, "txMinInterval", + bfd_config->min_tx); + json_object_object_add(json, "peerBfdInfo", json_bfd); + } else + vty_out(vty, + " BFD: Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n", + bfd_config->detection_multiplier, bfd_config->min_rx, + bfd_config->min_tx); } DEFUN (ip_ospf_bfd, @@ -391,17 +215,8 @@ DEFUN (ip_ospf_bfd, "Enables BFD support\n") { VTY_DECLVAR_CONTEXT(interface, ifp); - struct ospf_if_params *params; - struct bfd_info *bfd_info; - - assert(ifp); - params = IF_DEF_PARAMS(ifp); - bfd_info = params->bfd_info; - - if (!bfd_info || !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)) - ospf_bfd_if_param_set(ifp, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX, - BFD_DEF_DETECT_MULT, 1); - + ospf_interface_enable_bfd(ifp); + ospf_interface_bfd_apply(ifp); return CMD_SUCCESS; } @@ -421,23 +236,63 @@ DEFUN( "Desired min transmit interval\n") { VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; int idx_number = 3; int idx_number_2 = 4; int idx_number_3 = 5; - uint32_t rx_val; - uint32_t tx_val; - uint8_t dm_val; - int ret; - assert(ifp); + ospf_interface_enable_bfd(ifp); + + params = IF_DEF_PARAMS(ifp); + params->bfd_config->detection_multiplier = + strtol(argv[idx_number]->arg, NULL, 10); + params->bfd_config->min_rx = strtol(argv[idx_number_2]->arg, NULL, 10); + params->bfd_config->min_tx = strtol(argv[idx_number_3]->arg, NULL, 10); + + ospf_interface_bfd_apply(ifp); + + return CMD_SUCCESS; +} - if ((ret = bfd_validate_param( - vty, argv[idx_number]->arg, argv[idx_number_2]->arg, - argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val)) - != CMD_SUCCESS) - return ret; +DEFUN (ip_ospf_bfd_prof, + ip_ospf_bfd_prof_cmd, + "ip ospf bfd profile BFDPROF", + "IP Information\n" + "OSPF interface commands\n" + "Enables BFD support\n" + BFD_PROFILE_STR + BFD_PROFILE_NAME_STR) +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + int idx_prof = 4; - ospf_bfd_if_param_set(ifp, rx_val, tx_val, dm_val, 0); + ospf_interface_enable_bfd(ifp); + params = IF_DEF_PARAMS(ifp); + strlcpy(params->bfd_config->profile, argv[idx_prof]->arg, + sizeof(params->bfd_config->profile)); + ospf_interface_bfd_apply(ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_ip_ospf_bfd_prof, + no_ip_ospf_bfd_prof_cmd, + "no ip ospf bfd profile [BFDPROF]", + NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Enables BFD support\n" + BFD_PROFILE_STR + BFD_PROFILE_NAME_STR) +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + + ospf_interface_enable_bfd(ifp); + params = IF_DEF_PARAMS(ifp); + params->bfd_config->profile[0] = 0; + ospf_interface_bfd_apply(ifp); return CMD_SUCCESS; } @@ -461,29 +316,18 @@ DEFUN (no_ip_ospf_bfd, ) { VTY_DECLVAR_CONTEXT(interface, ifp); - struct ospf_if_params *params; - - assert(ifp); - - params = IF_DEF_PARAMS(ifp); - if (params->bfd_info) { - ospf_bfd_reg_dereg_all_nbr(ifp, ZEBRA_BFD_DEST_DEREGISTER); - bfd_info_free(&(params->bfd_info)); - } - + ospf_interface_disable_bfd(ifp, IF_DEF_PARAMS(ifp)); return CMD_SUCCESS; } -void ospf_bfd_init(void) +void ospf_bfd_init(struct thread_master *tm) { - bfd_gbl_init(); - - /* Initialize BFD client functions */ - zclient->interface_bfd_dest_update = ospf_bfd_interface_dest_update; - zclient->bfd_dest_replay = ospf_bfd_nbr_replay; + bfd_protocol_integration_init(zclient, tm); /* Install BFD command */ install_element(INTERFACE_NODE, &ip_ospf_bfd_cmd); install_element(INTERFACE_NODE, &ip_ospf_bfd_param_cmd); + install_element(INTERFACE_NODE, &ip_ospf_bfd_prof_cmd); + install_element(INTERFACE_NODE, &no_ip_ospf_bfd_prof_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_bfd_cmd); } diff --git a/ospfd/ospf_bfd.h b/ospfd/ospf_bfd.h index 74385d3268..9393c839f5 100644 --- a/ospfd/ospf_bfd.h +++ b/ospfd/ospf_bfd.h @@ -23,27 +23,34 @@ #ifndef _ZEBRA_OSPF_BFD_H #define _ZEBRA_OSPF_BFD_H +#include "ospfd/ospf_interface.h" #include "json.h" -extern void ospf_bfd_init(void); +extern void ospf_bfd_init(struct thread_master *tm); extern void ospf_bfd_write_config(struct vty *vty, - struct ospf_if_params *params); + const struct ospf_if_params *params); extern void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state, int state); -extern void ospf_bfd_interface_show(struct vty *vty, struct interface *ifp, - json_object *json_interface_sub, - bool use_json); - -extern void ospf_bfd_info_nbr_create(struct ospf_interface *oi, - struct ospf_neighbor *nbr); +/** + * Legacy information: it is the peers who actually have this information + * and the protocol should not need to know about timers. + */ +extern void ospf_interface_bfd_show(struct vty *vty, + const struct interface *ifp, + struct json_object *json); -extern void ospf_bfd_show_info(struct vty *vty, void *bfd_info, - json_object *json_obj, bool use_json, - int param_only); +/** + * Disables interface BFD configuration and remove settings from all peers. + */ +extern void ospf_interface_disable_bfd(struct interface *ifp, + struct ospf_if_params *oip); -extern void ospf_bfd_info_free(void **bfd_info); +/** + * Create/update BFD session for this OSPF neighbor. + */ +extern void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr); #endif /* _ZEBRA_OSPF_BFD_H */ diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 19829d4546..2442f2e781 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -21,6 +21,7 @@ #include <zebra.h> +#include "lib/bfd.h" #include "monotime.h" #include "linklist.h" #include "thread.h" @@ -60,6 +61,7 @@ unsigned long conf_debug_ospf_ti_lfa = 0; unsigned long conf_debug_ospf_defaultinfo = 0; unsigned long conf_debug_ospf_ldp_sync = 0; unsigned long conf_debug_ospf_gr = 0; +unsigned long conf_debug_ospf_bfd; /* Enable debug option variables -- valid only session. */ unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; @@ -76,6 +78,7 @@ unsigned long term_debug_ospf_ti_lfa = 0; unsigned long term_debug_ospf_defaultinfo; unsigned long term_debug_ospf_ldp_sync; unsigned long term_debug_ospf_gr = 0; +unsigned long term_debug_ospf_bfd; const char *ospf_redist_string(unsigned int route_type) { @@ -1563,6 +1566,31 @@ DEFPY (debug_ospf_gr, return CMD_SUCCESS; } +DEFPY(debug_ospf_bfd, debug_ospf_bfd_cmd, + "[no] debug ospf bfd", + NO_STR + DEBUG_STR + OSPF_STR + "Bidirection Forwarding Detection\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) { + bfd_protocol_integration_set_debug(false); + CONF_DEBUG_OFF(bfd, BFD_LIB); + } else { + bfd_protocol_integration_set_debug(true); + CONF_DEBUG_ON(bfd, BFD_LIB); + } + } + + if (no) + TERM_DEBUG_OFF(bfd, BFD_LIB); + else + TERM_DEBUG_ON(bfd, BFD_LIB); + + return CMD_SUCCESS; +} + DEFUN (no_debug_ospf, no_debug_ospf_cmd, "no debug ospf", @@ -1594,6 +1622,10 @@ DEFUN (no_debug_ospf, DEBUG_OFF(defaultinfo, DEFAULTINFO); DEBUG_OFF(ldp_sync, LDP_SYNC); + /* BFD debugging is two parts: OSPF and library. */ + DEBUG_OFF(bfd, BFD_LIB); + bfd_protocol_integration_set_debug(false); + for (i = 0; i < 5; i++) DEBUG_PACKET_OFF(i, flag); } @@ -1621,6 +1653,7 @@ DEFUN (no_debug_ospf, TERM_DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE); TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO); TERM_DEBUG_OFF(ldp_sync, LDP_SYNC); + TERM_DEBUG_OFF(bfd, BFD_LIB); return CMD_SUCCESS; } @@ -1730,6 +1763,10 @@ static int show_debugging_ospf_common(struct vty *vty) if (IS_DEBUG_OSPF(gr, GR_HELPER) == OSPF_DEBUG_GR_HELPER) vty_out(vty, " OSPF Graceful Restart Helper debugging is on\n"); + if (IS_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB) + vty_out(vty, + " OSPF BFD integration library debugging is on\n"); + vty_out(vty, "\n"); return CMD_SUCCESS; @@ -1917,6 +1954,11 @@ static int config_write_debug(struct vty *vty) write = 1; } + if (IS_CONF_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB) { + vty_out(vty, "debug ospf%s bfd\n", str); + write = 1; + } + return write; } @@ -1949,6 +1991,7 @@ void ospf_debug_init(void) install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd); install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd); install_element(ENABLE_NODE, &debug_ospf_gr_cmd); + install_element(ENABLE_NODE, &debug_ospf_bfd_cmd); install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd); install_element(ENABLE_NODE, &debug_ospf_packet_cmd); @@ -1992,6 +2035,7 @@ void ospf_debug_init(void) install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd); install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd); install_element(CONFIG_NODE, &debug_ospf_gr_cmd); + install_element(CONFIG_NODE, &debug_ospf_bfd_cmd); install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd); install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd); diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h index c4c5606663..b1c1d02a51 100644 --- a/ospfd/ospf_dump.h +++ b/ospfd/ospf_dump.h @@ -67,6 +67,8 @@ #define OSPF_DEBUG_GR_HELPER 0x01 #define OSPF_DEBUG_GR 0x03 +#define OSPF_DEBUG_BFD_LIB 0x01 + /* Macro for setting debug option. */ #define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) #define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b) @@ -140,6 +142,7 @@ extern unsigned long term_debug_ospf_ti_lfa; extern unsigned long term_debug_ospf_defaultinfo; extern unsigned long term_debug_ospf_ldp_sync; extern unsigned long term_debug_ospf_gr; +extern unsigned long term_debug_ospf_bfd; /* Message Strings. */ extern char *ospf_lsa_type_str[]; diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 51599ccc8a..6829c4a347 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -35,6 +35,7 @@ #include "ldp_sync.h" #include "ospfd/ospfd.h" +#include "ospfd/ospf_bfd.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" @@ -49,11 +50,11 @@ #include "ospfd/ospf_dump.h" #include "ospfd/ospf_ldp_sync.h" -DEFINE_QOBJ_TYPE(ospf_interface) -DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd)) -DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd)) -DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)) -DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)) +DEFINE_QOBJ_TYPE(ospf_interface); +DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd)); +DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd)); +DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)); +DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)); int ospf_interface_neighbor_count(struct ospf_interface *oi) { @@ -545,10 +546,11 @@ static struct ospf_if_params *ospf_new_if_params(void) return oip; } -void ospf_del_if_params(struct ospf_if_params *oip) +static void ospf_del_if_params(struct interface *ifp, + struct ospf_if_params *oip) { list_delete(&oip->auth_crypt); - bfd_info_free(&(oip->bfd_info)); + ospf_interface_disable_bfd(ifp, oip); ldp_sync_info_free(&(oip->ldp_sync_info)); XFREE(MTYPE_OSPF_IF_PARAMS, oip); } @@ -582,7 +584,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) && !OSPF_IF_PARAM_CONFIGURED(oip, auth_type) && !OSPF_IF_PARAM_CONFIGURED(oip, if_area) && listcount(oip->auth_crypt) == 0) { - ospf_del_if_params(oip); + ospf_del_if_params(ifp, oip); rn->info = NULL; route_unlock_node(rn); } @@ -696,10 +698,10 @@ static int ospf_if_delete_hook(struct interface *ifp) for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn)) if (rn->info) - ospf_del_if_params(rn->info); + ospf_del_if_params(ifp, rn->info); route_table_finish(IF_OIFS_PARAMS(ifp)); - ospf_del_if_params((struct ospf_if_params *)IF_DEF_PARAMS(ifp)); + ospf_del_if_params(ifp, IF_DEF_PARAMS(ifp)); XFREE(MTYPE_OSPF_IF_INFO, ifp->info); return rc; @@ -1270,12 +1272,27 @@ void ospf_if_interface(struct interface *ifp) hook_call(ospf_if_update, ifp); } -static int ospf_ifp_create(struct interface *ifp) +uint32_t ospf_if_count_area_params(struct interface *ifp) { - struct ospf *ospf = NULL; struct ospf_if_params *params; struct route_node *rn; uint32_t count = 0; + + params = IF_DEF_PARAMS(ifp); + if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) + count++; + + for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn)) + if ((params = rn->info) + && OSPF_IF_PARAM_CONFIGURED(params, if_area)) + count++; + + return count; +} + +static int ospf_ifp_create(struct interface *ifp) +{ + struct ospf *ospf = NULL; struct ospf_if_info *oii; if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) @@ -1301,18 +1318,8 @@ static int ospf_ifp_create(struct interface *ifp) if (!ospf) return 0; - params = IF_DEF_PARAMS(ifp); - if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) - count++; - - for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn)) - if ((params = rn->info) && OSPF_IF_PARAM_CONFIGURED(params, if_area)) - count++; - - if (count > 0) { - ospf->if_ospf_cli_count += count; + if (ospf_if_count_area_params(ifp) > 0) ospf_interface_area_set(ospf, ifp); - } ospf_if_recalculate_output_cost(ifp); @@ -1380,9 +1387,7 @@ static int ospf_ifp_down(struct interface *ifp) static int ospf_ifp_destroy(struct interface *ifp) { struct ospf *ospf; - struct ospf_if_params *params; struct route_node *rn; - uint32_t count = 0; if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) zlog_debug( @@ -1395,18 +1400,8 @@ static int ospf_ifp_destroy(struct interface *ifp) ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); if (ospf) { - params = IF_DEF_PARAMS(ifp); - if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) - count++; - - for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn)) - if ((params = rn->info) && OSPF_IF_PARAM_CONFIGURED(params, if_area)) - count++; - - if (count > 0) { - ospf->if_ospf_cli_count -= count; + if (ospf_if_count_area_params(ifp) > 0) ospf_interface_area_unset(ospf, ifp); - } } for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index bf59af16c2..e2d7327381 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -22,6 +22,7 @@ #ifndef _ZEBRA_OSPF_INTERFACE_H #define _ZEBRA_OSPF_INTERFACE_H +#include "lib/bfd.h" #include "qobj.h" #include "hook.h" #include "ospfd/ospf_packet.h" @@ -104,7 +105,16 @@ struct ospf_if_params { uint32_t network_lsa_seqnum; /* Network LSA seqnum */ /* BFD configuration */ - struct bfd_info *bfd_info; + struct bfd_configuration { + /** BFD session detection multiplier. */ + uint8_t detection_multiplier; + /** BFD session minimum required receive interval. */ + uint32_t min_rx; + /** BFD session minimum required transmission interval. */ + uint32_t min_tx; + /** BFD profile. */ + char profile[BFD_PROFILE_NAME_LEN]; + } *bfd_config; /* MPLS LDP-IGP Sync configuration */ struct ldp_sync_info *ldp_sync_info; @@ -252,9 +262,9 @@ struct ospf_interface { uint32_t full_nbrs; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(ospf_interface) +DECLARE_QOBJ_TYPE(ospf_interface); /* Prototypes. */ extern char *ospf_if_name(struct ospf_interface *); @@ -285,7 +295,6 @@ extern struct ospf_if_params *ospf_lookup_if_params(struct interface *, struct in_addr); extern struct ospf_if_params *ospf_get_if_params(struct interface *, struct in_addr); -extern void ospf_del_if_params(struct ospf_if_params *); extern void ospf_free_if_params(struct interface *, struct in_addr); extern void ospf_if_update_params(struct interface *, struct in_addr); @@ -329,10 +338,12 @@ extern void ospf_if_set_multicast(struct ospf_interface *); extern void ospf_if_interface(struct interface *ifp); -DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd)) -DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd)) +extern uint32_t ospf_if_count_area_params(struct interface *ifp); -DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)) -DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)) +DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd)); +DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd)); + +DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp)); +DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp)); #endif /* _ZEBRA_OSPF_INTERFACE_H */ diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 36e97f8779..1850d946b8 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -45,7 +45,7 @@ DEFINE_HOOK(ospf_ism_change, (struct ospf_interface * oi, int state, int oldstate), - (oi, state, oldstate)) + (oi, state, oldstate)); /* elect DR and BDR. Refer to RFC2319 section 9.4 */ static struct ospf_neighbor *ospf_dr_election_sub(struct list *routers) diff --git a/ospfd/ospf_ism.h b/ospfd/ospf_ism.h index c41ba6c843..5d0f95aed1 100644 --- a/ospfd/ospf_ism.h +++ b/ospfd/ospf_ism.h @@ -97,6 +97,6 @@ extern int ospf_dr_election(struct ospf_interface *oi); DECLARE_HOOK(ospf_ism_change, (struct ospf_interface * oi, int state, int oldstate), - (oi, state, oldstate)) + (oi, state, oldstate)); #endif /* _ZEBRA_OSPF_ISM_H */ diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 6bde5467b2..cb1c565d37 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -1765,7 +1765,14 @@ static struct ospf_lsa *ospf_lsa_translated_nssa_new(struct ospf *ospf, /* copy over Type-7 data to new */ extnew->e[0].tos = ext->e[0].tos; extnew->e[0].route_tag = ext->e[0].route_tag; - extnew->e[0].fwd_addr.s_addr = ext->e[0].fwd_addr.s_addr; + if (type7->area->suppress_fa) { + extnew->e[0].fwd_addr.s_addr = 0; + if (IS_DEBUG_OSPF_NSSA) + zlog_debug( + "ospf_lsa_translated_nssa_new(): Suppress forwarding address for %pI4", + &ei.p.prefix); + } else + extnew->e[0].fwd_addr.s_addr = ext->e[0].fwd_addr.s_addr; new->data->ls_seqnum = type7->data->ls_seqnum; /* add translated flag, checksum and lock new lsa */ @@ -1777,7 +1784,8 @@ static struct ospf_lsa *ospf_lsa_translated_nssa_new(struct ospf *ospf, /* Originate Translated Type-5 for supplied Type-7 NSSA LSA */ struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf, - struct ospf_lsa *type7) + struct ospf_lsa *type7, + struct ospf_lsa *type5) { struct ospf_lsa *new; struct as_external_lsa *extnew; @@ -1796,6 +1804,10 @@ struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf, extnew = (struct as_external_lsa *)new->data; + /* Update LSA sequence number from translated Type-5 LSA */ + if (type5) + new->data->ls_seqnum = lsa_seqnum_increment(type5); + if ((new = ospf_lsa_install(ospf, NULL, new)) == NULL) { flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, "%s: Could not install LSA id %pI4", __func__, @@ -1823,6 +1835,8 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, struct ospf_lsa *type5) { struct ospf_lsa *new = NULL; + struct as_external_lsa *extold = NULL; + uint32_t ls_seqnum = 0; /* Sanity checks. */ assert(type7 || type5); @@ -1887,6 +1901,12 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, return NULL; } + extold = (struct as_external_lsa *)type5->data; + if (type7->area->suppress_fa == 1) { + if (extold->e[0].fwd_addr.s_addr == 0) + ls_seqnum = ntohl(type5->data->ls_seqnum); + } + /* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_as(ospf, type5); @@ -1899,6 +1919,11 @@ struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, return NULL; } + if (type7->area->suppress_fa == 1) { + if (extold->e[0].fwd_addr.s_addr == 0) + new->data->ls_seqnum = htonl(ls_seqnum + 1); + } + if (!(new = ospf_lsa_install(ospf, NULL, new))) { flog_warn( EC_OSPF_LSA_INSTALL_FAILURE, diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index f2a0d36e7e..3c1f94e628 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -341,11 +341,12 @@ extern char link_info_set(struct stream **s, struct in_addr id, extern struct in_addr ospf_get_nssa_ip(struct ospf_area *); extern int ospf_translated_nssa_compare(struct ospf_lsa *, struct ospf_lsa *); -extern struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *, - struct ospf_lsa *, - struct ospf_lsa *); -extern struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *, - struct ospf_lsa *); +extern struct ospf_lsa *ospf_translated_nssa_refresh(struct ospf *ospf, + struct ospf_lsa *type7, + struct ospf_lsa *type5); +extern struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf, + struct ospf_lsa *type7, + struct ospf_lsa *type5); extern void ospf_flush_lsa_from_area(struct ospf *ospf, struct in_addr area_id, int type); #endif /* _ZEBRA_OSPF_LSA_H */ diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 6a90dbff11..91ba3044fe 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -22,6 +22,7 @@ #include <zebra.h> #include <lib/version.h> +#include "bfd.h" #include "getopt.h" #include "thread.h" #include "prefix.h" @@ -55,6 +56,7 @@ #include "ospfd/ospf_bfd.h" #include "ospfd/ospf_errors.h" #include "ospfd/ospf_ldp_sync.h" +#include "ospfd/ospf_routemap_nb.h" /* ospfd privileges */ zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, @@ -98,6 +100,7 @@ static void sighup(void) static void sigint(void) { zlog_notice("Terminating on signal"); + bfd_protocol_integration_set_shutdown(true); ospf_terminate(); exit(0); } @@ -132,6 +135,7 @@ static const struct frr_yang_module_info *const ospfd_yang_modules[] = { &frr_interface_info, &frr_route_map_info, &frr_vrf_info, + &frr_ospf_route_map_info, }; FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT, @@ -141,7 +145,8 @@ FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT, .signals = ospf_signals, .n_signals = array_size(ospf_signals), .privs = &ospfd_privs, .yang_modules = ospfd_yang_modules, - .n_yang_modules = array_size(ospfd_yang_modules), ) + .n_yang_modules = array_size(ospfd_yang_modules), +); /* OSPFd main routine. */ int main(int argc, char **argv) @@ -213,7 +218,7 @@ int main(int argc, char **argv) ospf_vty_clear_init(); /* OSPF BFD init */ - ospf_bfd_init(); + ospf_bfd_init(master); /* OSPF LDP IGP Sync init */ ospf_ldp_sync_init(); diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index f4fb68cbdf..2838443892 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -25,38 +25,38 @@ #include "ospf_memory.h" -DEFINE_MGROUP(OSPFD, "ospfd") -DEFINE_MTYPE(OSPFD, OSPF_TOP, "OSPF top") -DEFINE_MTYPE(OSPFD, OSPF_AREA, "OSPF area") -DEFINE_MTYPE(OSPFD, OSPF_AREA_RANGE, "OSPF area range") -DEFINE_MTYPE(OSPFD, OSPF_NETWORK, "OSPF network") -DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR_STATIC, "OSPF static nbr") -DEFINE_MTYPE(OSPFD, OSPF_IF, "OSPF interface") -DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR, "OSPF neighbor") -DEFINE_MTYPE(OSPFD, OSPF_ROUTE, "OSPF route") -DEFINE_MTYPE(OSPFD, OSPF_TMP, "OSPF tmp mem") -DEFINE_MTYPE(OSPFD, OSPF_LSA, "OSPF LSA") -DEFINE_MTYPE(OSPFD, OSPF_LSA_DATA, "OSPF LSA data") -DEFINE_MTYPE(OSPFD, OSPF_LSDB, "OSPF LSDB") -DEFINE_MTYPE(OSPFD, OSPF_PACKET, "OSPF packet") -DEFINE_MTYPE(OSPFD, OSPF_FIFO, "OSPF FIFO queue") -DEFINE_MTYPE(OSPFD, OSPF_VERTEX, "OSPF vertex") -DEFINE_MTYPE(OSPFD, OSPF_VERTEX_PARENT, "OSPF vertex parent") -DEFINE_MTYPE(OSPFD, OSPF_NEXTHOP, "OSPF nexthop") -DEFINE_MTYPE(OSPFD, OSPF_PATH, "OSPF path") -DEFINE_MTYPE(OSPFD, OSPF_VL_DATA, "OSPF VL data") -DEFINE_MTYPE(OSPFD, OSPF_CRYPT_KEY, "OSPF crypt key") -DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_INFO, "OSPF ext. info") -DEFINE_MTYPE(OSPFD, OSPF_DISTANCE, "OSPF distance") -DEFINE_MTYPE(OSPFD, OSPF_IF_INFO, "OSPF if info") -DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params") -DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message") -DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters") -DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters") -DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters") -DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters") -DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters") -DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper") -DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation") -DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space") -DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space") +DEFINE_MGROUP(OSPFD, "ospfd"); +DEFINE_MTYPE(OSPFD, OSPF_TOP, "OSPF top"); +DEFINE_MTYPE(OSPFD, OSPF_AREA, "OSPF area"); +DEFINE_MTYPE(OSPFD, OSPF_AREA_RANGE, "OSPF area range"); +DEFINE_MTYPE(OSPFD, OSPF_NETWORK, "OSPF network"); +DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR_STATIC, "OSPF static nbr"); +DEFINE_MTYPE(OSPFD, OSPF_IF, "OSPF interface"); +DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR, "OSPF neighbor"); +DEFINE_MTYPE(OSPFD, OSPF_ROUTE, "OSPF route"); +DEFINE_MTYPE(OSPFD, OSPF_TMP, "OSPF tmp mem"); +DEFINE_MTYPE(OSPFD, OSPF_LSA, "OSPF LSA"); +DEFINE_MTYPE(OSPFD, OSPF_LSA_DATA, "OSPF LSA data"); +DEFINE_MTYPE(OSPFD, OSPF_LSDB, "OSPF LSDB"); +DEFINE_MTYPE(OSPFD, OSPF_PACKET, "OSPF packet"); +DEFINE_MTYPE(OSPFD, OSPF_FIFO, "OSPF FIFO queue"); +DEFINE_MTYPE(OSPFD, OSPF_VERTEX, "OSPF vertex"); +DEFINE_MTYPE(OSPFD, OSPF_VERTEX_PARENT, "OSPF vertex parent"); +DEFINE_MTYPE(OSPFD, OSPF_NEXTHOP, "OSPF nexthop"); +DEFINE_MTYPE(OSPFD, OSPF_PATH, "OSPF path"); +DEFINE_MTYPE(OSPFD, OSPF_VL_DATA, "OSPF VL data"); +DEFINE_MTYPE(OSPFD, OSPF_CRYPT_KEY, "OSPF crypt key"); +DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_INFO, "OSPF ext. info"); +DEFINE_MTYPE(OSPFD, OSPF_DISTANCE, "OSPF distance"); +DEFINE_MTYPE(OSPFD, OSPF_IF_INFO, "OSPF if info"); +DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params"); +DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message"); +DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters"); +DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters"); +DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters"); +DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters"); +DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters"); +DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper"); +DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation"); +DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space"); +DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space"); diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index 42bc8d7b77..9bd0a844af 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -24,40 +24,40 @@ #include "memory.h" -DECLARE_MGROUP(OSPFD) -DECLARE_MTYPE(OSPF_TOP) -DECLARE_MTYPE(OSPF_AREA) -DECLARE_MTYPE(OSPF_AREA_RANGE) -DECLARE_MTYPE(OSPF_NETWORK) -DECLARE_MTYPE(OSPF_NEIGHBOR_STATIC) -DECLARE_MTYPE(OSPF_IF) -DECLARE_MTYPE(OSPF_NEIGHBOR) -DECLARE_MTYPE(OSPF_ROUTE) -DECLARE_MTYPE(OSPF_TMP) -DECLARE_MTYPE(OSPF_LSA) -DECLARE_MTYPE(OSPF_LSA_DATA) -DECLARE_MTYPE(OSPF_LSDB) -DECLARE_MTYPE(OSPF_PACKET) -DECLARE_MTYPE(OSPF_FIFO) -DECLARE_MTYPE(OSPF_VERTEX) -DECLARE_MTYPE(OSPF_VERTEX_PARENT) -DECLARE_MTYPE(OSPF_NEXTHOP) -DECLARE_MTYPE(OSPF_PATH) -DECLARE_MTYPE(OSPF_VL_DATA) -DECLARE_MTYPE(OSPF_CRYPT_KEY) -DECLARE_MTYPE(OSPF_EXTERNAL_INFO) -DECLARE_MTYPE(OSPF_DISTANCE) -DECLARE_MTYPE(OSPF_IF_INFO) -DECLARE_MTYPE(OSPF_IF_PARAMS) -DECLARE_MTYPE(OSPF_MESSAGE) -DECLARE_MTYPE(OSPF_MPLS_TE) -DECLARE_MTYPE(OSPF_ROUTER_INFO) -DECLARE_MTYPE(OSPF_PCE_PARAMS) -DECLARE_MTYPE(OSPF_SR_PARAMS) -DECLARE_MTYPE(OSPF_EXT_PARAMS) -DECLARE_MTYPE(OSPF_GR_HELPER) -DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR) -DECLARE_MTYPE(OSPF_P_SPACE) -DECLARE_MTYPE(OSPF_Q_SPACE) +DECLARE_MGROUP(OSPFD); +DECLARE_MTYPE(OSPF_TOP); +DECLARE_MTYPE(OSPF_AREA); +DECLARE_MTYPE(OSPF_AREA_RANGE); +DECLARE_MTYPE(OSPF_NETWORK); +DECLARE_MTYPE(OSPF_NEIGHBOR_STATIC); +DECLARE_MTYPE(OSPF_IF); +DECLARE_MTYPE(OSPF_NEIGHBOR); +DECLARE_MTYPE(OSPF_ROUTE); +DECLARE_MTYPE(OSPF_TMP); +DECLARE_MTYPE(OSPF_LSA); +DECLARE_MTYPE(OSPF_LSA_DATA); +DECLARE_MTYPE(OSPF_LSDB); +DECLARE_MTYPE(OSPF_PACKET); +DECLARE_MTYPE(OSPF_FIFO); +DECLARE_MTYPE(OSPF_VERTEX); +DECLARE_MTYPE(OSPF_VERTEX_PARENT); +DECLARE_MTYPE(OSPF_NEXTHOP); +DECLARE_MTYPE(OSPF_PATH); +DECLARE_MTYPE(OSPF_VL_DATA); +DECLARE_MTYPE(OSPF_CRYPT_KEY); +DECLARE_MTYPE(OSPF_EXTERNAL_INFO); +DECLARE_MTYPE(OSPF_DISTANCE); +DECLARE_MTYPE(OSPF_IF_INFO); +DECLARE_MTYPE(OSPF_IF_PARAMS); +DECLARE_MTYPE(OSPF_MESSAGE); +DECLARE_MTYPE(OSPF_MPLS_TE); +DECLARE_MTYPE(OSPF_ROUTER_INFO); +DECLARE_MTYPE(OSPF_PCE_PARAMS); +DECLARE_MTYPE(OSPF_SR_PARAMS); +DECLARE_MTYPE(OSPF_EXT_PARAMS); +DECLARE_MTYPE(OSPF_GR_HELPER); +DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR); +DECLARE_MTYPE(OSPF_P_SPACE); +DECLARE_MTYPE(OSPF_Q_SPACE); #endif /* _QUAGGA_OSPF_MEMORY_H */ diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index 2fa43923ab..a1b35b2fcd 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -21,6 +21,7 @@ #include <zebra.h> +#include "lib/bfd.h" #include "linklist.h" #include "prefix.h" #include "memory.h" @@ -99,8 +100,6 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->crypt_seqnum = 0; - ospf_bfd_info_nbr_create(oi, nbr); - /* Initialize GR Helper info*/ nbr->gr_helper_info.recvd_grace_period = 0; nbr->gr_helper_info.actual_grace_period = 0; @@ -149,7 +148,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) /* Cancel all events. */ /* Thread lookup cost would be negligible. */ thread_cancel_event(master, nbr); - ospf_bfd_info_free(&nbr->bfd_info); + bfd_sess_free(&nbr->bfd_session); OSPF_NSM_TIMER_OFF(nbr->gr_helper_info.t_grace_timer); @@ -458,6 +457,9 @@ static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi, if (ntohs(ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC) nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; + /* Configure BFD if interface has it. */ + ospf_neighbor_bfd_apply(nbr); + if (IS_DEBUG_OSPF_EVENT) zlog_debug("NSM[%s:%pI4]: start", IF_NAME(oi), &nbr->router_id); diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 758693e289..2ce6d6755c 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -88,7 +88,7 @@ struct ospf_neighbor { uint32_t state_change; /* NSM state change counter */ /* BFD information */ - void *bfd_info; + struct bfd_session_params *bfd_session; /* ospf graceful restart HELPER info */ struct ospf_helper_info gr_helper_info; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 26e7855e8c..006c4888ae 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -53,7 +53,7 @@ DEFINE_HOOK(ospf_nsm_change, (struct ospf_neighbor * on, int state, int oldstate), - (on, state, oldstate)) + (on, state, oldstate)); static void nsm_clear_adj(struct ospf_neighbor *); @@ -761,7 +761,8 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) if (state == NSM_Down) nbr->crypt_seqnum = 0; - ospf_bfd_trigger_event(nbr, old_state, state); + if (nbr->bfd_session) + ospf_bfd_trigger_event(nbr, old_state, state); /* Preserve old status? */ } diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h index 24cf05009c..e8573c6301 100644 --- a/ospfd/ospf_nsm.h +++ b/ospfd/ospf_nsm.h @@ -78,6 +78,6 @@ extern void ospf_db_summary_clear(struct ospf_neighbor *); extern int nsm_should_adj(struct ospf_neighbor *nbr); DECLARE_HOOK(ospf_nsm_change, (struct ospf_neighbor * on, int state, int oldstate), - (on, state, oldstate)) + (on, state, oldstate)); #endif /* _ZEBRA_OSPF_NSM_H */ diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 3939b5479f..ae9ab48d4a 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -56,9 +56,9 @@ #include "ospfd/ospf_ext.h" #include "ospfd/ospf_errors.h" -DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table") -DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info") -DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info") +DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table"); +DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info"); +DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info"); /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for Opaque-LSAs handling. diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index bdc65d23bf..d3b114840e 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -33,6 +33,7 @@ #include "plist.h" #include "vrf.h" #include "frrstr.h" +#include "northbound_cli.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" @@ -534,7 +535,7 @@ static const struct route_map_rule_cmd route_set_tag_cmd = { route_map_rule_tag_free, }; -DEFUN (set_metric_type, +DEFUN_YANG (set_metric_type, set_metric_type_cmd, "set metric-type <type-1|type-2>", SET_STR @@ -543,11 +544,19 @@ DEFUN (set_metric_type, "OSPF[6] external type 2 metric\n") { char *ext = argv[2]->text; - return generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), - "metric-type", ext); + + const char *xpath = + "./set-action[action='frr-ospf-route-map:metric-type']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-ospf-route-map:metric-type", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, ext); + return nb_cli_apply_changes(vty, NULL); } -DEFUN (no_set_metric_type, +DEFUN_YANG (no_set_metric_type, no_set_metric_type_cmd, "no set metric-type [<type-1|type-2>]", NO_STR @@ -556,9 +565,11 @@ DEFUN (no_set_metric_type, "OSPF[6] external type 1 metric\n" "OSPF[6] external type 2 metric\n") { - char *ext = (argc == 4) ? argv[3]->text : NULL; - return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), - "metric-type", ext); + const char *xpath = + "./set-action[action='frr-ospf-route-map:metric-type']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); } /* Route-map init */ diff --git a/pathd/path_memory.c b/ospfd/ospf_routemap_nb.c index ad4904a298..1f6b0ef78c 100644 --- a/pathd/path_memory.c +++ b/ospfd/ospf_routemap_nb.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2020 NetDEF, Inc. + * Copyright (C) 2020 Vmware + * Sarita Patra * * 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 @@ -16,10 +17,23 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <zebra.h> +#include "lib/northbound.h" +#include "lib/routemap.h" +#include "ospf_routemap_nb.h" -#include <memory.h> - -#include "pathd/path_memory.h" - -DEFINE_MGROUP(PATHD, "pathd") +/* clang-format off */ +const struct frr_yang_module_info frr_ospf_route_map_info = { + .name = "frr-ospf-route-map", + .nodes = { + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-ospf-route-map:metric-type", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_metric_type_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_metric_type_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/staticd/static_memory.h b/ospfd/ospf_routemap_nb.h index 077cd0f32b..17bcb4f5c3 100644 --- a/staticd/static_memory.h +++ b/ospfd/ospf_routemap_nb.h @@ -1,7 +1,6 @@ /* - * static memory code. - * Copyright (C) 2018 Cumulus Networks, Inc. - * Donald Sharp + * Copyright (C) 2020 Vmware + * Sarita Patra * * 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 @@ -17,14 +16,22 @@ * 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 __STATIC_MEMORY_H__ -#include "memory.h" +#ifndef _FRR_OSPF_ROUTEMAP_NB_H_ +#define _FRR_OSPF_ROUTEMAP_NB_H_ -DECLARE_MGROUP(STATIC) +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct frr_yang_module_info frr_ospf_route_map_info; -DECLARE_MTYPE(STATIC_ROUTE); -DECLARE_MTYPE(STATIC_NEXTHOP); -DECLARE_MTYPE(STATIC_PATH); +/* prototypes */ +int lib_route_map_entry_set_action_rmap_set_action_metric_type_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_metric_type_destroy(struct nb_cb_destroy_args *args); + +#ifdef __cplusplus +} +#endif #endif diff --git a/ospfd/ospf_routemap_nb_config.c b/ospfd/ospf_routemap_nb_config.c new file mode 100644 index 0000000000..bfb18c5e08 --- /dev/null +++ b/ospfd/ospf_routemap_nb_config.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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 "lib/command.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/routemap.h" +#include "ospf_routemap_nb.h" + +/* + * XPath: + * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-ospf-route-map:metric-type + */ +int lib_route_map_entry_set_action_rmap_set_action_metric_type_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "metric-type"; + rhc->rhc_event = RMAP_EVENT_SET_DELETED; + + rv = generic_set_add(rhc->rhc_rmi, "metric-type", type, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_metric_type_destroy( + struct nb_cb_destroy_args *args) +{ + return lib_route_map_entry_set_destroy(args); +} diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 3f4ca44b05..43b998ac5b 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -674,7 +674,7 @@ static struct ospf_area *ospfAreaLookup(struct variable *v, oid name[], if (area == NULL) return NULL; - oid_copy_addr(name + v->namelen, addr, sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, addr); *length = sizeof(struct in_addr) + v->namelen; return area; @@ -800,7 +800,7 @@ static struct ospf_area *ospfStubAreaLookup(struct variable *v, oid name[], if (area == NULL) return NULL; - oid_copy_addr(name + v->namelen, addr, sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, addr); /* Set TOS 0. */ name[v->namelen + sizeof(struct in_addr)] = 0; *length = v->namelen + sizeof(struct in_addr) + 1; @@ -1008,15 +1008,14 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name, /* Fill in value. */ offset = name + v->namelen; - oid_copy_addr(offset, area_id, IN_ADDR_SIZE); + oid_copy_in_addr(offset, area_id); offset += IN_ADDR_SIZE; *offset = lsa->data->type; offset++; - oid_copy_addr(offset, &lsa->data->id, - IN_ADDR_SIZE); + oid_copy_in_addr(offset, &lsa->data->id); offset += IN_ADDR_SIZE; - oid_copy_addr(offset, &lsa->data->adv_router, - IN_ADDR_SIZE); + oid_copy_in_addr(offset, + &lsa->data->adv_router); return lsa; } @@ -1170,9 +1169,9 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v, /* Fill in value. */ offset = name + v->namelen; - oid_copy_addr(offset, area_id, IN_ADDR_SIZE); + oid_copy_in_addr(offset, area_id); offset += IN_ADDR_SIZE; - oid_copy_addr(offset, range_net, IN_ADDR_SIZE); + oid_copy_in_addr(offset, range_net); return range; } @@ -1573,7 +1572,7 @@ static struct ospf_interface *ospfIfLookup(struct variable *v, oid *name, if (oi) { *length = v->namelen + IN_ADDR_SIZE + 1; offset = name + v->namelen; - oid_copy_addr(offset, ifaddr, IN_ADDR_SIZE); + oid_copy_in_addr(offset, ifaddr); offset += IN_ADDR_SIZE; *offset = *ifindex; return oi; @@ -1717,7 +1716,7 @@ static struct ospf_interface *ospfIfMetricLookup(struct variable *v, oid *name, if (oi) { *length = v->namelen + IN_ADDR_SIZE + 1 + 1; offset = name + v->namelen; - oid_copy_addr(offset, ifaddr, IN_ADDR_SIZE); + oid_copy_in_addr(offset, ifaddr); offset += IN_ADDR_SIZE; *offset = *ifindex; offset++; @@ -1906,9 +1905,9 @@ ospfVirtIfLookup(struct variable *v, oid *name, size_t *length, if (vl_data) { *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; - oid_copy_addr(name + v->namelen, area_id, IN_ADDR_SIZE); - oid_copy_addr(name + v->namelen + IN_ADDR_SIZE, - neighbor, IN_ADDR_SIZE); + oid_copy_in_addr(name + v->namelen, area_id); + oid_copy_in_addr(name + v->namelen + IN_ADDR_SIZE, + neighbor); return vl_data; } } @@ -2083,8 +2082,7 @@ static struct ospf_neighbor *ospfNbrLookup(struct variable *v, oid *name, if (nbr) { *length = v->namelen + IN_ADDR_SIZE + 1; - oid_copy_addr(name + v->namelen, nbr_addr, - IN_ADDR_SIZE); + oid_copy_in_addr(name + v->namelen, nbr_addr); name[v->namelen + IN_ADDR_SIZE] = *ifindex; return nbr; } @@ -2307,10 +2305,9 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name, *offset = OSPF_AS_EXTERNAL_LSA; offset++; - oid_copy_addr(offset, &lsa->data->id, IN_ADDR_SIZE); + oid_copy_in_addr(offset, &lsa->data->id); offset += IN_ADDR_SIZE; - oid_copy_addr(offset, &lsa->data->adv_router, - IN_ADDR_SIZE); + oid_copy_in_addr(offset, &lsa->data->adv_router); return lsa; } @@ -2440,7 +2437,7 @@ static void ospfTrapNbrStateChange(struct ospf_neighbor *on) zlog_info("%s: trap sent: %pI4 now %s", __func__, &on->address.u.prefix4, msgbuf); - oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE); + oid_copy_in_addr(index, &(on->address.u.prefix4)); index[IN_ADDR_SIZE] = 0; smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid, @@ -2455,7 +2452,7 @@ static void ospfTrapVirtNbrStateChange(struct ospf_neighbor *on) zlog_info("ospfTrapVirtNbrStateChange trap sent"); - oid_copy_addr(index, &(on->address.u.prefix4), IN_ADDR_SIZE); + oid_copy_in_addr(index, &(on->address.u.prefix4)); index[IN_ADDR_SIZE] = 0; smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid, @@ -2499,7 +2496,7 @@ static void ospfTrapIfStateChange(struct ospf_interface *oi) &oi->address->u.prefix4, lookup_msg(ospf_ism_state_msg, oi->state, NULL)); - oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE); + oid_copy_in_addr(index, &(oi->address->u.prefix4)); index[IN_ADDR_SIZE] = 0; smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid, @@ -2514,7 +2511,7 @@ static void ospfTrapVirtIfStateChange(struct ospf_interface *oi) zlog_info("ospfTrapVirtIfStateChange trap sent"); - oid_copy_addr(index, &(oi->address->u.prefix4), IN_ADDR_SIZE); + oid_copy_in_addr(index, &(oi->address->u.prefix4)); index[IN_ADDR_SIZE] = 0; smux_trap(ospf_variables, array_size(ospf_variables), ospf_trap_oid, @@ -2565,4 +2562,5 @@ static int ospf_snmp_module_init(void) FRR_MODULE_SETUP(.name = "ospfd_snmp", .version = FRR_VERSION, .description = "ospfd AgentX SNMP module", - .init = ospf_snmp_module_init, ) + .init = ospf_snmp_module_init, +); diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 6cd6a47098..95553dacdf 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -89,7 +89,7 @@ static int vertex_cmp(const struct vertex *v1, const struct vertex *v2) } return 0; } -DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp) +DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp); static void lsdb_clean_stat(struct ospf_lsdb *lsdb) { @@ -1987,3 +1987,27 @@ void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason) thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf, delay, &ospf->t_spf_calc); } + +/* Restart OSPF SPF algorithm*/ +void ospf_restart_spf(struct ospf *ospf) +{ + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Restart SPF.", __PRETTY_FUNCTION__); + + /* Handling inter area and intra area routes*/ + if (ospf->new_table) { + ospf_route_delete(ospf, ospf->new_table); + ospf_route_table_free(ospf->new_table); + ospf->new_table = route_table_init(); + } + + /* Handling of TYPE-5 lsa(external routes) */ + if (ospf->old_external_route) { + ospf_route_delete(ospf, ospf->old_external_route); + ospf_route_table_free(ospf->old_external_route); + ospf->old_external_route = route_table_init(); + } + + /* Trigger SPF */ + ospf_spf_calculate_schedule(ospf, SPF_FLAG_CONFIG_CHANGE); +} diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h index 66555be4b7..4ff4a6d125 100644 --- a/ospfd/ospf_spf.h +++ b/ospfd/ospf_spf.h @@ -33,7 +33,7 @@ /* The "root" is the node running the SPF calculation */ -PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue) +PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue); /* A router or network in an area */ struct vertex { struct vertex_pqueue_item pqi; @@ -98,6 +98,6 @@ extern struct vertex_parent *ospf_spf_vertex_parent_find(struct in_addr id, extern int vertex_parent_cmp(void *aa, void *bb); extern void ospf_spf_print(struct vty *vty, struct vertex *v, int i); - +extern void ospf_restart_spf(struct ospf *ospf); /* void ospf_spf_calculate_timer_add (); */ #endif /* _QUAGGA_OSPF_SPF_H */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 17ff9a1a46..f2842538a5 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -43,6 +43,9 @@ #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "network.h" +#include "link_state.h" +#include "zclient.h" +#include "printfrr.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -60,6 +63,9 @@ #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_te.h" +#include "ospfd/ospf_sr.h" +#include "ospfd/ospf_ri.h" +#include "ospfd/ospf_ext.h" #include "ospfd/ospf_vty.h" #include "ospfd/ospf_errors.h" @@ -71,6 +77,7 @@ struct ospf_mpls_te OspfMplsTE; static const char *const mode2text[] = {"Off", "AS", "Area"}; + /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for MPLS-TE handling. *------------------------------------------------------------------------*/ @@ -82,8 +89,11 @@ static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_status); static void ospf_mpls_te_config_write_router(struct vty *vty); static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa); static int ospf_mpls_te_lsa_originate_area(void *arg); -static int ospf_mpls_te_lsa_originate_as(void *arg); +static int ospf_mpls_te_lsa_inter_as_as(void *arg); +static int ospf_mpls_te_lsa_inter_as_area(void *arg); static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa); +static int ospf_mpls_te_lsa_update(struct ospf_lsa *lsa); +static int ospf_mpls_te_lsa_delete(struct ospf_lsa *lsa); static void del_mpls_te_link(void *val); static void ospf_mpls_te_register_vty(void); @@ -92,79 +102,72 @@ int ospf_mpls_te_init(void) { int rc; + /* Register Opaque AREA LSA Type 1 for Traffic Engineering */ rc = ospf_register_opaque_functab( - OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, - ospf_mpls_te_new_if, ospf_mpls_te_del_if, - ospf_mpls_te_ism_change, ospf_mpls_te_nsm_change, + OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, + ospf_mpls_te_new_if, + ospf_mpls_te_del_if, + ospf_mpls_te_ism_change, + ospf_mpls_te_nsm_change, ospf_mpls_te_config_write_router, - NULL, /*ospf_mpls_te_config_write_if */ + NULL, /* ospf_mpls_te_config_write_if */ NULL, /* ospf_mpls_te_config_write_debug */ ospf_mpls_te_show_info, ospf_mpls_te_lsa_originate_area, - ospf_mpls_te_lsa_refresh, NULL, /* ospf_mpls_te_new_lsa_hook */ - NULL /* ospf_mpls_te_del_lsa_hook */); + ospf_mpls_te_lsa_refresh, + ospf_mpls_te_lsa_update, /* ospf_mpls_te_new_lsa_hook */ + ospf_mpls_te_lsa_delete /* ospf_mpls_te_del_lsa_hook */); if (rc != 0) { flog_warn( EC_OSPF_OPAQUE_REGISTRATION, - "ospf_mpls_te_init: Failed to register Traffic Engineering functions"); + "MPLS-TE (%s): Failed to register Traffic Engineering functions", + __func__); return rc; } - memset(&OspfMplsTE, 0, sizeof(struct ospf_mpls_te)); - OspfMplsTE.enabled = false; - OspfMplsTE.inter_as = Off; - OspfMplsTE.iflist = list_new(); - OspfMplsTE.iflist->del = del_mpls_te_link; - - ospf_mpls_te_register_vty(); - - return rc; -} - -/* Additional register for RFC5392 support */ -static int ospf_mpls_te_register(enum inter_as_mode mode) -{ - int rc = 0; - uint8_t scope; - - if (OspfMplsTE.inter_as != Off) + /* + * Wee need also to register Opaque LSA Type 6 i.e. Inter-AS RFC5392 for + * both AREA and AS at least to have the possibility to call the show() + * function when looking to the opaque LSA of the OSPF database. + */ + rc = ospf_register_opaque_functab(OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_INTER_AS_LSA, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + ospf_mpls_te_show_info, + ospf_mpls_te_lsa_inter_as_area, + ospf_mpls_te_lsa_refresh, NULL, NULL); + if (rc != 0) { + flog_warn( + EC_OSPF_OPAQUE_REGISTRATION, + "MPLS-TE (%s): Failed to register Inter-AS with Area scope", + __func__); return rc; + } - if (mode == AS) - scope = OSPF_OPAQUE_AS_LSA; - else - scope = OSPF_OPAQUE_AREA_LSA; - - rc = ospf_register_opaque_functab(scope, OPAQUE_TYPE_INTER_AS_LSA, NULL, + rc = ospf_register_opaque_functab(OSPF_OPAQUE_AS_LSA, + OPAQUE_TYPE_INTER_AS_LSA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ospf_mpls_te_show_info, - ospf_mpls_te_lsa_originate_as, + ospf_mpls_te_lsa_inter_as_as, ospf_mpls_te_lsa_refresh, NULL, NULL); - if (rc != 0) { flog_warn( EC_OSPF_OPAQUE_REGISTRATION, - "ospf_router_info_init: Failed to register Inter-AS functions"); + "MPLS-TE (%s): Failed to register Inter-AS with AS scope", + __func__); return rc; } - return rc; -} - -static int ospf_mpls_te_unregister(void) -{ - uint8_t scope; - - if (OspfMplsTE.inter_as == Off) - return 0; - - if (OspfMplsTE.inter_as == AS) - scope = OSPF_OPAQUE_AS_LSA; - else - scope = OSPF_OPAQUE_AREA_LSA; + memset(&OspfMplsTE, 0, sizeof(struct ospf_mpls_te)); + OspfMplsTE.enabled = false; + OspfMplsTE.export = false; + OspfMplsTE.inter_as = Off; + OspfMplsTE.iflist = list_new(); + OspfMplsTE.iflist->del = del_mpls_te_link; - ospf_delete_opaque_functab(scope, OPAQUE_TYPE_INTER_AS_LSA); + ospf_mpls_te_register_vty(); - return 0; + return rc; } void ospf_mpls_te_term(void) @@ -173,28 +176,28 @@ void ospf_mpls_te_term(void) ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); + ospf_delete_opaque_functab(OSPF_OPAQUE_AREA_LSA, + OPAQUE_TYPE_INTER_AS_LSA); + ospf_delete_opaque_functab(OSPF_OPAQUE_AS_LSA, + OPAQUE_TYPE_INTER_AS_LSA); OspfMplsTE.enabled = false; - - ospf_mpls_te_unregister(); OspfMplsTE.inter_as = Off; + OspfMplsTE.export = false; return; } void ospf_mpls_te_finish(void) { - // list_delete_all_node(OspfMplsTE.iflist); - OspfMplsTE.enabled = false; - ospf_mpls_te_unregister(); OspfMplsTE.inter_as = Off; + OspfMplsTE.export = false; } /*------------------------------------------------------------------------* * Followings are control functions for MPLS-TE parameters management. *------------------------------------------------------------------------*/ - static void del_mpls_te_link(void *val) { XFREE(MTYPE_OSPF_MPLS_TE, val); @@ -235,8 +238,7 @@ static struct mpls_te_link *lookup_linkparams_by_instance(struct ospf_lsa *lsa) if (lp->instance == key) return lp; - zlog_info("lookup_linkparams_by_instance: Entry not found: key(%x)", - key); + ote_debug("MPLS-TE (%s): Entry not found: key(%x)", __func__, key); return NULL; } @@ -484,6 +486,13 @@ static void set_linkparams_inter_as(struct mpls_te_link *lp, lp->ras.header.type = htons(TE_LINK_SUBTLV_RAS); lp->ras.header.length = htons(TE_LINK_SUBTLV_DEF_SIZE); lp->ras.value = htonl(as); + + /* Set Type & Flooding flag accordingly */ + lp->type = INTER_AS; + if (OspfMplsTE.inter_as == AS) + SET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); + else + UNSET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); } static void unset_linkparams_inter_as(struct mpls_te_link *lp) @@ -497,6 +506,10 @@ static void unset_linkparams_inter_as(struct mpls_te_link *lp) lp->ras.header.type = htons(0); lp->ras.header.length = htons(0); lp->ras.value = htonl(0); + + /* Reset Type & Flooding flag accordingly */ + lp->type = STD_TE; + UNSET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); } void set_linkparams_llri(struct mpls_te_link *lp, uint32_t local, @@ -606,15 +619,15 @@ static void update_linkparams(struct mpls_te_link *lp) /* Get the Interface structure */ if ((ifp = lp->ifp) == NULL) { - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "OSPF MPLS-TE: Abort update TE parameters: no interface associated to Link Parameters"); + ote_debug( + "MPLS-TE (%s): Abort update TE parameters: no interface associated to Link Parameters", + __func__); return; } if (!HAS_LINK_PARAMS(ifp)) { - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "OSPF MPLS-TE: Abort update TE parameters: no Link Parameters for interface"); + ote_debug( + "MPLS-TE (%s): Abort update TE parameters: no Link Parameters for interface", + __func__); return; } @@ -688,17 +701,18 @@ static void update_linkparams(struct mpls_te_link *lp) /* Flush LSA if it engaged and was previously a STD_TE one */ if (IS_STD_TE(lp->type) && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "OSPF MPLS-TE Update IF: Switch from Standard LSA to INTER-AS for %s[%d/%d]", - ifp->name, lp->flags, lp->type); + ote_debug( + "MPLS-TE (%s): Update IF: Switch from Standard LSA to INTER-AS for %s[%d/%d]", + __func__, ifp->name, lp->flags, lp->type); ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); /* Then, switch it to INTER-AS */ - if (OspfMplsTE.inter_as == AS) - lp->flags = INTER_AS | FLOOD_AS; - else { - lp->flags = INTER_AS | FLOOD_AREA; + if (OspfMplsTE.inter_as == AS) { + lp->type = INTER_AS; + SET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); + } else { + lp->type = INTER_AS; + UNSET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); lp->area = ospf_area_lookup_by_area_id( ospf_lookup_by_vrf_id(VRF_DEFAULT), OspfMplsTE.interas_areaid); @@ -707,10 +721,9 @@ static void update_linkparams(struct mpls_te_link *lp) set_linkparams_inter_as(lp, ifp->link_params->rmt_ip, ifp->link_params->rmt_as); } else { - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "OSPF MPLS-TE Update IF: Switch from INTER-AS LSA to Standard for %s[%d/%d]", - ifp->name, lp->flags, lp->type); + ote_debug( + "MPLS-TE (%s): Update IF: Switch from INTER-AS LSA to Standard for %s[%d/%d]", + __func__, ifp->name, lp->flags, lp->type); /* reset inter-as TE params */ /* Flush LSA if it engaged and was previously an INTER_AS one */ @@ -718,7 +731,8 @@ static void update_linkparams(struct mpls_te_link *lp) && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); /* Then, switch it to Standard TE */ - lp->flags = STD_TE | FLOOD_AREA; + lp->flags = STD_TE; + UNSET_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS); } unset_linkparams_inter_as(lp); } @@ -730,10 +744,8 @@ static void initialize_linkparams(struct mpls_te_link *lp) struct ospf_interface *oi = NULL; struct route_node *rn; - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "MPLS-TE(initialize_linkparams) Initialize Link Parameters for interface %s", - ifp->name); + ote_debug("MPLS-TE (%s): Initialize Link Parameters for interface %s", + __func__, ifp->name); /* Search OSPF Interface parameters for this interface */ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { @@ -746,10 +758,9 @@ static void initialize_linkparams(struct mpls_te_link *lp) } if ((oi == NULL) || (oi->ifp != ifp)) { - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "MPLS-TE(initialize_linkparams) Could not find corresponding OSPF Interface for %s", - ifp->name); + ote_debug( + "MPLS-TE (%s): Could not find corresponding OSPF Interface for %s", + __func__, ifp->name); return; } @@ -780,21 +791,20 @@ static int is_mandated_params_set(struct mpls_te_link *lp) int rc = 0; if (ntohs(OspfMplsTE.router_addr.header.type) == 0) { - flog_warn( - EC_OSPF_TE_UNEXPECTED, - "MPLS-TE(is_mandated_params_set) Missing Router Address"); + flog_warn(EC_OSPF_TE_UNEXPECTED, + "MPLS-TE (%s): Missing Router Address", __func__); return rc; } if (ntohs(lp->link_type.header.type) == 0) { flog_warn(EC_OSPF_TE_UNEXPECTED, - "MPLS-TE(is_mandated_params_set) Missing Link Type"); + "MPLS-TE (%s): Missing Link Type", __func__); return rc; } if (!IS_INTER_AS(lp->type) && (ntohs(lp->link_id.header.type) == 0)) { - flog_warn(EC_OSPF_TE_UNEXPECTED, - "MPLS-TE(is_mandated_params_set) Missing Link ID"); + flog_warn(EC_OSPF_TE_UNEXPECTED, "MPLS-TE (%s) Missing Link ID", + __func__); return rc; } @@ -810,10 +820,9 @@ static int ospf_mpls_te_new_if(struct interface *ifp) { struct mpls_te_link *new; - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "MPLS-TE(ospf_mpls_te_new_if) Add new %s interface %s to MPLS-TE list", - ifp->link_params ? "Active" : "Inactive", ifp->name); + ote_debug("MPLS-TE (%s): Add new %s interface %s to MPLS-TE list", + __func__, ifp->link_params ? "Active" : "Inactive", + ifp->name); if (lookup_linkparams_by_ifp(ifp) != NULL) return 0; @@ -826,7 +835,7 @@ static int ospf_mpls_te_new_if(struct interface *ifp) * active */ /* This default behavior will be adapted with call to * ospf_mpls_te_update_if() */ - new->type = STD_TE | FLOOD_AREA; + new->type = STD_TE; new->flags = LPFLG_LSA_INACTIVE; /* Initialize Link Parameters from Interface */ @@ -838,10 +847,8 @@ static int ospf_mpls_te_new_if(struct interface *ifp) /* Add Link Parameters structure to the list */ listnode_add(OspfMplsTE.iflist, new); - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "OSPF MPLS-TE New IF: Add new LP context for %s[%d/%d]", - ifp->name, new->flags, new->type); + ote_debug("MPLS-TE (%s): Add new LP context for %s[%d/%d]", __func__, + ifp->name, new->flags, new->type); /* Schedule Opaque-LSA refresh. */ /* XXX */ return 0; @@ -874,17 +881,15 @@ void ospf_mpls_te_update_if(struct interface *ifp) { struct mpls_te_link *lp; - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "OSPF MPLS-TE: Update LSA parameters for interface %s [%s]", - ifp->name, HAS_LINK_PARAMS(ifp) ? "ON" : "OFF"); + ote_debug("MPLS-TE (%s): Update LSA parameters for interface %s [%s]", + __func__, ifp->name, HAS_LINK_PARAMS(ifp) ? "ON" : "OFF"); /* Get Link context from interface */ if ((lp = lookup_linkparams_by_ifp(ifp)) == NULL) { flog_warn( EC_OSPF_TE_UNEXPECTED, - "OSPF MPLS-TE Update: Did not find Link Parameters context for interface %s", - ifp->name); + "MPLS-TE (%s): Did not find Link Parameters context for interface %s", + __func__, ifp->name); return; } @@ -949,9 +954,6 @@ static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_state) /* Keep Area information in combination with linkparams. */ lp->area = oi->area; - /* Keep interface MPLS-TE status */ - lp->flags = HAS_LINK_PARAMS(oi->ifp); - switch (oi->state) { case ISM_PointToPoint: case ISM_DROther: @@ -962,17 +964,22 @@ static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_state) set_linkparams_lclif_ipaddr(lp, oi->address->u.prefix4); break; - default: - /* State is undefined: Flush LSA if engaged */ - if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) + case ISM_Down: + /* Interface goes Down: Flush LSA if engaged */ + if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { + ote_debug( + "MPLS-TE (%s): Interface %s goes down: flush LSA", + __func__, IF_NAME(oi)); ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); + return; + } + break; + default: break; } - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "MPLS-TE(%s): Update Link parameters for interface %s", - __func__, IF_NAME(oi)); + ote_debug("MPLS-TE (%s): Update Link parameters for interface %s", + __func__, IF_NAME(oi)); return; } @@ -1009,12 +1016,21 @@ static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_state) return; } + /* Flush TE Opaque LSA if Neighbor State goes Down or Deleted */ + if (OspfMplsTE.enabled + && (nbr->state == NSM_Down || nbr->state == NSM_Deleted)) { + if (CHECK_FLAG(lp->flags, EXT_LPFLG_LSA_ENGAGED)) { + ote_debug( + "MPLS-TE (%s): Interface %s goes down: flush LSA", + __func__, IF_NAME(oi)); + ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); + } + return; + } + /* Keep Area information in combination with SR info. */ lp->area = oi->area; - /* Keep interface MPLS-TE status */ - lp->flags = HAS_LINK_PARAMS(oi->ifp); - /* * The Link ID is identical to the contents of the Link ID field * in the Router LSA for these link types. @@ -1034,18 +1050,22 @@ static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_state) set_linkparams_link_id(lp, DR(oi)); break; - default: - /* State is undefined: Flush LSA if engaged */ - if (OspfMplsTE.enabled && - CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) + case ISM_Down: + /* State goes Down: Flush LSA if engaged */ + if (OspfMplsTE.enabled + && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { + ote_debug( + "MPLS-TE (%s): Interface %s goes down: flush LSA", + __func__, IF_NAME(oi)); ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); + } return; + default: + break; } - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "MPLS-TE (%s): Add Link-ID %pI4 for interface %s ", - __func__, &lp->link_id.value, oi->ifp->name); + ote_debug("MPLS-TE (%s): Add Link-ID %pI4 for interface %s ", __func__, + &lp->link_id.value, oi->ifp->name); /* Try to Schedule LSA */ if (OspfMplsTE.enabled) { @@ -1058,7 +1078,7 @@ static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_state) } /*------------------------------------------------------------------------* - * Followings are OSPF protocol processing functions for MPLS-TE. + * Followings are OSPF protocol processing functions for MPLS-TE LSA. *------------------------------------------------------------------------*/ static void build_tlv_header(struct stream *s, struct tlv_header *tlvh) @@ -1119,11 +1139,12 @@ static void build_link_tlv(struct stream *s, struct mpls_te_link *lp) static void ospf_mpls_te_lsa_body_set(struct stream *s, struct mpls_te_link *lp) { /* - * The router address TLV is type 1, and ... - * It must appear in exactly one - * Traffic Engineering LSA originated by a router. + * The router address TLV is type 1, and ... It must appear in exactly + * one Traffic Engineering LSA originated by a router but not in + * Inter-AS TLV. */ - build_router_tlv(s); + if (!IS_INTER_AS(lp->type)) + build_router_tlv(s); /* * Only one Link TLV shall be carried in each LSA, allowing for fine @@ -1154,7 +1175,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf *ospf, /* Set opaque-LSA header fields depending of the type of RFC */ if (IS_INTER_AS(lp->type)) { - if (IS_FLOOD_AS(lp->type)) { + if (IS_FLOOD_AS(lp->flags)) { /* Enable AS external as we flood Inter-AS with Opaque * Type 11 */ @@ -1186,10 +1207,9 @@ static struct ospf_lsa *ospf_mpls_te_lsa_new(struct ospf *ospf, area->ospf->router_id); } - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) - zlog_debug( - "LSA[Type%d:%pI4]: Create an Opaque-LSA/MPLS-TE instance", - lsa_type, &lsa_id); + ote_debug( + "MPLS-TE (%s): LSA[Type%d:%pI4]: Create an Opaque-LSA/MPLS-TE instance", + __func__, lsa_type, &lsa_id); /* Set opaque-LSA body fields. */ ospf_mpls_te_lsa_body_set(s, lp); @@ -1221,16 +1241,15 @@ static int ospf_mpls_te_lsa_originate1(struct ospf_area *area, /* Create new Opaque-LSA/MPLS-TE instance. */ new = ospf_mpls_te_lsa_new(area->ospf, area, lp); if (new == NULL) { - flog_warn( - EC_OSPF_TE_UNEXPECTED, - "ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?"); + flog_warn(EC_OSPF_TE_UNEXPECTED, + "MPLS-TE (%s): ospf_mpls_te_lsa_new() ?", __func__); return rc; } /* Install this LSA into LSDB. */ if (ospf_lsa_install(area->ospf, NULL /*oi*/, new) == NULL) { flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, - "ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?"); + "MPLS-TE (%s): ospf_lsa_install() ?", __func__); ospf_lsa_unlock(&new); return rc; } @@ -1243,13 +1262,12 @@ static int ospf_mpls_te_lsa_originate1(struct ospf_area *area, /* Flood new LSA through area. */ ospf_flood_through_area(area, NULL /*nbr*/, new); - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { - zlog_debug( - "LSA[Type%d:%pI4]: Originate Opaque-LSA/MPLS-TE: Area(%pI4), Link(%s)", - new->data->type, &new->data->id, &area->area_id, - lp->ifp->name); + ote_debug( + "MPLS-TE (%s): LSA[Type%d:%pI4]: Originate Opaque-LSA/MPLS-TE: Area(%pI4), Link(%s)", + __func__, new->data->type, &new->data->id, &area->area_id, + lp->ifp->name); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) ospf_lsa_header_dump(new->data); - } rc = 0; return rc; @@ -1263,8 +1281,7 @@ static int ospf_mpls_te_lsa_originate_area(void *arg) int rc = -1; if (!OspfMplsTE.enabled) { - zlog_info( - "ospf_mpls_te_lsa_originate_area: MPLS-TE is disabled now."); + ote_debug("MPLS-TE (%s): MPLS-TE is disabled now.", __func__); rc = 0; /* This is not an error case. */ return rc; } @@ -1272,7 +1289,7 @@ static int ospf_mpls_te_lsa_originate_area(void *arg) for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { /* Process only enabled LSA with area scope flooding */ if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE) - || IS_FLOOD_AS(lp->type)) + || IS_FLOOD_AS(lp->flags)) continue; if (lp->area == NULL) @@ -1284,26 +1301,26 @@ static int ospf_mpls_te_lsa_originate_area(void *arg) if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { if (CHECK_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH)) { UNSET_FLAG(lp->flags, LPFLG_LSA_FORCED_REFRESH); - zlog_info( - "OSPF MPLS-TE (ospf_mpls_te_lsa_originate_area): Refresh instead of Originate"); + ote_debug( + "MPLS-TE (%s): Refresh instead of Originate", + __func__); ospf_mpls_te_lsa_schedule(lp, REFRESH_THIS_LSA); } continue; } if (!is_mandated_params_set(lp)) { - zlog_info( - "ospf_mpls_te_lsa_originate_area: Link(%s) lacks some mandated MPLS-TE parameters.", - lp->ifp ? lp->ifp->name : "?"); + ote_debug( + "MPLS-TE (%s): Link(%s) lacks some mandated MPLS-TE parameters.", + __func__, lp->ifp ? lp->ifp->name : "?"); continue; } /* Ok, let's try to originate an LSA for this area and Link. */ - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "MPLS-TE(ospf_mpls_te_lsa_originate_area) Let's finally reoriginate the LSA %d through the Area %pI4 for Link %s", - lp->instance, &area->area_id, - lp->ifp ? lp->ifp->name : "?"); + ote_debug( + "MPLS-TE (%s): Let's finally reoriginate the LSA %d through the Area %pI4 for Link %s", + __func__, lp->instance, &area->area_id, + lp->ifp ? lp->ifp->name : "?"); if (ospf_mpls_te_lsa_originate1(area, lp) != 0) return rc; } @@ -1321,9 +1338,9 @@ static int ospf_mpls_te_lsa_originate2(struct ospf *top, /* Create new Opaque-LSA/Inter-AS instance. */ new = ospf_mpls_te_lsa_new(top, NULL, lp); if (new == NULL) { - flog_warn( - EC_OSPF_LSA_UNEXPECTED, - "ospf_mpls_te_lsa_originate2: ospf_router_info_lsa_new() ?"); + flog_warn(EC_OSPF_LSA_UNEXPECTED, + "MPLS-TE (%s): ospf_router_info_lsa_new() ?", + __func__); return rc; } new->vrf_id = top->vrf_id; @@ -1331,7 +1348,7 @@ static int ospf_mpls_te_lsa_originate2(struct ospf *top, /* Install this LSA into LSDB. */ if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, - "ospf_mpls_te_lsa_originate2: ospf_lsa_install() ?"); + "MPLS-TE (%s): ospf_lsa_install() ?", __func__); ospf_lsa_unlock(&new); return rc; } @@ -1344,12 +1361,12 @@ static int ospf_mpls_te_lsa_originate2(struct ospf *top, /* Flood new LSA through AS. */ ospf_flood_through_as(top, NULL /*nbr */, new); - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { - zlog_debug( - "LSA[Type%d:%pI4]: Originate Opaque-LSA/MPLS-TE Inter-AS", - new->data->type, &new->data->id); + ote_debug( + "MPLS-TE (%s): LSA[Type%d:%pI4]: Originate Opaque-LSA/MPLS-TE Inter-AS", + __func__, new->data->type, &new->data->id); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) ospf_lsa_header_dump(new->data); - } + rc = 0; return rc; @@ -1364,8 +1381,8 @@ static int ospf_mpls_te_lsa_originate_as(void *arg) int rc = -1; if ((!OspfMplsTE.enabled) || (OspfMplsTE.inter_as == Off)) { - zlog_info( - "ospf_mpls_te_lsa_originate_as: MPLS-TE Inter-AS is disabled for now."); + ote_debug("MPLS-TE (%s): Inter-AS is disabled for now", + __func__); rc = 0; /* This is not an error case. */ return rc; } @@ -1373,6 +1390,7 @@ static int ospf_mpls_te_lsa_originate_as(void *arg) for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { /* Process only enabled INTER_AS Links or Pseudo-Links */ if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE) + || !CHECK_FLAG(lp->flags, LPFLG_LSA_FLOOD_AS) || !IS_INTER_AS(lp->type)) continue; @@ -1387,20 +1405,19 @@ static int ospf_mpls_te_lsa_originate_as(void *arg) if (!is_mandated_params_set(lp)) { flog_warn( EC_OSPF_TE_UNEXPECTED, - "ospf_mpls_te_lsa_originate_as: Link(%s) lacks some mandated MPLS-TE parameters.", - lp->ifp ? lp->ifp->name : "?"); + "MPLS-TE (%s): Link(%s) lacks some mandated MPLS-TE parameters.", + __func__, lp->ifp ? lp->ifp->name : "?"); continue; } /* Ok, let's try to originate an LSA for this AS and Link. */ - if (IS_DEBUG_OSPF_TE) - zlog_debug( - "MPLS-TE(ospf_mpls_te_lsa_originate_as) Let's finally re-originate the Inter-AS LSA %d through the %s for Link %s", - lp->instance, - IS_FLOOD_AS(lp->type) ? "AS" : "Area", - lp->ifp ? lp->ifp->name : "Unknown"); + ote_debug( + "MPLS-TE (%s): Let's finally re-originate the Inter-AS LSA %d through the %s for Link %s", + __func__, lp->instance, + IS_FLOOD_AS(lp->flags) ? "AS" : "Area", + lp->ifp ? lp->ifp->name : "Unknown"); - if (IS_FLOOD_AS(lp->type)) { + if (IS_FLOOD_AS(lp->flags)) { top = (struct ospf *)arg; ospf_mpls_te_lsa_originate2(top, lp); } else { @@ -1413,6 +1430,30 @@ static int ospf_mpls_te_lsa_originate_as(void *arg) return rc; } +/* + * As Inter-AS LSA must be registered with both AREA and AS flooding, and + * because all origination callback functions are call (disregarding the Opaque + * LSA type and Flooding scope) it is necessary to determine which flooding + * scope is associated with the LSA origination as parameter is of type void and + * must be cast to struct *ospf for AS flooding and to struct *ospf_area for + * Area flooding. + */ +static int ospf_mpls_te_lsa_inter_as_as(void *arg) +{ + if (OspfMplsTE.inter_as == AS) + return ospf_mpls_te_lsa_originate_as(arg); + else + return 0; +} + +static int ospf_mpls_te_lsa_inter_as_area(void *arg) +{ + if (OspfMplsTE.inter_as == Area) + return ospf_mpls_te_lsa_originate_area(arg); + else + return 0; +} + static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) { struct mpls_te_link *lp; @@ -1426,7 +1467,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) * change. * It seems a slip among routers in the routing domain. */ - zlog_info("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now."); + ote_debug("MPLS-TE (%s): MPLS-TE is disabled now", __func__); lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ } @@ -1434,7 +1475,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) /* At first, resolve lsa/lp relationship. */ if ((lp = lookup_linkparams_by_instance(lsa)) == NULL) { flog_warn(EC_OSPF_TE_UNEXPECTED, - "ospf_mpls_te_lsa_refresh: Invalid parameter?"); + "MPLS-TE (%s): Invalid parameter?", __func__); lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ ospf_opaque_lsa_flush_schedule(lsa); @@ -1443,9 +1484,8 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) /* Check if lp was not disable in the interval */ if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE)) { - flog_warn( - EC_OSPF_TE_UNEXPECTED, - "ospf_mpls_te_lsa_refresh: lp was disabled: Flush it!"); + flog_warn(EC_OSPF_TE_UNEXPECTED, + "MPLS-TE (%s): lp was disabled: Flush it!", __func__); lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ } @@ -1461,7 +1501,7 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) new = ospf_mpls_te_lsa_new(top, area, lp); if (new == NULL) { flog_warn(EC_OSPF_TE_UNEXPECTED, - "ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?"); + "MPLS-TE (%s): ospf_mpls_te_lsa_new() ?", __func__); return NULL; } new->data->ls_seqnum = lsa_seqnum_increment(lsa); @@ -1475,24 +1515,23 @@ static struct ospf_lsa *ospf_mpls_te_lsa_refresh(struct ospf_lsa *lsa) if (ospf_lsa_install(top, NULL /*oi */, new) == NULL) { flog_warn(EC_OSPF_LSA_INSTALL_FAILURE, - "ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); + "MPLS-TE (%s): ospf_lsa_install() ?", __func__); ospf_lsa_unlock(&new); return NULL; } /* Flood updated LSA through AS or Area depending of the RFC of the link */ - if (IS_FLOOD_AS(lp->type)) + if (IS_FLOOD_AS(lp->flags)) ospf_flood_through_as(top, NULL, new); else ospf_flood_through_area(area, NULL /*nbr*/, new); /* Debug logging. */ - if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) { - zlog_debug("LSA[Type%d:%pI4]: Refresh Opaque-LSA/MPLS-TE", - new->data->type, &new->data->id); + ote_debug("MPLS-TE (%s): LSA[Type%d:%pI4]: Refresh Opaque-LSA/MPLS-TE", + __func__, new->data->type, &new->data->id); + if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) ospf_lsa_header_dump(new->data); - } return new; } @@ -1509,14 +1548,19 @@ void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode) top = ospf_lookup_by_vrf_id(VRF_DEFAULT); /* Check if the pseudo link is ready to flood */ - if (!(CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE)) - || !(IS_FLOOD_AREA(lp->type) || IS_FLOOD_AS(lp->type))) { + if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ACTIVE)) return; - } + + ote_debug("MPLS-TE (%s): Schedule %s%s%s LSA for interface %s", + __func__, + opcode == REORIGINATE_THIS_LSA ? "Re-Originate" : "", + opcode == REFRESH_THIS_LSA ? "Refresh" : "", + opcode == FLUSH_THIS_LSA ? "Flush" : "", + lp->ifp ? lp->ifp->name : "-"); lsa.area = lp->area; lsa.data = &lsah; - if (IS_FLOOD_AS(lp->type)) { + if (IS_FLOOD_AS(lp->flags)) { lsah.type = OSPF_OPAQUE_AS_LSA; tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA, lp->instance); lsah.id.s_addr = htonl(tmp); @@ -1531,7 +1575,8 @@ void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode) if (lp->area == NULL) { flog_warn( EC_OSPF_TE_UNEXPECTED, - "MPLS-TE(ospf_mpls_te_lsa_schedule) Area context is null. Abort !"); + "MPLS-TE (%s): Area context is null. Abort !", + __func__); return; } tmp = SET_OPAQUE_LSID(OPAQUE_TYPE_INTER_AS_LSA, @@ -1545,14 +1590,11 @@ void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode) switch (opcode) { case REORIGINATE_THIS_LSA: - if (IS_FLOOD_AS(lp->type)) { + if (IS_FLOOD_AS(lp->flags)) { ospf_opaque_lsa_reoriginate_schedule( (void *)top, OSPF_OPAQUE_AS_LSA, OPAQUE_TYPE_INTER_AS_LSA); - break; - } - - if (IS_FLOOD_AREA(lp->type)) { + } else { if (IS_INTER_AS(lp->type)) ospf_opaque_lsa_reoriginate_schedule( (void *)lp->area, OSPF_OPAQUE_AREA_LSA, @@ -1561,7 +1603,6 @@ void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode) ospf_opaque_lsa_reoriginate_schedule( (void *)lp->area, OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); - break; } break; case REFRESH_THIS_LSA: @@ -1574,14 +1615,1532 @@ void ospf_mpls_te_lsa_schedule(struct mpls_te_link *lp, enum lsa_opcode opcode) break; default: flog_warn(EC_OSPF_TE_UNEXPECTED, - "ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", + "MPLS-TE (%s): Unknown opcode (%u)", __func__, opcode); break; } +} - return; +/** + * ------------------------------------------------------ + * Followings are Link State Data Base control functions. + * ------------------------------------------------------ + */ + +/** + * Get Vertex from TED by the router which advertised the LSA. A new Vertex and + * associated Link State Node are created if Vertex is not found. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return Link State Vertex + */ +static struct ls_vertex *get_vertex(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_node_id lnid; + struct ls_node *lnode; + struct ls_vertex *vertex; + + /* Sanity Check */ + if (!ted || !lsa || !lsa->data || !lsa->area) + return NULL; + + /* Search if a Link State Vertex already exist */ + lnid.origin = OSPFv2; + lnid.id.ip.addr = lsa->data->adv_router; + lnid.id.ip.area_id = lsa->area->area_id; + vertex = ls_find_vertex_by_id(ted, lnid); + + /* Create Node & Vertex in the Link State Date Base if not found */ + if (!vertex) { + const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; + + lnode = ls_node_new(lnid, inaddr_any, in6addr_any); + snprintfrr(lnode->name, MAX_NAME_LENGTH, "%pI4", + &lnid.id.ip.addr); + vertex = ls_vertex_add(ted, lnode); + } + + if (IS_LSA_SELF(lsa)) + ted->self = vertex; + + return vertex; +} + +/** + * Get Edge from TED by Link State Attribute ID. A new Edge and associated Link + * State Attributes are created if not found. + * + * @param ted Link State Traffic Engineering Database + * @param adv Link State Node ID of router which advertised Edge + * @param link_id Link State Attribute ID + * + * @return Link State Edge + */ +static struct ls_edge *get_edge(struct ls_ted *ted, struct ls_node_id adv, + struct in_addr link_id) +{ + uint64_t key; + struct ls_edge *edge; + struct ls_attributes *attr; + + /* Search Edge that corresponds to the Link ID */ + key = ((uint64_t)ntohl(link_id.s_addr)) & 0xffffffff; + edge = ls_find_edge_by_key(ted, key); + + /* Create new one if not exist */ + if (!edge) { + attr = ls_attributes_new(adv, link_id, in6addr_any, 0); + edge = ls_edge_add(ted, attr); + } + + return edge; } +/** + * Export Link State information to consumer daemon through ZAPI Link State + * Opaque Message. + * + * @param type Type of Link State Element i.e. Vertex, Edge or Subnet + * @param link_state Pointer to Link State Vertex, Edge or Subnet + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_export(uint8_t type, void *link_state) +{ + struct ls_message msg = {}; + int rc = 0; + + if (!OspfMplsTE.export) + return rc; + + switch (type) { + case LS_MSG_TYPE_NODE: + ls_vertex2msg(&msg, (struct ls_vertex *)link_state); + rc = ls_send_msg(zclient, &msg, NULL); + break; + case LS_MSG_TYPE_ATTRIBUTES: + ls_edge2msg(&msg, (struct ls_edge *)link_state); + rc = ls_send_msg(zclient, &msg, NULL); + break; + case LS_MSG_TYPE_PREFIX: + ls_subnet2msg(&msg, (struct ls_subnet *)link_state); + rc = ls_send_msg(zclient, &msg, NULL); + break; + default: + rc = -1; + break; + } + + return rc; +} + +/** + * Update Link State Edge & Attributes from the given Link State Attributes ID + * and metric. This function is called when parsing Router LSA. + * + * @param ted Link State Traffic Engineering Database + * @param vertex Vertex where the Edge is attached as source + * @param link_data Link State Edge ID + * @param metric Standard metric attached to this Edge + */ +static void ospf_te_update_link(struct ls_ted *ted, struct ls_vertex *vertex, + struct in_addr link_data, uint8_t metric) +{ + struct ls_edge *edge; + struct ls_attributes *attr; + + /* Sanity check */ + if (!ted || !vertex || !vertex->node) + return; + + /* Get Corresponding Edge from Link State Data Base */ + edge = get_edge(ted, vertex->node->adv, link_data); + attr = edge->attributes; + + /* re-attached edge to vertex if needed */ + if (!edge->source) + edge->source = vertex; + + /* Check if it is just an LSA refresh */ + if ((CHECK_FLAG(attr->flags, LS_ATTR_METRIC) + && (attr->metric == metric))) { + edge->status = SYNC; + return; + } + + /* Update metric value */ + attr->metric = metric; + SET_FLAG(attr->flags, LS_ATTR_METRIC); + if (edge->status != NEW) + edge->status = UPDATE; + + ote_debug(" |- %s Edge %pI4 with metric %d", + edge->status == NEW ? "Add" : "Update", &attr->standard.local, + attr->metric); + + /* Export Link State Edge */ + ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); + edge->status = SYNC; +} + +/** + * Update Link State Subnet & Prefix from the given prefix and metric. This + * function is called when parsing Router LSA. + * + * @param ted Link State Traffic Engineering Database + * @param vertex Vertex where the Edge is attached as source + * @param p Prefix associated to the Subnet + * @param metric Standard metric attached to this Edge + */ +static void ospf_te_update_subnet(struct ls_ted *ted, struct ls_vertex *vertex, + struct prefix p, uint8_t metric) +{ + struct ls_subnet *subnet; + struct ls_prefix *ls_pref; + + /* Search if there is a Subnet for this prefix */ + subnet = ls_find_subnet(ted, p); + + /* If found a Subnet, check if it is attached to this Vertex */ + if (subnet) { + /* Re-attach the subnet to the vertex if necessary */ + if (subnet->vertex != vertex) { + subnet->vertex = vertex; + listnode_add_sort_nodup(vertex->prefixes, subnet); + } + /* Check if it is a simple refresh */ + ls_pref = subnet->ls_pref; + if ((CHECK_FLAG(ls_pref->flags, LS_PREF_METRIC)) + && (ls_pref->metric == metric)) { + subnet->status = SYNC; + return; + } + ls_pref->metric = metric; + SET_FLAG(ls_pref->flags, LS_PREF_METRIC); + subnet->status = UPDATE; + } else { + /* Create new Link State Prefix */ + ls_pref = ls_prefix_new(vertex->node->adv, p); + ls_pref->metric = metric; + SET_FLAG(ls_pref->flags, LS_PREF_METRIC); + /* and add it to the TED */ + subnet = ls_subnet_add(ted, ls_pref); + } + + ote_debug(" |- %s subnet %pFX with metric %d", + subnet->status == NEW ? "Add" : "Update", &subnet->key, + ls_pref->metric); + + /* Export Link State Subnet */ + ospf_te_export(LS_MSG_TYPE_PREFIX, subnet); + subnet->status = SYNC; +} + +/** + * Delete Subnet that correspond to the given IPv4 address and export deletion + * information before removal. Prefix length is fixed to IPV4_MAX_PREFIXLEN. + * + * @param ted Links State Database + * @param addr IPv4 address + */ +static void ospf_te_delete_subnet(struct ls_ted *ted, struct in_addr addr) +{ + struct prefix p; + struct ls_subnet *subnet; + + /* Search subnet that correspond to the address/32 as prefix */ + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.u.prefix4 = addr; + subnet = ls_find_subnet(ted, p); + + /* Remove subnet if found */ + if (subnet) { + subnet->status = DELETE; + ospf_te_export(LS_MSG_TYPE_PREFIX, subnet); + ls_subnet_del_all(ted, subnet); + } +} + +/** + * Parse Router LSA. This function will create or update corresponding Vertex, + * Edge and Subnet. It also remove Edge and Subnet if they are marked as Orphan + * once Router LSA is parsed. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct router_lsa *rl; + enum ls_node_type type; + struct ls_vertex *vertex; + struct ls_edge *edge; + struct ls_subnet *subnet; + struct listnode *node; + int len; + + /* Sanity Check */ + if (!ted || !lsa || !lsa->data) + return -1; + + ote_debug("MPLS-TE (%s): Parse Router LSA[%pI4] from Router[%pI4]", + __func__, &lsa->data->id, &lsa->data->adv_router); + + /* Get vertex from LSA Advertise Router ID */ + vertex = get_vertex(ted, lsa); + + /* Set Node type information if it has changed */ + rl = (struct router_lsa *)lsa->data; + if (IS_ROUTER_LSA_VIRTUAL(rl)) + type = PSEUDO; + else if (IS_ROUTER_LSA_EXTERNAL(rl)) + type = ASBR; + else if (IS_ROUTER_LSA_BORDER(rl)) + type = ABR; + else + type = STANDARD; + + if (vertex->status == NEW) { + vertex->node->type = type; + SET_FLAG(vertex->node->flags, LS_NODE_TYPE); + } else if (vertex->node->type != type) { + vertex->node->type = type; + vertex->status = UPDATE; + } + + /* Check if Vertex has been modified */ + if (vertex->status != SYNC) { + ote_debug(" |- %s Vertex %pI4", + vertex->status == NEW ? "Add" : "Update", + &vertex->node->router_id); + + /* Vertex is out of sync: export it */ + ospf_te_export(LS_MSG_TYPE_NODE, vertex); + vertex->status = SYNC; + } + + /* Mark outgoing Edge and Subnet as ORPHAN to detect deletion */ + for (ALL_LIST_ELEMENTS_RO(vertex->outgoing_edges, node, edge)) + edge->status = ORPHAN; + + for (ALL_LIST_ELEMENTS_RO(vertex->prefixes, node, subnet)) + subnet->status = ORPHAN; + + /* Then, process Link Information */ + len = ntohs(rl->header.length) - 4; + for (int i = 0; i < ntohs(rl->links) && len > 0; len -= 12, i++) { + struct prefix p; + uint32_t metric; + + switch (rl->link[i].type) { + case LSA_LINK_TYPE_POINTOPOINT: + ospf_te_update_link(ted, vertex, rl->link[i].link_data, + ntohs(rl->link[i].metric)); + /* Add corresponding subnet */ + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.u.prefix4 = rl->link[i].link_data; + metric = ntohs(rl->link[i].metric); + ospf_te_update_subnet(ted, vertex, p, metric); + break; + case LSA_LINK_TYPE_STUB: + /* Keep only /32 prefix */ + p.prefixlen = ip_masklen(rl->link[i].link_data); + if (p.prefixlen == IPV4_MAX_PREFIXLEN) { + p.family = AF_INET; + p.u.prefix4 = rl->link[i].link_id; + metric = ntohs(rl->link[i].metric); + ospf_te_update_subnet(ted, vertex, p, metric); + } + break; + default: + break; + } + } + /* Clean remaining Orphan Edges or Subnets */ + if (OspfMplsTE.export) + ls_vertex_clean(ted, vertex, zclient); + else + ls_vertex_clean(ted, vertex, NULL); + + return 0; +} + +/** + * Delete Vertex, Edge and Subnet associated to this Router LSA. This function + * is called when the router received such LSA with MAX_AGE (Flush) or when the + * router stop OSPF. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_delete_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_node_id lnid; + struct ls_vertex *vertex; + + /* Sanity Check */ + if (!ted || !lsa || !lsa->data) + return -1; + + /* Search Vertex that corresponds to this LSA */ + lnid.origin = OSPFv2; + lnid.id.ip.addr = lsa->data->adv_router; + lnid.id.ip.area_id = lsa->area->area_id; + vertex = ls_find_vertex_by_id(ted, lnid); + if (!vertex) + return -1; + + ote_debug("MPLS-TE (%s): Delete Vertex %pI4 from Router LSA[%pI4]", + __func__, &vertex->node->router_id, &lsa->data->id); + + /* Export deleted vertex ... */ + vertex->status = DELETE; + ospf_te_export(LS_MSG_TYPE_NODE, vertex); + + /* ... and remove Node & Vertex from Link State Date Base */ + ls_vertex_del_all(ted, vertex); + + return 0; +} + +/** + * Create or update Remote Vertex that corresponds to the remote ASBR of the + * foreign network if Edge is associated to an Inter-AS LSA (Type 6). + * + * @param ted Link State Traffic Engineering Database + * @param edge Link State Edge + */ +static void ospf_te_update_remote_asbr(struct ls_ted *ted, struct ls_edge *edge) +{ + struct ls_node_id lnid; + struct ls_vertex *vertex; + struct ls_node *lnode; + struct ls_attributes *attr; + struct prefix p; + + /* Sanity Check */ + if (!ted || !edge) + return; + + /* Search if a Link State Vertex already exist */ + attr = edge->attributes; + lnid.origin = OSPFv2; + lnid.id.ip.addr = attr->standard.remote_addr; + lnid.id.ip.area_id = attr->adv.id.ip.area_id; + vertex = ls_find_vertex_by_id(ted, lnid); + + /* Create Node & Vertex in the Link State Date Base if not found */ + if (!vertex) { + const struct in_addr inaddr_any = {.s_addr = INADDR_ANY}; + + lnode = ls_node_new(lnid, inaddr_any, in6addr_any); + snprintfrr(lnode->name, MAX_NAME_LENGTH, "%pI4", + &lnid.id.ip.addr); + vertex = ls_vertex_add(ted, lnode); + } + + /* Update Node information */ + lnode = vertex->node; + if (CHECK_FLAG(lnode->flags, LS_NODE_TYPE)) { + if (lnode->type != RMT_ASBR) { + lnode->type = RMT_ASBR; + if (vertex->status != NEW) + vertex->status = UPDATE; + } + } else { + lnode->type = RMT_ASBR; + SET_FLAG(lnode->flags, LS_NODE_TYPE); + if (vertex->status != NEW) + vertex->status = UPDATE; + } + if (CHECK_FLAG(lnode->flags, LS_NODE_AS_NUMBER)) { + if (lnode->as_number != attr->standard.remote_as) { + lnode->as_number = attr->standard.remote_as; + if (vertex->status != NEW) + vertex->status = UPDATE; + } + } else { + lnode->as_number = attr->standard.remote_as; + SET_FLAG(lnode->flags, LS_NODE_AS_NUMBER); + if (vertex->status != NEW) + vertex->status = UPDATE; + } + + /* Export Link State Vertex if needed */ + if (vertex->status == NEW || vertex->status == UPDATE) { + ote_debug(" |- %s Remote Vertex %pI4 for AS %u", + vertex->status == NEW ? "Add" : "Update", + &lnode->router_id, lnode->as_number); + ospf_te_export(LS_MSG_TYPE_NODE, vertex); + vertex->status = SYNC; + } + + /* Update corresponding Subnets */ + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.u.prefix4 = attr->standard.local; + ospf_te_update_subnet(ted, edge->source, p, attr->standard.te_metric); + + p.family = AF_INET; + p.prefixlen = IPV4_MAX_PREFIXLEN; + p.u.prefix4 = attr->standard.remote_addr; + ospf_te_update_subnet(ted, vertex, p, attr->standard.te_metric); + + /* Connect Edge to the remote Vertex */ + if (edge->destination == NULL) { + edge->destination = vertex; + listnode_add_sort_nodup(vertex->incoming_edges, edge); + } + + /* Finally set type to ASBR the node that advertised this Edge ... */ + vertex = edge->source; + lnode = vertex->node; + if (CHECK_FLAG(lnode->flags, LS_NODE_TYPE)) { + if (lnode->type != ASBR) { + lnode->type = ASBR; + if (vertex->status != NEW) + vertex->status = UPDATE; + } + } else { + lnode->type = ASBR; + SET_FLAG(lnode->flags, LS_NODE_TYPE); + if (vertex->status != NEW) + vertex->status = UPDATE; + } + + /* ... and Export it if needed */ + if (vertex->status == NEW || vertex->status == UPDATE) { + ospf_te_export(LS_MSG_TYPE_NODE, vertex); + vertex->status = SYNC; + } +} + +/** + * Parse Opaque Traffic Engineering LSA (Type 1) TLVs and create or update the + * corresponding Link State Edge and Attributes. Vertex connections are also + * updated if needed based on the remote IP address of the Edge and existing + * reverse Edge. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_edge *edge; + struct ls_vertex *vertex; + struct ls_attributes *old, attr = {}; + struct tlv_header *tlvh; + void *value; + uint16_t len, sum; + uint8_t lsa_id; + + /* Initialize Attribute */ + attr.adv.origin = OSPFv2; + attr.adv.id.ip.addr = lsa->data->adv_router; + if (lsa->data->type != OSPF_OPAQUE_AS_LSA) + attr.adv.id.ip.area_id = lsa->area->area_id; + + /* Initialize TLV browsing */ + tlvh = TLV_HDR_TOP(lsa->data); + + /* Skip TE Router-ID if present */ + if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR) + tlvh = TLV_HDR_NEXT(tlvh); + + /* Check if we have a TE Link TLV */ + len = TLV_BODY_SIZE(tlvh); + if ((len == 0) || (ntohs(tlvh->type) != TE_TLV_LINK)) + return 0; + + sum = 0; + /* Browse sub-TLV and fulfill Link State Attributes */ + for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { + uint32_t val32, tab32[2]; + float valf, tabf[8]; + struct in_addr addr; + + value = TLV_DATA(tlvh); + switch (ntohs(tlvh->type)) { + case TE_LINK_SUBTLV_LCLIF_IPADDR: + memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.standard.local = addr; + SET_FLAG(attr.flags, LS_ATTR_LOCAL_ADDR); + break; + case TE_LINK_SUBTLV_RMTIF_IPADDR: + memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.standard.remote = addr; + SET_FLAG(attr.flags, LS_ATTR_NEIGH_ADDR); + break; + case TE_LINK_SUBTLV_TE_METRIC: + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.standard.te_metric = ntohl(val32); + SET_FLAG(attr.flags, LS_ATTR_TE_METRIC); + break; + case TE_LINK_SUBTLV_MAX_BW: + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.standard.max_bw = ntohf(valf); + SET_FLAG(attr.flags, LS_ATTR_MAX_BW); + break; + case TE_LINK_SUBTLV_MAX_RSV_BW: + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.standard.max_rsv_bw = ntohf(valf); + SET_FLAG(attr.flags, LS_ATTR_MAX_RSV_BW); + break; + case TE_LINK_SUBTLV_UNRSV_BW: + memcpy(tabf, value, TE_LINK_SUBTLV_UNRSV_SIZE); + for (int i = 0; i < MAX_CLASS_TYPE; i++) + attr.standard.unrsv_bw[i] = ntohf(tabf[i]); + SET_FLAG(attr.flags, LS_ATTR_UNRSV_BW); + break; + case TE_LINK_SUBTLV_RSC_CLSCLR: + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.standard.admin_group = ntohl(val32); + SET_FLAG(attr.flags, LS_ATTR_ADM_GRP); + break; + case TE_LINK_SUBTLV_LLRI: + memcpy(tab32, value, TE_LINK_SUBTLV_LLRI_SIZE); + attr.standard.local_id = ntohl(tab32[0]); + attr.standard.remote_id = ntohl(tab32[1]); + SET_FLAG(attr.flags, LS_ATTR_LOCAL_ID); + SET_FLAG(attr.flags, LS_ATTR_NEIGH_ID); + break; + case TE_LINK_SUBTLV_RIP: + memcpy(&addr, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.standard.remote_addr = addr; + SET_FLAG(attr.flags, LS_ATTR_REMOTE_ADDR); + break; + case TE_LINK_SUBTLV_RAS: + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.standard.remote_as = ntohl(val32); + SET_FLAG(attr.flags, LS_ATTR_REMOTE_AS); + break; + case TE_LINK_SUBTLV_AV_DELAY: + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.extended.delay = ntohl(val32); + SET_FLAG(attr.flags, LS_ATTR_DELAY); + break; + case TE_LINK_SUBTLV_MM_DELAY: + memcpy(tab32, value, TE_LINK_SUBTLV_MM_DELAY_SIZE); + attr.extended.min_delay = ntohl(tab32[0]); + attr.extended.max_delay = ntohl(tab32[1]); + SET_FLAG(attr.flags, LS_ATTR_MIN_MAX_DELAY); + break; + case TE_LINK_SUBTLV_DELAY_VAR: + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.extended.jitter = ntohl(val32); + SET_FLAG(attr.flags, LS_ATTR_JITTER); + break; + case TE_LINK_SUBTLV_PKT_LOSS: + memcpy(&val32, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.extended.pkt_loss = ntohl(val32); + SET_FLAG(attr.flags, LS_ATTR_PACKET_LOSS); + break; + case TE_LINK_SUBTLV_RES_BW: + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.extended.rsv_bw = ntohf(valf); + SET_FLAG(attr.flags, LS_ATTR_RSV_BW); + break; + case TE_LINK_SUBTLV_AVA_BW: + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.extended.ava_bw = ntohf(valf); + SET_FLAG(attr.flags, LS_ATTR_AVA_BW); + break; + case TE_LINK_SUBTLV_USE_BW: + memcpy(&valf, value, TE_LINK_SUBTLV_DEF_SIZE); + attr.extended.used_bw = ntohf(valf); + SET_FLAG(attr.flags, LS_ATTR_USE_BW); + break; + default: + break; + } + sum += TLV_SIZE(tlvh); + } + + /* Get corresponding Edge from Link State Data Base */ + edge = get_edge(ted, attr.adv, attr.standard.local); + old = edge->attributes; + + ote_debug(" |- Process Traffic Engineering LSA %pI4 for Edge %pI4", + &lsa->data->id, &attr.standard.local); + + /* Update standard fields */ + len = sizeof(struct ls_standard); + if ((attr.flags & 0x0FFFF) == (old->flags & 0x0FFFF)) { + if (memcmp(&attr.standard, &old->standard, len) != 0) { + memcpy(&old->standard, &attr.standard, len); + if (edge->status != NEW) + edge->status = UPDATE; + } + } else { + memcpy(&old->standard, &attr.standard, len); + old->flags |= attr.flags & 0x0FFFF; + if (edge->status != NEW) + edge->status = UPDATE; + } + /* Update extended fields */ + len = sizeof(struct ls_extended); + if ((attr.flags & 0x0FF0000) == (old->flags & 0x0FF0000)) { + if (memcmp(&attr.extended, &old->extended, len) != 0) { + memcpy(&old->extended, &attr.extended, len); + if (edge->status != NEW) + edge->status = UPDATE; + } + } else { + memcpy(&old->extended, &attr.extended, len); + old->flags |= attr.flags & 0x0FF0000; + if (edge->status != NEW) + edge->status = UPDATE; + } + + /* If LSA is an Opaque Inter-AS, Add Node and Subnet */ + lsa_id = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)); + if (lsa_id == OPAQUE_TYPE_INTER_AS_LSA) + ospf_te_update_remote_asbr(ted, edge); + + /* Update remote Link if remote IP addr is known */ + if (CHECK_FLAG(old->flags, LS_ATTR_NEIGH_ADDR)) { + struct ls_edge *dst; + + dst = ls_find_edge_by_destination(ted, old); + /* Attach remote link if not set */ + if (dst && edge->source && dst->destination == NULL) { + vertex = edge->source; + if (vertex->incoming_edges) + listnode_add_sort_nodup(vertex->incoming_edges, + dst); + dst->destination = vertex; + } + /* and destination vertex to this edge */ + if (dst && dst->source && edge->destination == NULL) { + vertex = dst->source; + if (vertex->incoming_edges) + listnode_add_sort_nodup(vertex->incoming_edges, + edge); + edge->destination = vertex; + } + } + + /* Export Link State Edge if needed */ + if (edge->status == NEW || edge->status == UPDATE) { + ote_debug(" |- %s TE info. for Edge %pI4", + edge->status == NEW ? "Add" : "Update", + &edge->attributes->standard.local); + + ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); + edge->status = SYNC; + } + + return 0; +} + +/** + * Delete Link State Attributes information that correspond to the Opaque + * Traffic Engineering LSA (Type 1) TLVs. Note that the Edge is not removed. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_edge *edge; + struct ls_attributes *attr; + struct tlv_header *tlvh; + struct in_addr addr; + uint64_t key = 0; + uint16_t len, sum; + uint8_t lsa_id; + + /* Initialize TLV browsing */ + tlvh = TLV_HDR_TOP(lsa->data); + /* Skip Router TE ID if present */ + if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR) + tlvh = TLV_HDR_NEXT(tlvh); + len = TLV_BODY_SIZE(tlvh); + sum = 0; + + /* Browse sub-TLV to find Link ID */ + for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { + if (ntohs(tlvh->type) == TE_LINK_SUBTLV_LCLIF_IPADDR) { + memcpy(&addr, TLV_DATA(tlvh), TE_LINK_SUBTLV_DEF_SIZE); + key = ((uint64_t)ntohl(addr.s_addr)) & 0xffffffff; + break; + } + sum += TLV_SIZE(tlvh); + } + if (key == 0) + return 0; + + /* Search Edge that corresponds to the Link ID */ + edge = ls_find_edge_by_key(ted, key); + if (!edge || !edge->attributes) + return 0; + attr = edge->attributes; + + /* First, remove Remote ASBR and associated Edge & Subnet if any */ + lsa_id = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)); + if (lsa_id == OPAQUE_TYPE_INTER_AS_LSA) { + ote_debug(" |- Delete remote ASBR, Edge and Subnet"); + + if (edge->destination) { + edge->destination->status = DELETE; + ospf_te_export(LS_MSG_TYPE_NODE, edge->destination); + ls_vertex_del_all(ted, edge->destination); + } + + ospf_te_delete_subnet(ted, attr->standard.local); + + edge->status = DELETE; + ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); + ls_edge_del_all(ted, edge); + + return 0; + } + + ote_debug(" |- Delete TE info. for Edge %pI4", + &edge->attributes->standard.local); + + /* Remove Link State Attributes TE information */ + memset(&attr->standard, 0, sizeof(struct ls_standard)); + attr->flags &= 0x0FFFF; + memset(&attr->extended, 0, sizeof(struct ls_extended)); + attr->flags &= 0x0FF0000; + ls_attributes_srlg_del(attr); + + /* Export Edge that has been updated */ + if (CHECK_FLAG(attr->flags, LS_ATTR_ADJ_SID) + || CHECK_FLAG(attr->flags, LS_ATTR_BCK_ADJ_SID)) { + edge->status = UPDATE; + ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); + edge->status = SYNC; + } else { + /* Remove completely the Edge if Segment Routing is not set */ + ospf_te_delete_subnet(ted, attr->standard.local); + edge->status = DELETE; + ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); + ls_edge_del_all(ted, edge); + } + + return 0; +} + +/** + * Parse Opaque Router Information LSA (Type 4) TLVs and update the + * corresponding Link State Vertex with these information (Segment Routing). + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_vertex *vertex; + struct ls_node *node; + struct lsa_header *lsah = lsa->data; + struct tlv_header *tlvh; + uint16_t len = 0, sum = 0; + + /* Get vertex / Node from LSA Advertised Router ID */ + vertex = get_vertex(ted, lsa); + node = vertex->node; + + ote_debug(" |- Process Router Information LSA %pI4 for Vertex %pI4", + &lsa->data->id, &node->router_id); + + /* Initialize TLV browsing */ + len = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + for (tlvh = TLV_HDR_TOP(lsah); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { + struct ri_sr_tlv_sr_algorithm *algo; + struct ri_sr_tlv_sid_label_range *range; + struct ri_sr_tlv_node_msd *msd; + uint32_t size, lower; + + switch (ntohs(tlvh->type)) { + case RI_SR_TLV_SR_ALGORITHM: + algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; + + for (int i = 0; i < ntohs(algo->header.length); i++) { + if (CHECK_FLAG(node->flags, LS_NODE_SR) + && (node->algo[i] == algo->value[i])) + continue; + + node->algo[i] = algo->value[i]; + SET_FLAG(node->flags, LS_NODE_SR); + if (vertex->status != NEW) + vertex->status = UPDATE; + } + + /* Reset other Algorithms */ + for (int i = ntohs(algo->header.length); i < 2; i++) { + if (vertex->status != NEW + && node->algo[i] != SR_ALGORITHM_UNSET) + vertex->status = UPDATE; + node->algo[i] = SR_ALGORITHM_UNSET; + } + + break; + + case RI_SR_TLV_SRGB_LABEL_RANGE: + range = (struct ri_sr_tlv_sid_label_range *)tlvh; + size = GET_RANGE_SIZE(ntohl(range->size)); + lower = GET_LABEL(ntohl(range->lower.value)); + if ((CHECK_FLAG(node->flags, LS_NODE_SR)) + && ((node->srgb.range_size == size) + && (node->srgb.lower_bound == lower))) + break; + + node->srgb.range_size = size; + node->srgb.lower_bound = lower; + SET_FLAG(node->flags, LS_NODE_SR); + if (vertex->status != NEW) + vertex->status = UPDATE; + + break; + + case RI_SR_TLV_SRLB_LABEL_RANGE: + range = (struct ri_sr_tlv_sid_label_range *)tlvh; + size = GET_RANGE_SIZE(ntohl(range->size)); + lower = GET_LABEL(ntohl(range->lower.value)); + if ((CHECK_FLAG(node->flags, LS_NODE_SRLB)) + && ((node->srlb.range_size == size) + && (node->srlb.lower_bound == lower))) + break; + + node->srlb.range_size = size; + node->srlb.lower_bound = lower; + SET_FLAG(node->flags, LS_NODE_SRLB); + if (vertex->status != NEW) + vertex->status = UPDATE; + + break; + + case RI_SR_TLV_NODE_MSD: + msd = (struct ri_sr_tlv_node_msd *)tlvh; + if ((CHECK_FLAG(node->flags, LS_NODE_MSD)) + && (node->msd == msd->value)) + break; + + node->msd = msd->value; + SET_FLAG(node->flags, LS_NODE_MSD); + if (vertex->status != NEW) + vertex->status = UPDATE; + + break; + + default: + break; + } + sum += TLV_SIZE(tlvh); + } + + /* Vertex has been created or updated: export it */ + if (vertex->status == NEW || vertex->status == UPDATE) { + ote_debug(" |- %s SR info - SRGB[%d/%d] for Vertex %pI4", + vertex->status == NEW ? "Add" : "Update", + vertex->node->srgb.lower_bound, + vertex->node->srgb.range_size, + &vertex->node->router_id); + + ospf_te_export(LS_MSG_TYPE_NODE, vertex); + vertex->status = SYNC; + } + + return 0; +} + +/** + * Delete Link State Node information (Segment Routing) that correspond to the + * Opaque Router Information LSA (Type 4) TLVs. Note that the Vertex is not + * removed. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_delete_ri(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_node_id lnid; + struct ls_vertex *vertex; + struct ls_node *node; + + /* Search if a Link State Vertex already exist */ + lnid.origin = OSPFv2; + lnid.id.ip.addr = lsa->data->adv_router; + lnid.id.ip.area_id = lsa->area->area_id; + vertex = ls_find_vertex_by_id(ted, lnid); + if (!vertex) + return -1; + + /* Remove Segment Routing Information if any */ + node = vertex->node; + UNSET_FLAG(node->flags, LS_NODE_SR); + memset(&node->srgb, 0, sizeof(struct ls_srgb)); + node->algo[0] = SR_ALGORITHM_UNSET; + node->algo[1] = SR_ALGORITHM_UNSET; + UNSET_FLAG(node->flags, LS_NODE_SRLB); + memset(&node->srlb, 0, sizeof(struct ls_srlb)); + UNSET_FLAG(node->flags, LS_NODE_MSD); + node->msd = 0; + vertex->status = UPDATE; + + ote_debug(" |- Delete SR info. for Vertex %pI4", + &vertex->node->router_id); + + /* Vertex has been updated: export it */ + ospf_te_export(LS_MSG_TYPE_NODE, vertex); + vertex->status = SYNC; + + return 0; +} + +/** + * Parse Opaque Extended Prefix LSA (Type 7) TLVs and update the corresponding + * Link State Subnet with these information (Segment Routing ID). + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_parse_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_node_id lnid; + struct ls_subnet *subnet; + struct ls_prefix *ls_pref; + struct prefix pref; + struct ext_tlv_prefix *ext; + struct ext_subtlv_prefix_sid *pref_sid; + uint32_t label; + + /* Get corresponding Subnet from Link State Data Base */ + ext = (struct ext_tlv_prefix *)TLV_HDR_TOP(lsa->data); + pref.family = AF_INET; + pref.prefixlen = ext->pref_length; + pref.u.prefix4 = ext->address; + subnet = ls_find_subnet(ted, pref); + + /* Create new Link State Prefix if not found */ + if (!subnet) { + lnid.origin = OSPFv2; + lnid.id.ip.addr = lsa->data->adv_router; + lnid.id.ip.area_id = lsa->area->area_id; + ls_pref = ls_prefix_new(lnid, pref); + /* and add it to the TED */ + subnet = ls_subnet_add(ted, ls_pref); + } + + ote_debug(" |- Process Extended Prefix LSA %pI4 for subnet %pFX", + &lsa->data->id, &pref); + + /* Initialize TLV browsing */ + ls_pref = subnet->ls_pref; + pref_sid = (struct ext_subtlv_prefix_sid *)((char *)(ext) + TLV_HDR_SIZE + + EXT_TLV_PREFIX_SIZE); + label = CHECK_FLAG(pref_sid->flags, EXT_SUBTLV_PREFIX_SID_VFLG) + ? GET_LABEL(ntohl(pref_sid->value)) + : ntohl(pref_sid->value); + + /* Check if it is a simple refresh */ + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SR) + && ls_pref->sr.algo == pref_sid->algorithm + && ls_pref->sr.sid_flag == pref_sid->flags + && ls_pref->sr.sid == label) + return 0; + + /* Fulfill SR information */ + ls_pref->sr.algo = pref_sid->algorithm; + ls_pref->sr.sid_flag = pref_sid->flags; + ls_pref->sr.sid = label; + SET_FLAG(ls_pref->flags, LS_PREF_SR); + if (subnet->status != NEW) + subnet->status = UPDATE; + + /* Export Subnet if needed */ + if (subnet->status == NEW || subnet->status == UPDATE) { + ote_debug(" |- %s SID %d to subnet %pFX", + subnet->status == NEW ? "Add" : "Update", + ls_pref->sr.sid, &ls_pref->pref); + + ospf_te_export(LS_MSG_TYPE_PREFIX, subnet); + subnet->status = SYNC; + } + + return 0; +} + +/** + * Delete Link State Subnet information (Segment Routing ID) that correspond to + * the Opaque Extended Prefix LSA (Type 7) TLVs. Note that the Subnet is not + * removed. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_delete_ext_pref(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_subnet *subnet; + struct ls_prefix *ls_pref; + struct prefix pref; + struct ext_tlv_prefix *ext; + + /* Get corresponding Subnet from Link State Data Base */ + ext = (struct ext_tlv_prefix *)TLV_HDR_TOP(lsa->data); + pref.family = AF_INET; + pref.prefixlen = ext->pref_length; + pref.u.prefix4 = ext->address; + subnet = ls_find_subnet(ted, pref); + + /* Check if there is a corresponding subnet */ + if (!subnet) + return -1; + + ote_debug(" |- Delete SID %d to subnet %pFX", subnet->ls_pref->sr.sid, + &subnet->ls_pref->pref); + + /* Remove Segment Routing information */ + ls_pref = subnet->ls_pref; + UNSET_FLAG(ls_pref->flags, LS_PREF_SR); + memset(&ls_pref->sr, 0, sizeof(struct ls_sid)); + subnet->status = UPDATE; + + /* Subnet has been updated: export it */ + ospf_te_export(LS_MSG_TYPE_PREFIX, subnet); + subnet->status = SYNC; + + return 0; +} + +/** + * Parse Opaque Extended Link LSA (Type 8) TLVs and update the corresponding + * Link State Edge with these information (Segment Routing Adjacency). + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_parse_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_node_id lnid; + struct tlv_header *tlvh; + struct ext_tlv_link *ext; + struct ls_edge *edge; + struct ls_attributes *atr; + uint16_t len = 0, sum = 0, i; + uint32_t label; + + /* Get corresponding Edge from Link State Data Base */ + lnid.origin = OSPFv2; + lnid.id.ip.addr = lsa->data->adv_router; + lnid.id.ip.area_id = lsa->area->area_id; + ext = (struct ext_tlv_link *)TLV_HDR_TOP(lsa->data); + edge = get_edge(ted, lnid, ext->link_data); + atr = edge->attributes; + + ote_debug(" |- Process Extended Link LSA %pI4 for edge %pI4", + &lsa->data->id, &edge->attributes->standard.local); + + /* Initialize TLV browsing */ + len = TLV_BODY_SIZE(&ext->header); + tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE + + EXT_TLV_LINK_SIZE); + for (; sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { + struct ext_subtlv_adj_sid *adj; + struct ext_subtlv_lan_adj_sid *ladj; + struct ext_subtlv_rmt_itf_addr *rmt; + + switch (ntohs(tlvh->type)) { + case EXT_SUBTLV_ADJ_SID: + adj = (struct ext_subtlv_adj_sid *)tlvh; + label = CHECK_FLAG(adj->flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG) + ? GET_LABEL(ntohl(adj->value)) + : ntohl(adj->value); + i = CHECK_FLAG(adj->flags, + EXT_SUBTLV_LINK_ADJ_SID_BFLG) ? 1 : 0; + if (((i && CHECK_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID)) + || (!i && CHECK_FLAG(atr->flags, LS_ATTR_ADJ_SID))) + && atr->adj_sid[i].flags == adj->flags + && atr->adj_sid[i].sid == label + && atr->adj_sid[i].weight == adj->weight) + break; + + atr->adj_sid[i].flags = adj->flags; + atr->adj_sid[i].sid = label; + atr->adj_sid[i].weight = adj->weight; + if (i == 0) + SET_FLAG(atr->flags, LS_ATTR_ADJ_SID); + else + SET_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID); + if (edge->status != NEW) + edge->status = UPDATE; + + break; + case EXT_SUBTLV_LAN_ADJ_SID: + ladj = (struct ext_subtlv_lan_adj_sid *)tlvh; + label = CHECK_FLAG(ladj->flags, + EXT_SUBTLV_LINK_ADJ_SID_VFLG) + ? GET_LABEL(ntohl(ladj->value)) + : ntohl(ladj->value); + i = CHECK_FLAG(ladj->flags, + EXT_SUBTLV_LINK_ADJ_SID_BFLG) ? 1 : 0; + if (((i && CHECK_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID)) + || (!i && CHECK_FLAG(atr->flags, LS_ATTR_ADJ_SID))) + && atr->adj_sid[i].flags == ladj->flags + && atr->adj_sid[i].sid == label + && atr->adj_sid[i].weight == ladj->weight + && IPV4_ADDR_SAME(&atr->adj_sid[1].neighbor.addr, + &ladj->neighbor_id)) + break; + + atr->adj_sid[i].flags = ladj->flags; + atr->adj_sid[i].sid = label; + atr->adj_sid[i].weight = ladj->weight; + atr->adj_sid[i].neighbor.addr = ladj->neighbor_id; + if (i == 0) + SET_FLAG(atr->flags, LS_ATTR_ADJ_SID); + else + SET_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID); + if (edge->status != NEW) + edge->status = UPDATE; + + break; + case EXT_SUBTLV_RMT_ITF_ADDR: + rmt = (struct ext_subtlv_rmt_itf_addr *)tlvh; + if (CHECK_FLAG(atr->flags, LS_ATTR_NEIGH_ADDR) + && IPV4_ADDR_SAME(&atr->standard.remote, + &rmt->value)) + break; + + atr->standard.remote = rmt->value; + SET_FLAG(atr->flags, LS_ATTR_NEIGH_ADDR); + if (edge->status != NEW) + edge->status = UPDATE; + + break; + default: + break; + } + sum += TLV_SIZE(tlvh); + } + + /* Export Link State Edge if needed */ + if (edge->status == NEW || edge->status == UPDATE) { + ote_debug(" |- %s Adj-SID %d & %d to edge %pI4", + edge->status == NEW ? "Add" : "Update", + edge->attributes->adj_sid[0].sid, + edge->attributes->adj_sid[1].sid, + &edge->attributes->standard.local); + + ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); + edge->status = SYNC; + } + + return 0; +} + +/** + * Delete Link State Edge information (Segment Routing Adjacency) that + * correspond to the Opaque Extended Link LSA (Type 8) TLVs. Note that the Edge + * is not removed. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_delete_ext_link(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + struct ls_edge *edge; + struct ls_attributes *atr; + struct ext_tlv_link *ext; + uint64_t key; + + /* Search for corresponding Edge from Link State Data Base */ + ext = (struct ext_tlv_link *)TLV_HDR_TOP(lsa->data); + key = ((uint64_t)ntohl(ext->link_data.s_addr)) & 0xffffffff; + edge = ls_find_edge_by_key(ted, key); + + /* Check if there is a corresponding Edge */ + if (!edge) + return -1; + + ote_debug(" |- Delete Adj-SID %d to edge %pI4", + edge->attributes->adj_sid[0].sid, + &edge->attributes->standard.local); + + /* Remove Segment Routing information */ + atr = edge->attributes; + UNSET_FLAG(atr->flags, LS_ATTR_ADJ_SID); + UNSET_FLAG(atr->flags, LS_ATTR_BCK_ADJ_SID); + memset(atr->adj_sid, 0, 2 * sizeof(struct ls_sid)); + edge->status = UPDATE; + + /* Edge has been updated: export it */ + ospf_te_export(LS_MSG_TYPE_ATTRIBUTES, edge); + edge->status = SYNC; + + return 0; +} + +/** + * Parse Opaque LSA Type and call corresponding parser. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_parse_opaque_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + uint8_t key = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)); + int rc = -1; + + ote_debug("MPLS-TE (%s): Parse Opaque LSA[%pI4] from Router[%pI4]", + __func__, &lsa->data->id, &lsa->data->adv_router); + + switch (key) { + case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA: + case OPAQUE_TYPE_INTER_AS_LSA: + rc = ospf_te_parse_te(ted, lsa); + break; + case OPAQUE_TYPE_ROUTER_INFORMATION_LSA: + rc = ospf_te_parse_ri(ted, lsa); + break; + case OPAQUE_TYPE_EXTENDED_PREFIX_LSA: + rc = ospf_te_parse_ext_pref(ted, lsa); + break; + case OPAQUE_TYPE_EXTENDED_LINK_LSA: + rc = ospf_te_parse_ext_link(ted, lsa); + break; + default: + break; + } + + return rc; +} + +/** + * Parse Opaque LSA Type and call corresponding deletion function. + * + * @param ted Link State Traffic Engineering Database + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_te_delete_opaque_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) +{ + uint8_t key = GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)); + int rc = -1; + + ote_debug("MPLS-TE (%s): Parse Opaque LSA[%pI4] from Router[%pI4]", + __func__, &lsa->data->id, &lsa->data->adv_router); + + switch (key) { + case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA: + case OPAQUE_TYPE_INTER_AS_LSA: + rc = ospf_te_delete_te(ted, lsa); + break; + case OPAQUE_TYPE_ROUTER_INFORMATION_LSA: + rc = ospf_te_delete_ri(ted, lsa); + break; + case OPAQUE_TYPE_EXTENDED_PREFIX_LSA: + rc = ospf_te_delete_ext_pref(ted, lsa); + break; + case OPAQUE_TYPE_EXTENDED_LINK_LSA: + rc = ospf_te_delete_ext_link(ted, lsa); + break; + default: + break; + } + + return rc; +} + +/** + * Update Traffic Engineering Database Elements that correspond to the received + * OSPF LSA. If LSA age is equal to MAX_AGE, call deletion function instead. + * + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_mpls_te_lsa_update(struct ospf_lsa *lsa) +{ + + uint8_t rc; + + /* Check that MPLS-TE is active */ + if (!OspfMplsTE.enabled || !OspfMplsTE.ted) + return 0; + + /* Sanity Check */ + if (lsa == NULL) { + flog_warn(EC_OSPF_LSA_NULL, "TE (%s): Abort! LSA is NULL", + __func__); + return -1; + } + + /* If LSA is MAX_AGE, remove corresponding Link State element */ + if (IS_LSA_MAXAGE(lsa)) { + switch (lsa->data->type) { + case OSPF_ROUTER_LSA: + rc = ospf_te_delete_router_lsa(OspfMplsTE.ted, lsa); + break; + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + rc = ospf_te_delete_opaque_lsa(OspfMplsTE.ted, lsa); + break; + default: + rc = 0; + break; + } + } else { + /* Parse LSA to Update corresponding Link State element */ + switch (lsa->data->type) { + case OSPF_ROUTER_LSA: + rc = ospf_te_parse_router_lsa(OspfMplsTE.ted, lsa); + break; + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + rc = ospf_te_parse_opaque_lsa(OspfMplsTE.ted, lsa); + break; + default: + rc = 0; + break; + } + } + + return rc; +} + +/** + * Delete Traffic Engineering Database element from OSPF LSA. This function + * process only self LSA (i.e. advertised by the router) which reach MAX_AGE + * as LSA deleted by neighbor routers are Flushed (i.e. advertised with + * age == MAX_AGE) and processed by ospf_mpls_te_lsa_update() function. + * + * @param lsa OSPF Link State Advertisement + * + * @return 0 if success, -1 otherwise + */ +static int ospf_mpls_te_lsa_delete(struct ospf_lsa *lsa) +{ + + uint8_t rc; + + /* Check that MPLS-TE is active */ + if (!OspfMplsTE.enabled || !OspfMplsTE.ted) + return 0; + + /* Sanity Check */ + if (lsa == NULL) { + flog_warn(EC_OSPF_LSA_NULL, "TE (%s): Abort! LSA is NULL", + __func__); + return -1; + } + + /* + * Process only self LSAs that reach MAX_AGE. Indeed, when the router + * need to update or refresh an LSA, it first removes the old LSA from + * the LSDB and then insert the new one. Thus, to avoid removing + * corresponding Link State element and loosing some parameters + * instead of just updating it, only self LSAs that reach MAX_AGE are + * processed here. Other LSAs are processed by ospf_mpls_te_lsa_update() + * and eventually removed when LSA age is MAX_AGE i.e. LSA is flushed + * by the originator. + */ + if (!IS_LSA_SELF(lsa) || !IS_LSA_MAXAGE(lsa)) + return 0; + + /* Parse Link State information */ + switch (lsa->data->type) { + case OSPF_ROUTER_LSA: + rc = ospf_te_delete_router_lsa(OspfMplsTE.ted, lsa); + break; + case OSPF_OPAQUE_AREA_LSA: + case OSPF_OPAQUE_AS_LSA: + rc = ospf_te_delete_opaque_lsa(OspfMplsTE.ted, lsa); + break; + default: + rc = 0; + break; + } + + return rc; +} + +/** + * Send the whole Link State Traffic Engineering Database to the consumer that + * request it through a ZAPI Link State Synchronous Opaque Message. + * + * @param info ZAPI Opaque message + * + * @return 0 if success, -1 otherwise + */ +int ospf_te_sync_ted(struct zapi_opaque_reg_info dst) +{ + int rc = -1; + + /* Check that MPLS-TE and TE distribution are enabled */ + if (!OspfMplsTE.enabled || !OspfMplsTE.export) + return rc; + + rc = ls_sync_ted(OspfMplsTE.ted, zclient, &dst); + + return rc; +} + +/** + * Initialize Traffic Engineering Database from the various OSPF Link State + * Database (LSDB). + * + * @param ted Link State Traffice Engineering Database + * @param ospf OSPF main structure + */ +static void ospf_te_init_ted(struct ls_ted *ted, struct ospf *ospf) +{ + struct listnode *node, *nnode; + struct route_node *rn; + struct ospf_area *area; + struct ospf_lsa *lsa; + + /* Iterate over all areas. */ + for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { + if (!area->lsdb) + continue; + + /* Parse all Router LSAs from the area LSDB */ + LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) + ospf_te_parse_router_lsa(ted, lsa); + + /* Parse all Opaque LSAs from the area LSDB */ + LSDB_LOOP (OPAQUE_AREA_LSDB(area), rn, lsa) + ospf_te_parse_opaque_lsa(ted, lsa); + } + + /* Parse AS-external opaque LSAs from OSPF LSDB */ + if (ospf->lsdb) { + LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa) + ospf_te_parse_opaque_lsa(ted, lsa); + } + +} /*------------------------------------------------------------------------* * Followings are vty session control functions. @@ -2157,14 +3716,15 @@ static void ospf_mpls_te_config_write_router(struct vty *vty) vty_out(vty, " mpls-te on\n"); vty_out(vty, " mpls-te router-address %pI4\n", &OspfMplsTE.router_addr.value); - } - - if (OspfMplsTE.inter_as == AS) - vty_out(vty, " mpls-te inter-as as\n"); - if (OspfMplsTE.inter_as == Area) - vty_out(vty, " mpls-te inter-as area %pI4 \n", - &OspfMplsTE.interas_areaid); + if (OspfMplsTE.inter_as == AS) + vty_out(vty, " mpls-te inter-as as\n"); + if (OspfMplsTE.inter_as == Area) + vty_out(vty, " mpls-te inter-as area %pI4 \n", + &OspfMplsTE.interas_areaid); + if (OspfMplsTE.export) + vty_out(vty, " mpls-te export\n"); + } return; } @@ -2185,8 +3745,7 @@ DEFUN (ospf_mpls_te_on, if (OspfMplsTE.enabled) return CMD_SUCCESS; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("MPLS-TE: OFF -> ON"); + ote_debug("MPLS-TE: OFF -> ON"); OspfMplsTE.enabled = true; @@ -2204,6 +3763,14 @@ DEFUN (ospf_mpls_te_on, } } + /* Create TED and initialize it */ + OspfMplsTE.ted = ls_ted_new(1, "OSPF", 0); + if (!OspfMplsTE.ted) { + vty_out(vty, "Unable to create Link State Data Base\n"); + return CMD_WARNING; + } + ospf_te_init_ted(OspfMplsTE.ted, ospf); + return CMD_SUCCESS; } @@ -2221,11 +3788,13 @@ DEFUN (no_ospf_mpls_te, if (!OspfMplsTE.enabled) return CMD_SUCCESS; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("MPLS-TE: ON -> OFF"); + ote_debug("MPLS-TE: ON -> OFF"); + /* Remove TED */ + ls_ted_del_all(OspfMplsTE.ted); OspfMplsTE.enabled = false; + /* Flush all TE Opaque LSAs */ for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) if (CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); @@ -2235,16 +3804,11 @@ DEFUN (no_ospf_mpls_te, * This is to avoid having an inter-as value different from * Off when mpls-te gets restarted (after being removed) */ - if (OspfMplsTE.inter_as != Off) { - /* Deregister the Callbacks for Inter-AS support */ - ospf_mpls_te_unregister(); - OspfMplsTE.inter_as = Off; - } + OspfMplsTE.inter_as = Off; return CMD_SUCCESS; } - DEFUN (ospf_mpls_te_router_addr, ospf_mpls_te_router_addr_cmd, "mpls-te router-address A.B.C.D", @@ -2274,7 +3838,7 @@ DEFUN (ospf_mpls_te_router_addr, return CMD_SUCCESS; for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { - if ((lp->area == NULL) || IS_FLOOD_AS(lp->type)) + if ((lp->area == NULL) || IS_FLOOD_AS(lp->flags)) continue; if (!CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) { @@ -2284,7 +3848,7 @@ DEFUN (ospf_mpls_te_router_addr, } for (ALL_LIST_ELEMENTS(OspfMplsTE.iflist, node, nnode, lp)) { - if ((lp->area == NULL) || IS_FLOOD_AS(lp->type)) + if ((lp->area == NULL) || IS_FLOOD_AS(lp->flags)) continue; if (need_to_reoriginate) @@ -2324,18 +3888,9 @@ static int set_inter_as_mode(struct vty *vty, const char *mode_name, return CMD_WARNING; } - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "MPLS-TE: Inter-AS enable with %s flooding support", - mode2text[mode]); - - /* Register new callbacks regarding the flooding scope (AS or - * Area) */ - if (ospf_mpls_te_register(mode) < 0) { - vty_out(vty, - "Internal error: Unable to register Inter-AS functions\n"); - return CMD_WARNING; - } + ote_debug( + "MPLS-TE (%s): Inter-AS enable with %s flooding support", + __func__, mode2text[mode]); /* Enable mode and re-originate LSA if needed */ if ((OspfMplsTE.inter_as == Off) @@ -2346,9 +3901,11 @@ static int set_inter_as_mode(struct vty *vty, const char *mode_name, lp)) { if (IS_INTER_AS(lp->type)) { if (mode == AS) - lp->type |= FLOOD_AS; + SET_FLAG(lp->flags, + LPFLG_LSA_FLOOD_AS); else - lp->type |= FLOOD_AREA; + UNSET_FLAG(lp->flags, + LPFLG_LSA_FLOOD_AS); ospf_mpls_te_lsa_schedule( lp, REORIGINATE_THIS_LSA); } @@ -2401,8 +3958,7 @@ DEFUN (no_ospf_mpls_te_inter_as, struct listnode *node, *nnode; struct mpls_te_link *lp; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug("MPLS-TE: Inter-AS support OFF"); + ote_debug("MPLS-TE: Inter-AS support OFF"); if ((OspfMplsTE.enabled) && (OspfMplsTE.inter_as != Off)) { /* Flush all Inter-AS LSA */ @@ -2411,14 +3967,55 @@ DEFUN (no_ospf_mpls_te_inter_as, && CHECK_FLAG(lp->flags, LPFLG_LSA_ENGAGED)) ospf_mpls_te_lsa_schedule(lp, FLUSH_THIS_LSA); - /* Deregister the Callbacks for Inter-AS support */ - ospf_mpls_te_unregister(); OspfMplsTE.inter_as = Off; } return CMD_SUCCESS; } +DEFUN (ospf_mpls_te_export, + ospf_mpls_te_export_cmd, + "mpls-te export", + MPLS_TE_STR + "Export the MPLS-TE information as Link State\n") +{ + + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + if (OspfMplsTE.enabled) { + if (ls_register(zclient, true) != 0) { + vty_out(vty, "Unable to register Link State\n"); + return CMD_WARNING; + } + OspfMplsTE.export = true; + } else { + vty_out(vty, "mpls-te has not been turned on\n"); + return CMD_WARNING; + } + return CMD_SUCCESS; +} + + +DEFUN (no_ospf_mpls_te_export, + no_ospf_mpls_te_export_cmd, + "no mpls-te export", + NO_STR + MPLS_TE_STR + "Stop export of the MPLS-TE information as Link State\n") +{ + + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + if (OspfMplsTE.export) { + if (ls_unregister(zclient, true) != 0) { + vty_out(vty, "Unable to unregister Link State\n"); + return CMD_WARNING; + } + OspfMplsTE.export = false; + } + return CMD_SUCCESS; +} + DEFUN (show_ip_ospf_mpls_te_router, show_ip_ospf_mpls_te_router_cmd, "show ip ospf mpls-te router", @@ -2435,7 +4032,9 @@ DEFUN (show_ip_ospf_mpls_te_router, show_vty_router_addr(vty, &OspfMplsTE.router_addr.header); else - vty_out(vty, " N/A\n"); + vty_out(vty, " Router address is not set\n"); + vty_out(vty, " Link State distribution is %s\n", + OspfMplsTE.export ? "Active" : "Inactive"); } return CMD_SUCCESS; } @@ -2592,10 +4191,142 @@ DEFUN (show_ip_ospf_mpls_te_link, return CMD_SUCCESS; } +DEFUN (show_ip_ospf_mpls_te_db, + show_ip_ospf_mpls_te_db_cmd, + "show ip ospf mpls-te database [<vertex [<self-originate|adv-router A.B.C.D>]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]", + SHOW_STR + IP_STR + OSPF_STR + "MPLS-TE information\n" + "MPLS-TE database\n" + "MPLS-TE Vertex\n" + "Self-originated MPLS-TE router\n" + "Advertised MPLS-TE router\n" + "MPLS-TE router ID (as an IP address)\n" + "MPLS-TE Edge\n" + "MPLS-TE Edge ID (as an IP address)\n" + "MPLS-TE Subnet\n" + "MPLS-TE Subnet ID (as an IP prefix)\n" + "Verbose output\n" + JSON_STR) +{ + int idx = 0; + struct in_addr ip_addr; + struct prefix pref; + struct ls_vertex *vertex; + struct ls_edge *edge; + struct ls_subnet *subnet; + uint64_t key; + bool verbose = false; + bool uj = use_json(argc, argv); + json_object *json = NULL; + + if (!OspfMplsTE.enabled || !OspfMplsTE.ted) { + vty_out(vty, "MPLS-TE database is not enabled\n"); + return CMD_WARNING; + } + + if (uj) + json = json_object_new_object(); + + if (argv[argc - 1]->arg && strmatch(argv[argc - 1]->text, "verbose")) + verbose = true; + + idx = 5; + if (argv_find(argv, argc, "vertex", &idx)) { + /* Show Vertex */ + if (argv_find(argv, argc, "self-originate", &idx)) + vertex = OspfMplsTE.ted->self; + else if (argv_find(argv, argc, "adv-router", &idx)) { + if (!inet_aton(argv[idx + 1]->arg, &ip_addr)) { + vty_out(vty, + "Specified Router ID %s is invalid\n", + argv[idx + 1]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + /* Get the Vertex from the Link State Database */ + key = ((uint64_t)ntohl(ip_addr.s_addr)) & 0xffffffff; + vertex = ls_find_vertex_by_key(OspfMplsTE.ted, key); + if (!vertex) { + vty_out(vty, "No vertex found for ID %pI4\n", + &ip_addr); + return CMD_WARNING; + } + } else + vertex = NULL; + + if (vertex) + ls_show_vertex(vertex, vty, json, verbose); + else + ls_show_vertices(OspfMplsTE.ted, vty, json, verbose); + + } else if (argv_find(argv, argc, "edge", &idx)) { + /* Show Edge */ + if (argv_find(argv, argc, "A.B.C.D", &idx)) { + if (!inet_aton(argv[idx]->arg, &ip_addr)) { + vty_out(vty, + "Specified Edge ID %s is invalid\n", + argv[idx]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + /* Get the Edge from the Link State Database */ + key = ((uint64_t)ntohl(ip_addr.s_addr)) & 0xffffffff; + edge = ls_find_edge_by_key(OspfMplsTE.ted, key); + if (!edge) { + vty_out(vty, "No edge found for ID %pI4\n", + &ip_addr); + return CMD_WARNING; + } + } else + edge = NULL; + + if (edge) + ls_show_edge(edge, vty, json, verbose); + else + ls_show_edges(OspfMplsTE.ted, vty, json, verbose); + + } else if (argv_find(argv, argc, "subnet", &idx)) { + /* Show Subnet */ + if (argv_find(argv, argc, "A.B.C.D/M", &idx)) { + if (!str2prefix(argv[idx]->arg, &pref)) { + vty_out(vty, "Invalid prefix format %s\n", + argv[idx]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + /* Get the Subnet from the Link State Database */ + subnet = ls_find_subnet(OspfMplsTE.ted, pref); + if (!subnet) { + vty_out(vty, "No subnet found for ID %pFX\n", + &pref); + return CMD_WARNING; + } + } else + subnet = NULL; + + if (subnet) + ls_show_subnet(subnet, vty, json, verbose); + else + ls_show_subnets(OspfMplsTE.ted, vty, json, verbose); + + } else { + /* Show the complete TED */ + ls_show_ted(OspfMplsTE.ted, vty, json, verbose); + } + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; +} + static void ospf_mpls_te_register_vty(void) { install_element(VIEW_NODE, &show_ip_ospf_mpls_te_router_cmd); install_element(VIEW_NODE, &show_ip_ospf_mpls_te_link_cmd); + install_element(VIEW_NODE, &show_ip_ospf_mpls_te_db_cmd); install_element(OSPF_NODE, &ospf_mpls_te_on_cmd); install_element(OSPF_NODE, &no_ospf_mpls_te_cmd); @@ -2603,6 +4334,8 @@ static void ospf_mpls_te_register_vty(void) install_element(OSPF_NODE, &ospf_mpls_te_inter_as_cmd); install_element(OSPF_NODE, &ospf_mpls_te_inter_as_area_cmd); install_element(OSPF_NODE, &no_ospf_mpls_te_inter_as_cmd); + install_element(OSPF_NODE, &ospf_mpls_te_export_cmd); + install_element(OSPF_NODE, &no_ospf_mpls_te_export_cmd); return; } diff --git a/ospfd/ospf_te.h b/ospfd/ospf_te.h index 06c17f07fe..fc9ca20780 100644 --- a/ospfd/ospf_te.h +++ b/ospfd/ospf_te.h @@ -74,25 +74,29 @@ #define GMPLS 0x02 #define INTER_AS 0x04 #define PSEUDO_TE 0x08 -#define FLOOD_AREA 0x10 -#define FLOOD_AS 0x20 -#define EMULATED 0x80 +#define EMULATED 0x10 -#define IS_STD_TE(x) (x & STD_TE) +#define IS_STD_TE(x) (x & STD_TE) #define IS_PSEUDO_TE(x) (x & PSEUDO_TE) #define IS_INTER_AS(x) (x & INTER_AS) #define IS_EMULATED(x) (x & EMULATED) -#define IS_FLOOD_AREA(x) (x & FLOOD_AREA) -#define IS_FLOOD_AS(x) (x & FLOOD_AS) -#define IS_INTER_AS_EMU(x) (x & INTER_AS & EMULATED) -#define IS_INTER_AS_AS(x) (x & INTER_AS & FLOOD_AS) /* Flags to manage TE Link LSA */ -#define LPFLG_LSA_INACTIVE 0x0 -#define LPFLG_LSA_ACTIVE 0x1 -#define LPFLG_LSA_ENGAGED 0x2 -#define LPFLG_LOOKUP_DONE 0x4 -#define LPFLG_LSA_FORCED_REFRESH 0x8 +#define LPFLG_LSA_INACTIVE 0x00 +#define LPFLG_LSA_ACTIVE 0x01 +#define LPFLG_LSA_ENGAGED 0x02 +#define LPFLG_LOOKUP_DONE 0x04 +#define LPFLG_LSA_FORCED_REFRESH 0x08 +#define LPFLG_LSA_FLOOD_AS 0x10 + +#define IS_FLOOD_AS(x) (x & LPFLG_LSA_FLOOD_AS) + +/* Macro to log debug message */ +#define ote_debug(...) \ + do { \ + if (IS_DEBUG_OSPF_TE) \ + zlog_debug(__VA_ARGS__); \ + } while (0) /* * Following section defines TLV body parts. @@ -336,9 +340,13 @@ struct te_link_subtlv { /* Following structure are internal use only. */ struct ospf_mpls_te { - /* Status of MPLS-TE: enable or disbale */ + /* Status of MPLS-TE: enable or disable */ bool enabled; + /* Traffic Engineering Database i.e. Link State */ + struct ls_ted *ted; + bool export; + /* RFC5392 */ enum inter_as_mode inter_as; struct in_addr interas_areaid; @@ -414,4 +422,15 @@ extern void set_linkparams_llri(struct mpls_te_link *, uint32_t, uint32_t); extern void set_linkparams_lrrid(struct mpls_te_link *, struct in_addr, struct in_addr); +struct zapi_opaque_reg_info; +/** + * Call when a client send a Link State Sync message. In turn, OSPF will send + * the contain of the Link State Data base. + * + * @param info ZAPI Opaque message information + * + * @return 0 on success, -1 otherwise + */ +extern int ospf_te_sync_ted(struct zapi_opaque_reg_info dst); + #endif /* _ZEBRA_OSPF_MPLS_TE_H */ diff --git a/ospfd/ospf_ti_lfa.c b/ospfd/ospf_ti_lfa.c index 4a0186bfb9..59b3b624e3 100644 --- a/ospfd/ospf_ti_lfa.c +++ b/ospfd/ospf_ti_lfa.c @@ -37,9 +37,9 @@ DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item, - p_spaces_compare_func) + p_spaces_compare_func); DECLARE_RBTREE_UNIQ(q_spaces, struct q_space, q_spaces_item, - q_spaces_compare_func) + q_spaces_compare_func); static void ospf_ti_lfa_generate_p_space(struct ospf_area *area, struct vertex *child, diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 2ff59ccf49..a1dac641d7 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -60,7 +60,7 @@ FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, -) +); static const char *const ospf_network_type_str[] = { "Null", "POINTOPOINT", "BROADCAST", "NBMA", "POINTOMULTIPOINT", @@ -577,6 +577,7 @@ DEFUN (ospf_network_area, struct prefix_ipv4 p; struct in_addr area_id; int ret, format; + uint32_t count; if (ospf->instance) { vty_out(vty, @@ -584,14 +585,15 @@ DEFUN (ospf_network_area, return CMD_WARNING_CONFIG_FAILED; } - if (ospf->if_ospf_cli_count > 0) { + count = ospf_count_area_params(ospf); + if (count > 0) { vty_out(vty, "Please remove all ip ospf area x.x.x.x commands first.\n"); if (IS_DEBUG_OSPF_EVENT) zlog_debug( "%s ospf vrf %s num of %u ip ospf area x config", __func__, ospf->name ? ospf->name : "NIL", - ospf->if_ospf_cli_count); + count); return CMD_WARNING_CONFIG_FAILED; } @@ -1574,6 +1576,58 @@ DEFUN (ospf_area_nssa, return ospf_area_nssa_cmd_handler(vty, argc, argv, 0, 0); } +DEFUN(ospf_area_nssa_suppress_fa, ospf_area_nssa_suppress_fa_cmd, + "area <A.B.C.D|(0-4294967295)> nssa suppress-fa", + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Suppress forwarding address\n") +{ + int idx_ipv4_number = 1; + struct in_addr area_id; + int format; + + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + VTY_GET_OSPF_AREA_ID_NO_BB("NSSA", area_id, format, + argv[idx_ipv4_number]->arg); + + ospf_area_display_format_set(ospf, ospf_area_get(ospf, area_id), + format); + ospf_area_nssa_suppress_fa_set(ospf, area_id); + + ospf_schedule_abr_task(ospf); + + return CMD_SUCCESS; +} + +DEFUN(no_ospf_area_nssa_suppress_fa, no_ospf_area_nssa_suppress_fa_cmd, + "no area <A.B.C.D|(0-4294967295)> nssa suppress-fa", + NO_STR + "OSPF area parameters\n" + "OSPF area ID in IP address format\n" + "OSPF area ID as a decimal value\n" + "Configure OSPF area as nssa\n" + "Suppress forwarding address\n") +{ + int idx_ipv4_number = 2; + struct in_addr area_id; + int format; + + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + VTY_GET_OSPF_AREA_ID_NO_BB("nssa", area_id, format, + argv[idx_ipv4_number]->arg); + + ospf_area_display_format_set(ospf, ospf_area_get(ospf, area_id), + format); + ospf_area_nssa_suppress_fa_unset(ospf, area_id); + + ospf_schedule_abr_task(ospf); + + return CMD_SUCCESS; +} + DEFUN (ospf_area_nssa_no_summary, ospf_area_nssa_no_summary_cmd, "area <A.B.C.D|(0-4294967295)> nssa no-summary", @@ -2645,6 +2699,50 @@ DEFUN(no_ospf_ti_lfa, no_ospf_ti_lfa_cmd, return CMD_SUCCESS; } +static void ospf_maxpath_set(struct vty *vty, struct ospf *ospf, uint16_t paths) +{ + if (ospf->max_multipath == paths) + return; + + ospf->max_multipath = paths; + + /* Send deletion notification to zebra to delete all + * ospf specific routes and reinitiat SPF to reflect + * the new max multipath. + */ + ospf_restart_spf(ospf); +} + +/* Ospf Maximum multiple paths config support */ +DEFUN (ospf_max_multipath, + ospf_max_multipath_cmd, + "maximum-paths " CMD_RANGE_STR(1, MULTIPATH_NUM), + "Max no of multiple paths for ECMP support\n" + "Number of paths\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + int idx_number = 1; + uint16_t maxpaths; + + maxpaths = strtol(argv[idx_number]->arg, NULL, 10); + + ospf_maxpath_set(vty, ospf, maxpaths); + return CMD_SUCCESS; +} + +DEFUN (no_ospf_max_multipath, + no_ospf_max_multipath_cmd, + "no maximum-paths", + NO_STR + "Max no of multiple paths for ECMP support\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + uint16_t maxpaths = MULTIPATH_NUM; + + ospf_maxpath_set(vty, ospf, maxpaths); + return CMD_SUCCESS; +} + static const char *const ospf_abr_type_descr_str[] = { "Unknown", "Standard (RFC2328)", "Alternative IBM", "Alternative Cisco", "Alternative Shortcut" @@ -3174,6 +3272,10 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf, /* Show refresh parameters. */ vty_out(vty, " Refresh timer %d secs\n", ospf->lsa_refresh_interval); + + /* show max multipath */ + vty_out(vty, " Maximum multiple paths(ECMP) supported %d\n", + ospf->max_multipath); } /* Show ABR/ASBR flags. */ @@ -3776,7 +3878,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, " Neighbor Count is %d, Adjacent neighbor count is %d\n", ospf_nbr_count(oi, 0), ospf_nbr_count(oi, NSM_Full)); - ospf_bfd_interface_show(vty, ifp, json_interface_sub, use_json); + + ospf_interface_bfd_show(vty, ifp, json_interface_sub); /* OSPF Authentication information */ ospf_interface_auth_show(vty, oi, json_interface_sub, use_json); @@ -5282,7 +5385,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, .helper_exit_reason)); } - ospf_bfd_show_info(vty, nbr->bfd_info, json_neigh, use_json, 0); + bfd_sess_show(vty, json_neigh, nbr->bfd_session); if (use_json) json_object_array_add(json_neigh_array, json_neigh); @@ -7109,14 +7212,14 @@ DEFUN (show_ip_ospf_database_max, return ret; } -DEFUN (show_ip_ospf_instance_database, - show_ip_ospf_instance_database_cmd, - "show ip ospf [{(1-65535)|vrf NAME}] database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]", +ALIAS (show_ip_ospf_database_max, + show_ip_ospf_database_cmd, + "show ip ospf [vrf <NAME|all>] database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]", SHOW_STR IP_STR "OSPF information\n" - "Instance ID\n" VRF_CMD_HELP_STR + "All VRFs\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Link State ID (as an IP address)\n" @@ -7124,78 +7227,6 @@ DEFUN (show_ip_ospf_instance_database, "Advertising Router link states\n" "Advertising Router (as an IP address)\n" JSON_STR) -{ - struct ospf *ospf; - unsigned short instance = 0; - struct listnode *node = NULL; - char *vrf_name = NULL; - bool all_vrf = false; - int ret = CMD_SUCCESS; - int inst = 0; - int idx = 0; - uint8_t use_vrf = 0; - bool uj = use_json(argc, argv); - json_object *json = NULL; - - if (uj) - json = json_object_new_object(); - - if (argv_find(argv, argc, "(1-65535)", &idx)) { - instance = strtoul(argv[idx]->arg, NULL, 10); - if (instance != ospf_instance) - return CMD_NOT_MY_INSTANCE; - - ospf = ospf_lookup_instance(instance); - if (!ospf || !ospf->oi_running) - return CMD_SUCCESS; - - return (show_ip_ospf_database_common( - vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj)); - } else if (argv_find(argv, argc, "vrf", &idx)) { - vrf_name = argv[++idx]->arg; - all_vrf = strmatch(vrf_name, "all"); - } - - if (vrf_name) { - use_vrf = 1; - if (all_vrf) { - for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { - if (!ospf->oi_running) - continue; - ret = (show_ip_ospf_database_common( - vty, ospf, idx ? 2 : 0, argc, argv, - use_vrf, json, uj)); - } - } else { - ospf = ospf_lookup_by_inst_name(inst, vrf_name); - if ((ospf == NULL) || !ospf->oi_running) { - vty_out(vty, "%% OSPF instance not found\n"); - return CMD_SUCCESS; - } - - ret = (show_ip_ospf_database_common( - vty, ospf, idx ? 2 : 0, argc, argv, use_vrf, - json, uj)); - } - } else { - /* Display default ospf (instance 0) info */ - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - if (ospf == NULL || !ospf->oi_running) { - vty_out(vty, "%% OSPF instance not found\n"); - return CMD_SUCCESS; - } - - ret = (show_ip_ospf_database_common(vty, ospf, 0, argc, argv, - use_vrf, json, uj)); - } - - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string(json)); - json_object_free(json); - } - - return ret; -} DEFUN (show_ip_ospf_instance_database_max, show_ip_ospf_instance_database_max_cmd, @@ -7238,6 +7269,20 @@ DEFUN (show_ip_ospf_instance_database_max, return CMD_SUCCESS; } +ALIAS (show_ip_ospf_instance_database_max, + show_ip_ospf_instance_database_cmd, + "show ip ospf (1-65535) database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]", + SHOW_STR + IP_STR + "OSPF information\n" + "Instance ID\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Link State ID (as an IP address)\n" + "Self-originated link states\n" + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n" + JSON_STR) static int show_ip_ospf_database_type_adv_router_common(struct vty *vty, struct ospf *ospf, @@ -7327,14 +7372,14 @@ static int show_ip_ospf_database_type_adv_router_common(struct vty *vty, return CMD_SUCCESS; } -DEFUN (show_ip_ospf_instance_database_type_adv_router, - show_ip_ospf_instance_database_type_adv_router_cmd, - "show ip ospf [{(1-65535)|vrf NAME}] database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]", +DEFUN (show_ip_ospf_database_type_adv_router, + show_ip_ospf_database_type_adv_router_cmd, + "show ip ospf [vrf <NAME|all>] database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]", SHOW_STR IP_STR "OSPF information\n" - "Instance ID\n" VRF_CMD_HELP_STR + "All VRFs\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Advertising Router link states\n" @@ -7343,13 +7388,12 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, JSON_STR) { struct ospf *ospf = NULL; - unsigned short instance = 0; struct listnode *node = NULL; char *vrf_name = NULL; bool all_vrf = false; int ret = CMD_SUCCESS; int inst = 0; - int idx = 0, idx_vrf = 0; + int idx_vrf = 0; uint8_t use_vrf = 0; bool uj = use_json(argc, argv); json_object *json = NULL; @@ -7357,19 +7401,6 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, if (uj) json = json_object_new_object(); - if (argv_find(argv, argc, "(1-65535)", &idx)) { - instance = strtoul(argv[idx]->arg, NULL, 10); - if (instance != ospf_instance) - return CMD_NOT_MY_INSTANCE; - - ospf = ospf_lookup_instance(instance); - if (!ospf || !ospf->oi_running) - return CMD_SUCCESS; - - return (show_ip_ospf_database_type_adv_router_common( - vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj)); - } - OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); if (vrf_name) { @@ -7407,7 +7438,7 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, } ret = show_ip_ospf_database_type_adv_router_common( - vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj); + vty, ospf, 0, argc, argv, use_vrf, json, uj); } if (uj) { @@ -7416,8 +7447,50 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, } return ret; - /*return (show_ip_ospf_database_type_adv_router_common( - vty, ospf, idx ? 1 : 0, argc, argv));*/ +} + +DEFUN (show_ip_ospf_instance_database_type_adv_router, + show_ip_ospf_instance_database_type_adv_router_cmd, + "show ip ospf (1-65535) database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]", + SHOW_STR + IP_STR + "OSPF information\n" + "Instance ID\n" + "Database summary\n" + OSPF_LSA_TYPES_DESC + "Advertising Router link states\n" + "Advertising Router (as an IP address)\n" + "Self-originated link states\n" + JSON_STR) +{ + int idx_number = 3; + struct ospf *ospf; + unsigned short instance = 0; + bool uj = use_json(argc, argv); + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); + + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; + + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) + return CMD_SUCCESS; + + show_ip_ospf_database_type_adv_router_common(vty, ospf, 1, argc, argv, + 0, json, uj); + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + + return CMD_SUCCESS; } DEFUN (ip_ospf_authentication_args, @@ -8850,10 +8923,8 @@ DEFUN (ip_ospf_area, if (count > 0) { ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); - if (ospf) { + if (ospf) ospf_interface_area_unset(ospf, ifp); - ospf->if_ospf_cli_count -= count; - } } return CMD_NOT_MY_INSTANCE; @@ -8897,9 +8968,12 @@ DEFUN (ip_ospf_area, // update/create address-level params params = ospf_get_if_params((ifp), (addr)); if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { - vty_out(vty, - "Must remove previous area/address config before changing ospf area\n"); - return CMD_WARNING_CONFIG_FAILED; + if (!IPV4_ADDR_SAME(¶ms->if_area, &area_id)) { + vty_out(vty, + "Must remove previous area/address config before changing ospf area\n"); + return CMD_WARNING_CONFIG_FAILED; + } else + return CMD_SUCCESS; } ospf_if_update_params((ifp), (addr)); } @@ -8911,10 +8985,8 @@ DEFUN (ip_ospf_area, params->if_area_id_fmt = format; } - if (ospf) { + if (ospf) ospf_interface_area_set(ospf, ifp); - ospf->if_ospf_cli_count++; - } return CMD_SUCCESS; } @@ -8980,7 +9052,6 @@ DEFUN (no_ip_ospf_area, if (ospf) { ospf_interface_area_unset(ospf, ifp); - ospf->if_ospf_cli_count--; ospf_area_check_free(ospf, area_id); } @@ -11716,7 +11787,7 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) } /* bfd print. */ - if (params && params->bfd_info) + if (params && params->bfd_config) ospf_bfd_write_config(vty, params); /* MTU ignore print. */ @@ -11852,6 +11923,10 @@ static int config_write_ospf_area(struct vty *vty, struct ospf *ospf) vty_out(vty, " area %s nssa no-summary\n", buf); + if (area->suppress_fa) + vty_out(vty, + " area %s nssa suppress-fa\n", + buf); } if (area->default_cost != 1) @@ -12250,6 +12325,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf) vty_out(vty, " ospf write-multiplier %d\n", ospf->write_oi_count); + if (ospf->max_multipath != MULTIPATH_NUM) + vty_out(vty, " maximum-paths %d\n", ospf->max_multipath); + /* Max-metric router-lsa print */ config_write_stub_router(vty, ospf); @@ -12375,8 +12453,10 @@ void ospf_vty_show_init(void) install_element(VIEW_NODE, &show_ip_ospf_instance_cmd); /* "show ip ospf database" commands. */ + install_element(VIEW_NODE, &show_ip_ospf_database_cmd); install_element(VIEW_NODE, &show_ip_ospf_database_max_cmd); - + install_element(VIEW_NODE, + &show_ip_ospf_database_type_adv_router_cmd); install_element(VIEW_NODE, &show_ip_ospf_instance_database_type_adv_router_cmd); install_element(VIEW_NODE, &show_ip_ospf_instance_database_cmd); @@ -12711,6 +12791,8 @@ void ospf_vty_init(void) install_element(OSPF_NODE, &ospf_area_nssa_translate_cmd); install_element(OSPF_NODE, &ospf_area_nssa_no_summary_cmd); install_element(OSPF_NODE, &no_ospf_area_nssa_no_summary_cmd); + install_element(OSPF_NODE, &ospf_area_nssa_suppress_fa_cmd); + install_element(OSPF_NODE, &no_ospf_area_nssa_suppress_fa_cmd); install_element(OSPF_NODE, &no_ospf_area_nssa_cmd); install_element(OSPF_NODE, &ospf_area_default_cost_cmd); @@ -12774,6 +12856,10 @@ void ospf_vty_init(void) install_element(OSPF_NODE, &ospf_ti_lfa_cmd); install_element(OSPF_NODE, &no_ospf_ti_lfa_cmd); + /* Max path configurations */ + install_element(OSPF_NODE, &ospf_max_multipath_cmd); + install_element(OSPF_NODE, &no_ospf_max_multipath_cmd); + /* Init interface related vty commands. */ ospf_vty_if_init(); diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index a2fbd01ab8..a2ce4d1ce7 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -53,9 +53,9 @@ #include "ospfd/ospf_sr.h" #include "ospfd/ospf_ldp_sync.h" -DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table") -DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute") -DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments") +DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table"); +DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute"); +DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments"); /* Zebra structure to hold current status. */ @@ -297,7 +297,7 @@ void ospf_zebra_add(struct ospf *ospf, struct prefix_ipv4 *p, } for (ALL_LIST_ELEMENTS_RO(or->paths, node, path)) { - if (api.nexthop_num >= MULTIPATH_NUM) + if (api.nexthop_num >= ospf->max_multipath) break; ospf_zebra_add_nexthop(ospf, path, &api); @@ -2043,6 +2043,7 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS) struct zapi_opaque_msg info; struct ldp_igp_sync_if_state state; struct ldp_igp_sync_announce announce; + struct zapi_opaque_reg_info dst; int ret = 0; s = zclient->ibuf; @@ -2051,6 +2052,13 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS) return -1; switch (info.type) { + case LINK_STATE_SYNC: + STREAM_GETC(s, dst.proto); + STREAM_GETW(s, dst.instance); + STREAM_GETL(s, dst.session_id); + dst.type = LINK_STATE_SYNC; + ret = ospf_te_sync_ted(dst); + break; case LDP_IGP_SYNC_IF_STATE_UPDATE: STREAM_GET(&state, s, sizeof(state)); ret = ospf_ldp_sync_state_update(state); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 9590a9c73b..259209a736 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -42,6 +42,7 @@ #include "ldp_sync.h" #include "ospfd/ospfd.h" +#include "ospfd/ospf_bfd.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" @@ -62,7 +63,7 @@ #include "ospfd/ospf_gr_helper.h" -DEFINE_QOBJ_TYPE(ospf) +DEFINE_QOBJ_TYPE(ospf); /* OSPF process wide configuration. */ static struct ospf_master ospf_master; @@ -111,7 +112,7 @@ int q_spaces_compare_func(const struct q_space *a, const struct q_space *b) } DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item, - p_spaces_compare_func) + p_spaces_compare_func); void ospf_process_refresh_data(struct ospf *ospf, bool reset) { @@ -366,6 +367,9 @@ struct ospf *ospf_new_alloc(unsigned short instance, const char *name) new->maxage_lsa = route_table_init(); new->t_maxage_walker = NULL; + /* Max paths initialization */ + new->max_multipath = MULTIPATH_NUM; + /* Distance table init. */ new->distance_table = route_table_init(); @@ -475,41 +479,11 @@ struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name) static void ospf_init(struct ospf *ospf) { - struct vrf *vrf; - struct interface *ifp; - ospf_opaque_type11_lsa_init(ospf); if (ospf->vrf_id != VRF_UNKNOWN) ospf->oi_running = 1; - /* Activate 'ip ospf area x' configured interfaces for given - * vrf. Activate area on vrf x aware interfaces. - * vrf_enable callback calls router_id_update which - * internally will call ospf_if_update to trigger - * network_run_state - */ - vrf = vrf_lookup_by_id(ospf->vrf_id); - - FOR_ALL_INTERFACES (vrf, ifp) { - struct ospf_if_params *params; - struct route_node *rn; - uint32_t count = 0; - - params = IF_DEF_PARAMS(ifp); - if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) - count++; - - for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn)) - if ((params = rn->info) && OSPF_IF_PARAM_CONFIGURED(params, if_area)) - count++; - - if (count > 0) { - ospf_interface_area_set(ospf, ifp); - ospf->if_ospf_cli_count += count; - } - } - ospf_router_id_update(ospf); } @@ -553,6 +527,23 @@ struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id) return (vrf->info) ? (struct ospf *)vrf->info : NULL; } +uint32_t ospf_count_area_params(struct ospf *ospf) +{ + struct vrf *vrf; + struct interface *ifp; + uint32_t count = 0; + + if (ospf->vrf_id != VRF_UNKNOWN) { + vrf = vrf_lookup_by_id(ospf->vrf_id); + + FOR_ALL_INTERFACES (vrf, ifp) { + count += ospf_if_count_area_params(ifp); + } + } + + return count; +} + /* It should only be used when processing incoming info update from zebra. * Other situations, it is not sufficient to lookup the ospf instance by * vrf_name only without using the instance number. @@ -899,6 +890,7 @@ static void ospf_finish_final(struct ospf *ospf) close(ospf->fd); stream_free(ospf->ibuf); ospf->fd = -1; + ospf->max_multipath = MULTIPATH_NUM; ospf_delete(ospf); if (ospf->name) { @@ -1671,6 +1663,7 @@ int ospf_area_nssa_set(struct ospf *ospf, struct in_addr area_id) /* set NSSA area defaults */ area->no_summary = 0; + area->suppress_fa = 0; area->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE; area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; area->NSSATranslatorStabilityInterval = @@ -1692,6 +1685,7 @@ int ospf_area_nssa_unset(struct ospf *ospf, struct in_addr area_id, int argc) ospf->anyNSSA--; /* set NSSA area defaults */ area->no_summary = 0; + area->suppress_fa = 0; area->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE; area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; area->NSSATranslatorStabilityInterval = @@ -1707,6 +1701,32 @@ int ospf_area_nssa_unset(struct ospf *ospf, struct in_addr area_id, int argc) return 1; } +int ospf_area_nssa_suppress_fa_set(struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id(ospf, area_id); + if (area == NULL) + return 0; + + area->suppress_fa = 1; + + return 1; +} + +int ospf_area_nssa_suppress_fa_unset(struct ospf *ospf, struct in_addr area_id) +{ + struct ospf_area *area; + + area = ospf_area_lookup_by_area_id(ospf, area_id); + if (area == NULL) + return 0; + + area->suppress_fa = 0; + + return 1; +} + int ospf_area_nssa_translator_role_set(struct ospf *ospf, struct in_addr area_id, int role) { @@ -1931,6 +1951,9 @@ static void ospf_nbr_nbma_add(struct ospf_nbr_nbma *nbr_nbma, nbr_nbma->nbr = nbr; + /* Configure BFD if interface has it. */ + ospf_neighbor_bfd_apply(nbr); + OSPF_NSM_EVENT_EXECUTE(nbr, NSM_Start); } } diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 5148bf555c..2093eb2e42 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -310,11 +310,6 @@ struct ospf { /* Statistics for LSA used for new instantiation. */ uint32_t rx_lsa_count; - /* Counter of "ip ospf area x.x.x.x" used - * for mutual exclusion of network command under - * router ospf or ip ospf area x under interface. */ - uint32_t if_ospf_cli_count; - struct route_table *distance_table; /* Used during ospf instance going down send LSDB @@ -379,6 +374,11 @@ struct ospf { */ int aggr_action; + /* Max number of multiple paths + * to support ECMP. + */ + uint16_t max_multipath; + /* MPLS LDP-IGP Sync */ struct ldp_sync_info_cmd ldp_sync_cmd; @@ -386,9 +386,9 @@ struct ospf { bool ti_lfa_enabled; enum protection_type ti_lfa_protection_type; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(ospf) +DECLARE_QOBJ_TYPE(ospf); enum ospf_ti_lfa_p_q_space_adjacency { OSPF_TI_LFA_P_Q_SPACE_ADJACENT, @@ -424,7 +424,7 @@ struct protected_resource { struct in_addr router_id; }; -PREDECL_RBTREE_UNIQ(q_spaces) +PREDECL_RBTREE_UNIQ(q_spaces); struct q_space { struct vertex *root; struct list *vertex_list; @@ -436,7 +436,7 @@ struct q_space { struct q_spaces_item q_spaces_item; }; -PREDECL_RBTREE_UNIQ(p_spaces) +PREDECL_RBTREE_UNIQ(p_spaces); struct p_space { struct vertex *root; struct protected_resource *protected_resource; @@ -476,7 +476,7 @@ struct ospf_area { int shortcut_capability; /* Other ABRs agree on S-bit */ uint32_t default_cost; /* StubDefaultCost. */ int auth_type; /* Authentication type. */ - + int suppress_fa; /* Suppress forwarding address in NSSA ABR */ uint8_t NSSATranslatorRole; /* NSSA configured role */ #define OSPF_NSSA_ROLE_NEVER 0 @@ -650,6 +650,7 @@ extern struct ospf *ospf_new_alloc(unsigned short instance, const char *name); extern struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name); extern struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id); +extern uint32_t ospf_count_area_params(struct ospf *ospf); extern void ospf_finish(struct ospf *); extern void ospf_process_refresh_data(struct ospf *ospf, bool reset); extern void ospf_router_id_update(struct ospf *ospf); @@ -668,6 +669,10 @@ extern int ospf_area_no_summary_set(struct ospf *, struct in_addr); extern int ospf_area_no_summary_unset(struct ospf *, struct in_addr); extern int ospf_area_nssa_set(struct ospf *, struct in_addr); extern int ospf_area_nssa_unset(struct ospf *, struct in_addr, int); +extern int ospf_area_nssa_suppress_fa_set(struct ospf *ospf, + struct in_addr area_id); +extern int ospf_area_nssa_suppress_fa_unset(struct ospf *ospf, + struct in_addr area_id); extern int ospf_area_nssa_translator_role_set(struct ospf *, struct in_addr, int); extern int ospf_area_export_list_set(struct ospf *, struct ospf_area *, @@ -727,4 +732,5 @@ extern int p_spaces_compare_func(const struct p_space *a, const struct p_space *b); extern int q_spaces_compare_func(const struct q_space *a, const struct q_space *b); + #endif /* _ZEBRA_OSPFD_H */ diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 28d58452df..63610e38d8 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -51,6 +51,8 @@ ospfd_libfrrospf_a_SOURCES = \ ospfd/ospf_ri.c \ ospfd/ospf_route.c \ ospfd/ospf_routemap.c \ + ospfd/ospf_routemap_nb.c \ + ospfd/ospf_routemap_nb_config.c \ ospfd/ospf_spf.c \ ospfd/ospf_ti_lfa.c \ ospfd/ospf_sr.c \ @@ -100,6 +102,7 @@ noinst_HEADERS += \ ospfd/ospf_packet.h \ ospfd/ospf_ri.h \ ospfd/ospf_route.h \ + ospfd/ospf_routemap_nb.h \ ospfd/ospf_spf.h \ ospfd/ospf_ti_lfa.h \ ospfd/ospf_sr.h \ @@ -113,10 +116,14 @@ ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM) ospfd_ospfd_SOURCES = ospfd/ospf_main.c ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c -ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 ospfd_ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic ospfd_ospfd_snmp_la_LIBADD = lib/libfrrsnmp.la EXTRA_DIST += \ ospfd/ChangeLog.opaque.txt \ # end + +nodist_ospfd_ospfd_SOURCES = \ + yang/frr-ospf-route-map.yang.c \ + # end diff --git a/pathd/path_cli.c b/pathd/path_cli.c index 8beb428135..cf14aa8c61 100644 --- a/pathd/path_cli.c +++ b/pathd/path_cli.c @@ -20,6 +20,7 @@ #include <math.h> #include <zebra.h> +#include "memory.h" #include "log.h" #include "command.h" #include "mpls.h" @@ -28,7 +29,6 @@ #include "pathd/pathd.h" #include "pathd/path_nb.h" -#include "pathd/path_memory.h" #ifndef VTYSH_EXTRACT_PL #include "pathd/path_cli_clippy.c" #endif @@ -46,7 +46,7 @@ static int config_write_traffic_eng(struct vty *vty); static int config_write_segment_lists(struct vty *vty); static int config_write_sr_policies(struct vty *vty); -DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client") +DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client"); /* Vty node structures. */ static struct cmd_node segment_routing_node = { diff --git a/pathd/path_main.c b/pathd/path_main.c index 8b7d4aba48..f54ab736c4 100644 --- a/pathd/path_main.c +++ b/pathd/path_main.c @@ -114,7 +114,8 @@ FRR_DAEMON_INFO(pathd, PATH, .vty_port = PATH_VTY_PORT, .signals = path_signals, .n_signals = array_size(path_signals), .privs = &pathd_privs, .yang_modules = pathd_yang_modules, - .n_yang_modules = array_size(pathd_yang_modules), ) + .n_yang_modules = array_size(pathd_yang_modules), +); int main(int argc, char **argv, char **envp) { diff --git a/pathd/path_memory.h b/pathd/path_memory.h deleted file mode 100644 index e2f6787f66..0000000000 --- a/pathd/path_memory.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2020 NetDEF, 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 - */ - -#ifndef _FRR_PATH_MEMORY_H_ -#define _FRR_PATH_MEMORY_H_ - -#include "memory.h" - -DECLARE_MGROUP(PATHD) - -#endif /* _FRR_PATH_MEMORY_H_ */ diff --git a/pathd/path_nb_config.c b/pathd/path_nb_config.c index 669db169ae..af54f5bce2 100644 --- a/pathd/path_nb_config.c +++ b/pathd/path_nb_config.c @@ -302,7 +302,6 @@ int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args) struct srte_policy *policy; mpls_label_t binding_sid; - policy = nb_running_get_entry(args->dnode, NULL, true); binding_sid = yang_dnode_get_uint32(args->dnode, NULL); switch (args->event) { @@ -315,6 +314,7 @@ int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args) case NB_EV_ABORT: break; case NB_EV_APPLY: + policy = nb_running_get_entry(args->dnode, NULL, true); srte_policy_update_binding_sid(policy, binding_sid); SET_FLAG(policy->flags, F_POLICY_MODIFIED); break; @@ -668,12 +668,12 @@ int pathd_srte_policy_candidate_path_segment_list_name_modify( struct srte_candidate *candidate; const char *segment_list_name; - candidate = nb_running_get_entry(args->dnode, NULL, true); - segment_list_name = yang_dnode_get_string(args->dnode, NULL); - if (args->event != NB_EV_APPLY) return NB_OK; + candidate = nb_running_get_entry(args->dnode, NULL, true); + segment_list_name = yang_dnode_get_string(args->dnode, NULL); + candidate->segment_list = srte_segment_list_find(segment_list_name); candidate->lsp->segment_list = candidate->segment_list; assert(candidate->segment_list); diff --git a/pathd/path_pcep.c b/pathd/path_pcep.c index 8b5ca8aff3..d6cd48ecdb 100644 --- a/pathd/path_pcep.c +++ b/pathd/path_pcep.c @@ -19,6 +19,7 @@ #include <zebra.h> #include "pceplib/pcep_utils_counters.h" +#include "memory.h" #include "log.h" #include "command.h" #include "libfrr.h" @@ -31,13 +32,13 @@ #include "pathd/pathd.h" #include "pathd/path_errors.h" -#include "pathd/path_pcep_memory.h" #include "pathd/path_pcep.h" #include "pathd/path_pcep_cli.h" #include "pathd/path_pcep_controller.h" #include "pathd/path_pcep_lib.h" #include "pathd/path_pcep_config.h" +DEFINE_MTYPE(PATHD, PCEP, "PCEP module"); /* * Globals. @@ -317,4 +318,5 @@ int pcep_module_init(void) FRR_MODULE_SETUP(.name = "frr_pathd_pcep", .version = FRR_VERSION, .description = "FRR pathd PCEP module", - .init = pcep_module_init) + .init = pcep_module_init, +); diff --git a/pathd/path_pcep.h b/pathd/path_pcep.h index b131b31445..654d089cbc 100644 --- a/pathd/path_pcep.h +++ b/pathd/path_pcep.h @@ -22,11 +22,13 @@ #include <stdbool.h> #include <debug.h> #include <netinet/tcp.h> +#include "memory.h" #include "pceplib/pcep_utils_logging.h" #include "pceplib/pcep_pcc_api.h" #include "mpls.h" #include "pathd/pathd.h" -#include "pathd/path_pcep_memory.h" + +DECLARE_MTYPE(PCEP); #define PCEP_DEFAULT_PORT 4189 #define MAX_PCC 32 diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c index 7bbed9464d..14404b1d08 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -33,7 +33,6 @@ #include "pathd/pathd.h" #include "pathd/path_errors.h" -#include "pathd/path_pcep_memory.h" #include "pathd/path_pcep.h" #include "pathd/path_pcep_cli.h" #include "pathd/path_pcep_controller.h" @@ -1046,7 +1045,7 @@ static int path_pcep_cli_pcc_pcc_peer(struct vty *vty, const char *peer_name, XMALLOC(MTYPE_PCEP, sizeof(struct pcc_opts)); memcpy(&pcc_opts_copy->addr, &pce_opts_cli->pce_opts.config_opts.source_ip, - sizeof(struct pcc_opts)); + sizeof(pcc_opts_copy->addr)); pcc_opts_copy->msd = pcc_msd_g; pcc_opts_copy->port = pce_opts_cli->pce_opts.config_opts.source_port; if (pcep_ctrl_update_pcc_options(pcep_g->fpt, pcc_opts_copy)) { diff --git a/pathd/path_pcep_lib.c b/pathd/path_pcep_lib.c index 1d2f25889e..e9d699de47 100644 --- a/pathd/path_pcep_lib.c +++ b/pathd/path_pcep_lib.c @@ -18,15 +18,18 @@ #include <zebra.h> +#include "memory.h" + #include <debug.h> #include "pceplib/pcep_utils_counters.h" #include "pceplib/pcep_timers.h" #include "pathd/path_errors.h" -#include "pathd/path_memory.h" #include "pathd/path_pcep.h" #include "pathd/path_pcep_lib.h" #include "pathd/path_pcep_debug.h" -#include "pathd/path_pcep_memory.h" + +DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_INFRA, "PCEPlib Infrastructure"); +DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages"); #define CLASS_TYPE(CLASS, TYPE) (((CLASS) << 16) | (TYPE)) #define DEFAULT_LSAP_SETUP_PRIO 4 diff --git a/pathd/path_pcep_memory.c b/pathd/path_pcep_memory.c deleted file mode 100644 index 8f608090a6..0000000000 --- a/pathd/path_pcep_memory.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2020 NetDEF, 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 - */ - -#include <zebra.h> - -#include <memory.h> - -#include "pathd/path_pcep_memory.h" - -DEFINE_MTYPE(PATHD, PCEP, "PCEP module") -DEFINE_MTYPE(PATHD, PCEPLIB_INFRA, "PCEPlib Infrastructure") -DEFINE_MTYPE(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages") diff --git a/pathd/path_pcep_memory.h b/pathd/path_pcep_memory.h deleted file mode 100644 index 05c5e2d82b..0000000000 --- a/pathd/path_pcep_memory.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2020 NetDEF, 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 - */ - -#ifndef _FRR_PATH_PCEP_MEMORY_H_ -#define _FRR_PATH_PCEP_MEMORY_H_ - -#include "pathd/path_memory.h" - -DECLARE_MTYPE(PCEP) -DECLARE_MTYPE(PCEPLIB_INFRA) -DECLARE_MTYPE(PCEPLIB_MESSAGES) - -#endif /* _FRR_PATH_PCEP_MEMORY_H_ */ diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index 899ce805fe..a2c1e7cd4c 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -41,7 +41,6 @@ #include "pathd/pathd.h" #include "pathd/path_zebra.h" #include "pathd/path_errors.h" -#include "pathd/path_pcep_memory.h" #include "pathd/path_pcep.h" #include "pathd/path_pcep_controller.h" #include "pathd/path_pcep_lib.h" @@ -147,10 +146,10 @@ static uint32_t req_map_hash(const struct req_map_data *e); /* Data Structure Declarations */ DECLARE_HASH(plspid_map, struct plspid_map_data, mi, plspid_map_cmp, - plspid_map_hash) + plspid_map_hash); DECLARE_HASH(nbkey_map, struct nbkey_map_data, mi, nbkey_map_cmp, - nbkey_map_hash) -DECLARE_HASH(req_map, struct req_map_data, mi, req_map_cmp, req_map_hash) + nbkey_map_hash); +DECLARE_HASH(req_map, struct req_map_data, mi, req_map_cmp, req_map_hash); static inline int req_entry_compare(const struct req_entry *a, const struct req_entry *b) diff --git a/pathd/path_pcep_pcc.h b/pathd/path_pcep_pcc.h index c07a6ae541..ceac6f3278 100644 --- a/pathd/path_pcep_pcc.h +++ b/pathd/path_pcep_pcc.h @@ -30,9 +30,9 @@ enum pcc_status { PCEP_PCC_OPERATING }; -PREDECL_HASH(plspid_map) -PREDECL_HASH(nbkey_map) -PREDECL_HASH(req_map) +PREDECL_HASH(plspid_map); +PREDECL_HASH(nbkey_map); +PREDECL_HASH(req_map); struct plspid_map_data { struct plspid_map_item mi; diff --git a/pathd/pathd.c b/pathd/pathd.c index 14f5167bff..ae82186315 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -24,22 +24,23 @@ #include "network.h" #include "pathd/pathd.h" -#include "pathd/path_memory.h" #include "pathd/path_zebra.h" #include "pathd/path_debug.h" #define HOOK_DELAY 3 -DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List") -DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy") -DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path") +DEFINE_MGROUP(PATHD, "pathd"); + +DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List"); +DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy"); +DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path"); DEFINE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate), - (candidate)) + (candidate)); DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate), - (candidate)) + (candidate)); DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate), - (candidate)) + (candidate)); static void trigger_pathd_candidate_created(struct srte_candidate *candidate); static int trigger_pathd_candidate_created_timer(struct thread *thread); diff --git a/pathd/pathd.h b/pathd/pathd.h index 4879239db8..9c4d256cef 100644 --- a/pathd/pathd.h +++ b/pathd/pathd.h @@ -19,11 +19,14 @@ #ifndef _FRR_PATHD_H_ #define _FRR_PATHD_H_ +#include "lib/memory.h" #include "lib/mpls.h" #include "lib/ipaddr.h" #include "lib/srte.h" #include "lib/hook.h" +DECLARE_MGROUP(PATHD); + enum srte_protocol_origin { SRTE_ORIGIN_UNDEFINED = 0, SRTE_ORIGIN_PCEP = 1, @@ -338,11 +341,11 @@ RB_HEAD(srte_policy_head, srte_policy); RB_PROTOTYPE(srte_policy_head, srte_policy, entry, srte_policy_compare) DECLARE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate), - (candidate)) + (candidate)); DECLARE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate), - (candidate)) + (candidate)); DECLARE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate), - (candidate)) + (candidate)); extern struct srte_segment_list_head srte_segment_lists; extern struct srte_policy_head srte_policies; diff --git a/pathd/subdir.am b/pathd/subdir.am index 452d824669..b4501214bf 100644 --- a/pathd/subdir.am +++ b/pathd/subdir.am @@ -23,7 +23,6 @@ pathd_libpath_a_SOURCES = \ pathd/path_debug.c \ pathd/path_errors.c \ pathd/path_main.c \ - pathd/path_memory.c \ pathd/path_nb.c \ pathd/path_nb_config.c \ pathd/path_nb_state.c \ @@ -39,14 +38,12 @@ clippy_scan += \ noinst_HEADERS += \ pathd/path_debug.h \ pathd/path_errors.h \ - pathd/path_memory.h \ pathd/path_nb.h \ pathd/path_pcep.h \ pathd/path_pcep_cli.h \ pathd/path_pcep_controller.h \ pathd/path_pcep_debug.h \ pathd/path_pcep_lib.h \ - pathd/path_pcep_memory.h \ pathd/path_pcep_config.h \ pathd/path_pcep_pcc.h \ pathd/path_zebra.h \ @@ -65,7 +62,6 @@ pathd_pathd_pcep_la_SOURCES = \ pathd/path_pcep_controller.c \ pathd/path_pcep_debug.c \ pathd/path_pcep_lib.c \ - pathd/path_pcep_memory.c \ pathd/path_pcep_config.c \ pathd/path_pcep_pcc.c \ # end diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c index 01c52f24e5..1badaf95bd 100644 --- a/pbrd/pbr_main.c +++ b/pbrd/pbr_main.c @@ -131,7 +131,8 @@ FRR_DAEMON_INFO(pbrd, PBR, .vty_port = PBR_VTY_PORT, .privs = &pbr_privs, .yang_modules = pbrd_yang_modules, - .n_yang_modules = array_size(pbrd_yang_modules), ) + .n_yang_modules = array_size(pbrd_yang_modules), +); int main(int argc, char **argv, char **envp) { diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 5b851988f6..053b7363a3 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -37,9 +37,9 @@ #include "pbr_debug.h" #include "pbr_vrf.h" -DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map") -DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence") -DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface") +DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map"); +DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence"); +DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface"); static uint32_t pbr_map_sequence_unique; @@ -51,7 +51,7 @@ RB_GENERATE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare) struct pbr_map_entry_head pbr_maps = RB_INITIALIZER(&pbr_maps); -DEFINE_QOBJ_TYPE(pbr_map_sequence) +DEFINE_QOBJ_TYPE(pbr_map_sequence); static inline int pbr_map_compare(const struct pbr_map *pbrmap1, const struct pbr_map *pbrmap2) diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index ad2db146b7..caeadb0644 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -149,10 +149,10 @@ struct pbr_map_sequence { #define PBR_MAP_INVALID_VRF (1 << 5) uint64_t reason; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(pbr_map_sequence) +DECLARE_QOBJ_TYPE(pbr_map_sequence); extern struct pbr_map_entry_head pbr_maps; diff --git a/pbrd/pbr_memory.c b/pbrd/pbr_memory.c index febe406ca7..5531d41935 100644 --- a/pbrd/pbr_memory.c +++ b/pbrd/pbr_memory.c @@ -24,4 +24,4 @@ #include "pbrd/pbr_memory.h" -DEFINE_MGROUP(PBRD, "pbrd") +DEFINE_MGROUP(PBRD, "pbrd"); diff --git a/pbrd/pbr_memory.h b/pbrd/pbr_memory.h index a87d519099..eb13d5d9d1 100644 --- a/pbrd/pbr_memory.h +++ b/pbrd/pbr_memory.h @@ -19,6 +19,6 @@ */ #ifndef __PBR_MEMORY_H__ -DECLARE_MGROUP(PBRD) +DECLARE_MGROUP(PBRD); #endif diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index ba9ad97ab8..e127999b0b 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -35,7 +35,7 @@ #include "pbrd/pbr_memory.h" #include "pbrd/pbr_debug.h" -DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups") +DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups"); struct hash *pbr_nhg_hash; static struct hash *pbr_nhrc_hash; diff --git a/pbrd/pbr_vrf.c b/pbrd/pbr_vrf.c index 3284607406..1b69e23ce3 100644 --- a/pbrd/pbr_vrf.c +++ b/pbrd/pbr_vrf.c @@ -28,7 +28,7 @@ #include "pbr_nht.h" #include "pbr_zebra.h" -DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF") +DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF"); static struct pbr_vrf *pbr_vrf_alloc(void) { diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 467bbc8f72..4b73e13c27 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -41,7 +41,7 @@ #include "pbr_debug.h" #include "pbr_vrf.h" -DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface") +DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface"); /* Zebra structure to hold current status. */ struct zclient *zclient; diff --git a/pceplib/.gitignore b/pceplib/.gitignore index 5861f25a41..a82fe5a867 100644 --- a/pceplib/.gitignore +++ b/pceplib/.gitignore @@ -1,10 +1,22 @@ pcep_pcc test/pcep_msg_tests +test/pcep_msg_tests.log +test/pcep_msg_tests.trs test/pcep_pcc_api_tests +test/pcep_pcc_api_tests.log +test/pcep_pcc_api_tests.trs test/pcep_session_logic_tests +test/pcep_session_logic_tests.log +test/pcep_session_logic_tests.trs test/pcep_socket_comm_tests +test/pcep_socket_comm_tests.log +test/pcep_socket_comm_tests.trs test/pcep_timers_tests +test/pcep_timers_tests.log +test/pcep_timers_tests.trs test/pcep_utils_tests +test/pcep_utils_tests.log +test/pcep_utils_tests.trs test/valgrind.pcep_msg_tests.log test/valgrind.pcep_pcc_api_tests.log test/valgrind.pcep_session_logic_tests.log diff --git a/pceplib/pcep_msg_messages_encoding.c b/pceplib/pcep_msg_messages_encoding.c index 23ccef480c..7c8e1b3a1f 100644 --- a/pceplib/pcep_msg_messages_encoding.c +++ b/pceplib/pcep_msg_messages_encoding.c @@ -129,7 +129,7 @@ void pcep_encode_message(struct pcep_message *message, message_length += pcep_encode_object(node->data, versioning, message_buffer + message_length); - if (message_length > PCEP_MESSAGE_LENGTH) { + if (message_length >= PCEP_MESSAGE_LENGTH) { message->encoded_message = NULL; message->encoded_message_length = 0; return; @@ -295,6 +295,14 @@ struct pcep_message *pcep_decode_message(const uint8_t *msg_buf) msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags, &msg_type); + if (msg_length == 0) { + pcep_log(LOG_INFO, "%s: Discarding empty message", __func__); + return NULL; + } + if (msg_length >= PCEP_MESSAGE_LENGTH) { + pcep_log(LOG_INFO, "%s: Discarding message too big", __func__); + return NULL; + } struct pcep_message *msg = pceplib_calloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message)); diff --git a/pceplib/pcep_msg_objects_encoding.c b/pceplib/pcep_msg_objects_encoding.c index d40b840869..c4089ba5ec 100644 --- a/pceplib/pcep_msg_objects_encoding.c +++ b/pceplib/pcep_msg_objects_encoding.c @@ -1668,7 +1668,7 @@ struct pcep_object_header *pcep_decode_obj_ro(struct pcep_object_header *hdr, ipv6 = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr)); - decode_ipv6(uint32_ptr + LENGTH_4WORDS, ipv6); + decode_ipv6(uint32_ptr + 4, ipv6); dll_append(sr_subobj->nai_list, ipv6); read_count += LENGTH_8WORDS; @@ -1684,17 +1684,17 @@ struct pcep_object_header *pcep_decode_obj_ro(struct pcep_object_header *hdr, struct in_addr *ipv4 = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr)); - ipv4->s_addr = uint32_ptr[LENGTH_4WORDS]; + ipv4->s_addr = uint32_ptr[4]; dll_append(sr_subobj->nai_list, ipv4); ipv6 = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr)); - decode_ipv6(uint32_ptr + LENGTH_5WORDS, ipv6); + decode_ipv6(uint32_ptr + 5, ipv6); dll_append(sr_subobj->nai_list, ipv6); ipv4 = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr)); - ipv4->s_addr = uint32_ptr[LENGTH_9WORDS]; + ipv4->s_addr = uint32_ptr[9]; dll_append(sr_subobj->nai_list, ipv4); read_count += LENGTH_10WORDS; diff --git a/pceplib/pcep_msg_tlvs.c b/pceplib/pcep_msg_tlvs.c index 890da9517f..9c84e71ee1 100644 --- a/pceplib/pcep_msg_tlvs.c +++ b/pceplib/pcep_msg_tlvs.c @@ -401,7 +401,7 @@ pcep_tlv_create_srpag_pol_name(const char *pol_name, uint16_t pol_name_length) (normalize_pcep_tlv_length(pol_name_length) > MAX_POLICY_NAME) ? MAX_POLICY_NAME : pol_name_length; - memcpy(tlv->name, pol_name, pol_name_length); + memcpy(tlv->name, pol_name, length); tlv->name_length = length; return tlv; @@ -456,7 +456,7 @@ pcep_tlv_create_tlv_arbitrary(const char *data, uint16_t data_length, uint16_t length = (data_length > MAX_ARBITRARY_SIZE) ? MAX_ARBITRARY_SIZE : data_length; - memcpy(tlv->data, data, data_length); + memcpy(tlv->data, data, length); tlv->data_length = length; tlv->arbitraty_type = tlv_id; diff --git a/pceplib/pcep_msg_tlvs_encoding.c b/pceplib/pcep_msg_tlvs_encoding.c index 3322663dc3..967f138143 100644 --- a/pceplib/pcep_msg_tlvs_encoding.c +++ b/pceplib/pcep_msg_tlvs_encoding.c @@ -1135,7 +1135,7 @@ struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability( uint16_t buf_index = normalize_pcep_tlv_length( TLV_HEADER_LENGTH + LENGTH_1WORD + num_psts); while ((tlv->header.encoded_tlv_length - buf_index) > TLV_HEADER_LENGTH - && num_iterations++ > MAX_ITERATIONS) { + && num_iterations++ < MAX_ITERATIONS) { struct pcep_object_tlv_header *sub_tlv = pcep_decode_tlv(tlv_body_buf + buf_index); if (sub_tlv == NULL) { diff --git a/pceplib/pcep_msg_tools.c b/pceplib/pcep_msg_tools.c index 1d157ec3f5..e190d2a850 100644 --- a/pceplib/pcep_msg_tools.c +++ b/pceplib/pcep_msg_tools.c @@ -93,11 +93,11 @@ static const char *object_class_strs[] = {"NOT_IMPLEMENTED0", double_linked_list *pcep_msg_read(int sock_fd) { int ret; - uint8_t buffer[PCEP_MAX_SIZE] = {0}; + uint8_t buffer[PCEP_MESSAGE_LENGTH] = {0}; uint16_t buffer_read = 0; - ret = read(sock_fd, &buffer, PCEP_MAX_SIZE); + ret = read(sock_fd, &buffer, PCEP_MESSAGE_LENGTH); if (ret < 0) { pcep_log( @@ -114,13 +114,13 @@ double_linked_list *pcep_msg_read(int sock_fd) double_linked_list *msg_list = dll_initialize(); struct pcep_message *msg = NULL; - while ((ret - buffer_read) >= MESSAGE_HEADER_LENGTH) { + while (((uint16_t)ret - buffer_read) >= MESSAGE_HEADER_LENGTH) { /* Get the Message header, validate it, and return the msg * length */ - int32_t msg_hdr_length = + int32_t msg_length = pcep_decode_validate_msg_header(buffer + buffer_read); - if (msg_hdr_length < 0) { + if (msg_length < 0 || msg_length > PCEP_MESSAGE_LENGTH) { /* If the message header is invalid, we cant keep * reading since the length may be invalid */ pcep_log( @@ -130,17 +130,26 @@ double_linked_list *pcep_msg_read(int sock_fd) return msg_list; } - /* Check if the msg_hdr_length is longer than what was read, + /* Check if the msg_length is longer than what was read, * in which case, we need to read the rest of the message. */ - if ((ret - buffer_read) < msg_hdr_length) { - int read_len = (msg_hdr_length - (ret - buffer_read)); + if ((ret - buffer_read) < msg_length) { + int read_len = (msg_length - (ret - buffer_read)); int read_ret = 0; pcep_log( LOG_INFO, "%s: pcep_msg_read: Message not fully read! Trying to read %d bytes more, fd [%d]", __func__, read_len, sock_fd); - read_ret = read(sock_fd, &buffer[ret], read_len); + if (PCEP_MESSAGE_LENGTH - ret - buffer_read >= read_len ) + read_ret = + read(sock_fd, &buffer[ret], read_len); + else { + pcep_log( + LOG_ERR, + "%s: Trying to read size (%d) offset (%d) in a buff of size (%d)", + __func__, read_len, ret, PCEP_MESSAGE_LENGTH); + return msg_list; + } if (read_ret != read_len) { pcep_log( @@ -152,7 +161,7 @@ double_linked_list *pcep_msg_read(int sock_fd) } msg = pcep_decode_message(buffer + buffer_read); - buffer_read += msg_hdr_length; + buffer_read += msg_length; if (msg == NULL) { return msg_list; @@ -459,7 +468,12 @@ int pcep_msg_send(int sock_fd, struct pcep_message *msg) if (msg == NULL) { return 0; } + int msg_length = ntohs(msg->encoded_message_length); + if (msg_length > PCEP_MESSAGE_LENGTH) { + pcep_log(LOG_ERR, "%s: Not sended, size(% d) exceed max(% d) ", + __func__, msg_length, PCEP_MESSAGE_LENGTH); + return 0; + } - return write(sock_fd, msg->encoded_message, - ntohs(msg->encoded_message_length)); + return write(sock_fd, msg->encoded_message, msg_length); } diff --git a/pceplib/pcep_pcc.c b/pceplib/pcep_pcc.c index 2171f883cd..1a702a8b63 100644 --- a/pceplib/pcep_pcc.c +++ b/pceplib/pcep_pcc.c @@ -273,6 +273,7 @@ void send_pce_report_message(pcep_session *session) pcep_log(LOG_WARNING, "%s: send_pce_report_message SRP object was NULL", __func__); + dll_destroy_with_data(report_list); return; } dll_append(report_list, obj); @@ -313,6 +314,7 @@ void send_pce_report_message(pcep_session *session) pcep_log(LOG_WARNING, "%s: send_pce_report_message LSP object was NULL", __func__); + dll_destroy_with_data(report_list); return; } dll_append(report_list, obj); @@ -349,6 +351,7 @@ void send_pce_report_message(pcep_session *session) pcep_log(LOG_WARNING, "%s: send_pce_report_message ERO object was NULL", __func__); + dll_destroy_with_data(report_list); return; } dll_append(report_list, obj); diff --git a/pceplib/pcep_session_logic.c b/pceplib/pcep_session_logic.c index 5e4dae4900..52655914c6 100644 --- a/pceplib/pcep_session_logic.c +++ b/pceplib/pcep_session_logic.c @@ -61,7 +61,6 @@ static bool run_session_logic_common() memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle)); session_logic_handle_->active = true; - session_logic_handle_->session_logic_condition = false; session_logic_handle_->session_list = ordered_list_initialize(pointer_compare_function); session_logic_handle_->session_event_queue = queue_initialize(); @@ -91,6 +90,11 @@ static bool run_session_logic_common() return false; } + pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex)); + session_logic_handle_->session_logic_condition = true; + pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var)); + pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex)); + if (pthread_mutex_init(&(session_logic_handle_->session_list_mutex), NULL) != 0) { @@ -574,24 +578,20 @@ struct pcep_message *create_pcep_open(pcep_session *session) dll_append( tlv_list, pcep_tlv_create_stateful_pce_capability( + /* U flag */ session->pcc_config - .support_stateful_pce_lsp_update, /* U - flag - */ - session->pcc_config - .support_include_db_version, /* S flag - */ - session->pcc_config - .support_lsp_triggered_resync, /* T flag - */ - session->pcc_config - .support_lsp_delta_sync, /* D flag */ - session->pcc_config - .support_pce_triggered_initial_sync, /* F flag */ + .support_stateful_pce_lsp_update, + /* S flag */ + session->pcc_config.support_include_db_version, + /* I flag */ session->pcc_config - .support_pce_lsp_instantiation)); /* I - flag - */ + .support_pce_lsp_instantiation, + /* T flag */ + session->pcc_config.support_lsp_triggered_resync, + /* D flag */ + session->pcc_config.support_lsp_delta_sync, + /* F flag */ + session->pcc_config.support_pce_triggered_initial_sync)); } if (session->pcc_config.support_include_db_version) { diff --git a/pceplib/pcep_session_logic_loop.c b/pceplib/pcep_session_logic_loop.c index 5705ff2000..269aa1e07e 100644 --- a/pceplib/pcep_session_logic_loop.c +++ b/pceplib/pcep_session_logic_loop.c @@ -98,6 +98,7 @@ int session_logic_msg_ready_handler(void *data, int socket_fd) } else if (msg_list->num_entries == 0) { /* Invalid message received */ increment_unknown_message(session); + dll_destroy_with_data(msg_list); } else { /* Just logging the first of potentially several messages * received */ diff --git a/pceplib/pcep_session_logic_states.c b/pceplib/pcep_session_logic_states.c index e2c3c29591..3beceefad0 100644 --- a/pceplib/pcep_session_logic_states.c +++ b/pceplib/pcep_session_logic_states.c @@ -24,6 +24,7 @@ #include <stdbool.h> #include <stdio.h> #include <string.h> +#include <assert.h> #include "pcep_msg_encoding.h" #include "pcep_session_logic.h" @@ -461,6 +462,8 @@ void send_reconciled_pcep_open(pcep_session *session, struct pcep_object_open *open_obj = (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN); + // open_msg can not have empty obj_list + assert(open_obj != NULL); if (error_open_obj->open_deadtimer != session->pce_config.dead_timer_seconds) { diff --git a/pceplib/pcep_socket_comm_loop.c b/pceplib/pcep_socket_comm_loop.c index 8346c93025..d58409c4f3 100644 --- a/pceplib/pcep_socket_comm_loop.c +++ b/pceplib/pcep_socket_comm_loop.c @@ -26,6 +26,7 @@ #include <stddef.h> #include <string.h> #include <unistd.h> +#include <assert.h> #include "pcep_socket_comm_internals.h" #include "pcep_socket_comm_loop.h" @@ -129,6 +130,9 @@ int build_fd_sets(pcep_socket_comm_handle *socket_comm_handle) comm_session = (pcep_socket_comm_session *)node->data; if (comm_session->socket_fd > max_fd) { max_fd = comm_session->socket_fd; + } else if (comm_session->socket_fd < 0) { + pcep_log(LOG_ERR, "%s: Negative fd", __func__); + assert(comm_session->socket_fd > 0); } /*pcep_log(LOG_DEBUG, ld] socket_comm::build_fdSets set @@ -147,6 +151,9 @@ int build_fd_sets(pcep_socket_comm_handle *socket_comm_handle) comm_session = (pcep_socket_comm_session *)node->data; if (comm_session->socket_fd > max_fd) { max_fd = comm_session->socket_fd; + } else if (comm_session->socket_fd < 0) { + pcep_log(LOG_ERR, "%s: Negative fd", __func__); + assert(comm_session->socket_fd > 0); } /*pcep_log(LOG_DEBUG, "%s: [%ld] socket_comm::build_fdSets set diff --git a/pceplib/pcep_timers.c b/pceplib/pcep_timers.c index e9d9d4b21d..d0a2349d05 100644 --- a/pceplib/pcep_timers.c +++ b/pceplib/pcep_timers.c @@ -457,10 +457,17 @@ void pceplib_external_timer_expire_handler(void *data) } pcep_timer *timer = (pcep_timer *)data; + pthread_mutex_lock(&timers_context_->timer_list_lock); ordered_list_node *timer_node = ordered_list_find2(timers_context_->timer_list, timer, timer_list_node_timer_ptr_compare); + + /* Remove timer from list */ + if (timer_node) + ordered_list_remove_node2(timers_context_->timer_list, + timer_node); + pthread_mutex_unlock(&timers_context_->timer_list_lock); /* Cannot continue if the timer does not exist */ @@ -474,9 +481,5 @@ void pceplib_external_timer_expire_handler(void *data) timers_context_->expire_handler(timer->data, timer->timer_id); - pthread_mutex_lock(&timers_context_->timer_list_lock); - ordered_list_remove_node2(timers_context_->timer_list, timer_node); - pthread_mutex_unlock(&timers_context_->timer_list_lock); - pceplib_free(PCEPLIB_INFRA, timer); } diff --git a/pceplib/test/pcep_msg_messages_test.c b/pceplib/test/pcep_msg_messages_test.c index 10b678bcec..b8984a42bc 100644 --- a/pceplib/test/pcep_msg_messages_test.c +++ b/pceplib/test/pcep_msg_messages_test.c @@ -111,7 +111,7 @@ void test_pcep_msg_create_request() /* Test IPv4 */ struct pcep_object_rp *rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL); - struct in_addr src_addr, dst_addr; + struct in_addr src_addr={}, dst_addr={}; struct pcep_object_endpoints_ipv4 *ipv4_obj = pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr); message = pcep_msg_create_request(rp_obj, ipv4_obj, NULL); @@ -375,6 +375,10 @@ void test_pcep_msg_create_update() /* Should return NULL if obj_list is empty */ message = pcep_msg_create_update(obj_list); CU_ASSERT_PTR_NULL(message); + if (message != NULL) { + pcep_msg_free_message(message); + message = NULL; + } struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL); struct pcep_object_lsp *lsp = @@ -390,6 +394,10 @@ void test_pcep_msg_create_update() CU_ASSERT_PTR_NULL(message); dll_append(obj_list, ero); + if (message != NULL) { + pcep_msg_free_message(message); + message = NULL; + } message = pcep_msg_create_update(obj_list); CU_ASSERT_PTR_NOT_NULL(message); pcep_encode_message(message, versioning); @@ -416,6 +424,10 @@ void test_pcep_msg_create_initiate() /* Should return NULL if obj_list is empty */ struct pcep_message *message = pcep_msg_create_initiate(NULL); CU_ASSERT_PTR_NULL(message); + if (message != NULL) { + pcep_msg_free_message(message); + message = NULL; + } struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL); struct pcep_object_lsp *lsp = @@ -428,6 +440,10 @@ void test_pcep_msg_create_initiate() dll_append(obj_list, srp); message = pcep_msg_create_initiate(obj_list); CU_ASSERT_PTR_NULL(message); + if (message != NULL) { + pcep_msg_free_message(message); + message = NULL; + } dll_append(obj_list, lsp); dll_append(obj_list, ero); diff --git a/pceplib/test/pcep_msg_tlvs_test.c b/pceplib/test/pcep_msg_tlvs_test.c index 878e4d62af..6b650f6823 100644 --- a/pceplib/test/pcep_msg_tlvs_test.c +++ b/pceplib/test/pcep_msg_tlvs_test.c @@ -106,6 +106,10 @@ void test_pcep_tlv_create_speaker_entity_id() double_linked_list *list = dll_initialize(); tlv = pcep_tlv_create_speaker_entity_id(list); CU_ASSERT_PTR_NULL(tlv); + if (tlv != NULL) { + pceplib_free(PCEPLIB_INFRA, tlv); + tlv = NULL; + } uint32_t *speaker_entity = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t)); @@ -172,16 +176,28 @@ void test_pcep_tlv_create_path_setup_type_capability() double_linked_list *pst_list = dll_initialize(); tlv = pcep_tlv_create_path_setup_type_capability(pst_list, NULL); CU_ASSERT_PTR_NULL(tlv); + if (tlv != NULL) { + pcep_obj_free_tlv(&tlv->header); + tlv = NULL; + } /* Should still return NULL if pst_list is NULL */ double_linked_list *sub_tlv_list = dll_initialize(); tlv = pcep_tlv_create_path_setup_type_capability(NULL, sub_tlv_list); CU_ASSERT_PTR_NULL(tlv); + if (tlv != NULL) { + pcep_obj_free_tlv(&tlv->header); + tlv = NULL; + } /* Should still return NULL if pst_list is empty */ tlv = pcep_tlv_create_path_setup_type_capability(pst_list, sub_tlv_list); CU_ASSERT_PTR_NULL(tlv); + if (tlv != NULL) { + pcep_obj_free_tlv(&tlv->header); + tlv = NULL; + } /* Test only populating the pst list */ uint8_t *pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1); @@ -196,6 +212,10 @@ void test_pcep_tlv_create_path_setup_type_capability() tlv = pcep_tlv_create_path_setup_type_capability(pst_list, sub_tlv_list); CU_ASSERT_PTR_NOT_NULL(tlv); + if (tlv == NULL) { + CU_ASSERT_TRUE(tlv != NULL); + return; + } pcep_encode_tlv(&tlv->header, versioning, tlv_buf); CU_ASSERT_EQUAL(tlv->header.type, diff --git a/pceplib/test/pcep_msg_tools_test.c b/pceplib/test/pcep_msg_tools_test.c index a1260b1186..ff5fc62390 100644 --- a/pceplib/test/pcep_msg_tools_test.c +++ b/pceplib/test/pcep_msg_tools_test.c @@ -24,6 +24,9 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> + #include <CUnit/CUnit.h> @@ -164,7 +167,15 @@ void pcep_tools_test_teardown(void) int convert_hexstrs_to_binary(const char *hexbyte_strs[], uint16_t hexbyte_strs_length) { - int fd = fileno(tmpfile()); + mode_t oldumask; + oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + /* Set umask before anything for security */ + umask(0027); + char tmpfile[] = "/tmp/pceplib_XXXXXX"; + int fd = mkstemp(tmpfile); + umask(oldumask); + if (fd == -1) + return -1; int i = 0; for (; i < hexbyte_strs_length; i++) { @@ -192,6 +203,10 @@ void test_pcep_msg_read_pcep_initiate() { int fd = convert_hexstrs_to_binary(pcep_initiate_hexbyte_strs, pcep_initiate_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 1); @@ -287,6 +302,10 @@ void test_pcep_msg_read_pcep_initiate2() { int fd = convert_hexstrs_to_binary(pcep_initiate2_hexbyte_strs, pcep_initiate2_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 1); @@ -370,6 +389,10 @@ void test_pcep_msg_read_pcep_open() { int fd = convert_hexstrs_to_binary(pcep_open_odl_hexbyte_strs, pcep_open_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 1); @@ -410,6 +433,10 @@ void test_pcep_msg_read_pcep_update() { int fd = convert_hexstrs_to_binary(pcep_update_hexbyte_strs, pcep_update_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 1); @@ -488,6 +515,10 @@ void test_pcep_msg_read_pcep_open_initiate() int fd = convert_hexstrs_to_binary( pcep_open_initiate_odl_hexbyte_strs, pcep_open_initiate_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 2); @@ -513,6 +544,10 @@ void test_pcep_msg_read_pcep_open_cisco_pce() int fd = convert_hexstrs_to_binary( pcep_open_cisco_pce_hexbyte_strs, pcep_open_cisco_pce_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 1); @@ -571,6 +606,10 @@ void test_pcep_msg_read_pcep_update_cisco_pce() int fd = convert_hexstrs_to_binary( pcep_update_cisco_pce_hexbyte_strs, pcep_update_cisco_pce_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 1); @@ -708,6 +747,10 @@ void test_pcep_msg_read_pcep_report_cisco_pcc() int fd = convert_hexstrs_to_binary( pcep_report_cisco_pcc_hexbyte_strs, pcep_report_cisco_pcc_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 1); @@ -863,6 +906,10 @@ void test_pcep_msg_read_pcep_initiate_cisco_pcc() int fd = convert_hexstrs_to_binary( pcep_initiate_cisco_pcc_hexbyte_strs, pcep_initiate_cisco_pcc_hexbyte_strs_length); + if(fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } double_linked_list *msg_list = pcep_msg_read(fd); CU_ASSERT_PTR_NOT_NULL(msg_list); CU_ASSERT_EQUAL(msg_list->num_entries, 1); diff --git a/pceplib/test/pcep_session_logic_loop_test.c b/pceplib/test/pcep_session_logic_loop_test.c index 38fabd4ccd..3a40f59bb9 100644 --- a/pceplib/test/pcep_session_logic_loop_test.c +++ b/pceplib/test/pcep_session_logic_loop_test.c @@ -25,6 +25,8 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> #include <CUnit/CUnit.h> @@ -70,7 +72,6 @@ void pcep_session_logic_loop_test_setup() PCEPLIB_INFRA, sizeof(pcep_session_logic_handle)); memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle)); session_logic_handle_->active = true; - session_logic_handle_->session_logic_condition = false; session_logic_handle_->session_list = ordered_list_initialize(pointer_compare_function); session_logic_handle_->session_event_queue = queue_initialize(); @@ -79,6 +80,11 @@ void pcep_session_logic_loop_test_setup() pthread_mutex_init(&(session_logic_handle_->session_logic_mutex), NULL); pthread_mutex_init(&(session_logic_handle_->session_list_mutex), NULL); + pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex)); + session_logic_handle_->session_logic_condition = true; + pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var)); + pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex)); + session_logic_event_queue_ = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue)); memset(session_logic_event_queue_, 0, sizeof(pcep_event_queue)); @@ -128,7 +134,17 @@ void test_session_logic_msg_ready_handler() /* Read from an empty file should return 0, thus * session_logic_msg_ready_handler returns -1 */ - int fd = fileno(tmpfile()); + mode_t oldumask; + oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + /* Set umask before anything for security */ + umask(0027); + char tmpfile[] = "/tmp/pceplib_XXXXXX"; + int fd = mkstemp(tmpfile); + umask(oldumask); + if (fd == -1){ + CU_ASSERT_TRUE(fd>=0); + return; + } pcep_session session; memset(&session, 0, sizeof(pcep_session)); session.session_id = 100; diff --git a/pceplib/test/pcep_timers_event_loop_test.c b/pceplib/test/pcep_timers_event_loop_test.c index 9fcacaf0f2..ae63601df2 100644 --- a/pceplib/test/pcep_timers_event_loop_test.c +++ b/pceplib/test/pcep_timers_event_loop_test.c @@ -130,7 +130,9 @@ void test_walk_and_process_timers_timer_expired() timer->data = timer; // Set the timer to expire 10 seconds ago timer->expire_time = time(NULL) - 10; + pthread_mutex_lock(&test_timers_context->timer_list_lock); timer->timer_id = TEST_EVENT_LOOP_TIMER_ID; + pthread_mutex_unlock(&test_timers_context->timer_list_lock); ordered_list_add_node(test_timers_context->timer_list, timer); walk_and_process_timers(test_timers_context); diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index e873af5759..f43a31fde2 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -42,10 +42,10 @@ static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp, int hold_time); /* Memory Types */ -DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info") -DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info") -DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info") -DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet") +DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info"); +DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info"); +DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info"); +DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet"); /* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */ #define MAX_IP_HDR_LEN 24 diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index ae5b7940e9..4bbe7d35f0 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1094,6 +1094,8 @@ static void pim_show_interfaces_single(struct pim_instance *pim, json_object_int_add(json_row, "helloPeriod", pim_ifp->pim_hello_period); + json_object_int_add(json_row, "holdTime", + PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); json_object_string_add(json_row, "helloTimer", hello_timer); json_object_string_add(json_row, "helloStatStart", @@ -1243,6 +1245,8 @@ static void pim_show_interfaces_single(struct pim_instance *pim, vty_out(vty, "------\n"); vty_out(vty, "Period : %d\n", pim_ifp->pim_hello_period); + vty_out(vty, "HoldTime : %d\n", + PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); vty_out(vty, "Timer : %s\n", hello_timer); vty_out(vty, "StatStart : %s\n", stat_uptime); vty_out(vty, "Receive : %d\n", @@ -8987,7 +8991,7 @@ DEFUN (interface_ip_pim_hello, DEFUN (interface_no_ip_pim_hello, interface_no_ip_pim_hello_cmd, - "no ip pim hello [(1-180) (1-180)]", + "no ip pim hello [(1-180) [(1-180)]]", NO_STR IP_STR PIM_STR diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 5a09e7a8ee..70c233848a 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -92,7 +92,8 @@ FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT, .n_signals = 4 /* XXX array_size(pimd_signals) XXX*/, .privs = &pimd_privs, .yang_modules = pimd_yang_modules, - .n_yang_modules = array_size(pimd_yang_modules), ) + .n_yang_modules = array_size(pimd_yang_modules), +); int main(int argc, char **argv, char **envp) diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index 6bc8062c4b..1d811d9001 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -25,31 +25,31 @@ #include "pim_memory.h" -DEFINE_MGROUP(PIMD, "pimd") -DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL") -DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface") -DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join") -DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket") -DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group") -DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source") -DEFINE_MTYPE(PIMD, PIM_NEIGHBOR, "PIM interface neighbor") -DEFINE_MTYPE(PIMD, PIM_IFCHANNEL, "PIM interface (S,G) state") -DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state") -DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket") -DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route") -DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info") -DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info") -DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info") -DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer") -DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name") -DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache") -DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group") -DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr") -DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address") -DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP, "PIM JP AGG Group") -DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source") -DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state") -DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state") -DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration") -DEFINE_MTYPE(PIMD, PIM_PLIST_NAME, "PIM Prefix List Names") -DEFINE_MTYPE(PIMD, PIM_VXLAN_SG, "PIM VxLAN mroute cache") +DEFINE_MGROUP(PIMD, "pimd"); +DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL"); +DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface"); +DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join"); +DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket"); +DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group"); +DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source"); +DEFINE_MTYPE(PIMD, PIM_NEIGHBOR, "PIM interface neighbor"); +DEFINE_MTYPE(PIMD, PIM_IFCHANNEL, "PIM interface (S,G) state"); +DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state"); +DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket"); +DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route"); +DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info"); +DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info"); +DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info"); +DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer"); +DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name"); +DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache"); +DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group"); +DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr"); +DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address"); +DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP, "PIM JP AGG Group"); +DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source"); +DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state"); +DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state"); +DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration"); +DEFINE_MTYPE(PIMD, PIM_PLIST_NAME, "PIM Prefix List Names"); +DEFINE_MTYPE(PIMD, PIM_VXLAN_SG, "PIM VxLAN mroute cache"); diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 6beeb60075..4e5fcde7dd 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -24,33 +24,33 @@ #include "memory.h" -DECLARE_MGROUP(PIMD) -DECLARE_MTYPE(PIM_CHANNEL_OIL) -DECLARE_MTYPE(PIM_INTERFACE) -DECLARE_MTYPE(PIM_IGMP_JOIN) -DECLARE_MTYPE(PIM_IGMP_SOCKET) -DECLARE_MTYPE(PIM_IGMP_GROUP) -DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE) -DECLARE_MTYPE(PIM_NEIGHBOR) -DECLARE_MTYPE(PIM_IFCHANNEL) -DECLARE_MTYPE(PIM_UPSTREAM) -DECLARE_MTYPE(PIM_SSMPINGD) -DECLARE_MTYPE(PIM_STATIC_ROUTE) -DECLARE_MTYPE(PIM_BR) -DECLARE_MTYPE(PIM_RP) -DECLARE_MTYPE(PIM_FILTER_NAME) -DECLARE_MTYPE(PIM_MSDP_PEER) -DECLARE_MTYPE(PIM_MSDP_MG_NAME) -DECLARE_MTYPE(PIM_MSDP_SA) -DECLARE_MTYPE(PIM_MSDP_MG) -DECLARE_MTYPE(PIM_MSDP_MG_MBR) -DECLARE_MTYPE(PIM_SEC_ADDR) -DECLARE_MTYPE(PIM_JP_AGG_GROUP) -DECLARE_MTYPE(PIM_JP_AGG_SOURCE) -DECLARE_MTYPE(PIM_PIM_INSTANCE) -DECLARE_MTYPE(PIM_NEXTHOP_CACHE) -DECLARE_MTYPE(PIM_SSM_INFO) +DECLARE_MGROUP(PIMD); +DECLARE_MTYPE(PIM_CHANNEL_OIL); +DECLARE_MTYPE(PIM_INTERFACE); +DECLARE_MTYPE(PIM_IGMP_JOIN); +DECLARE_MTYPE(PIM_IGMP_SOCKET); +DECLARE_MTYPE(PIM_IGMP_GROUP); +DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE); +DECLARE_MTYPE(PIM_NEIGHBOR); +DECLARE_MTYPE(PIM_IFCHANNEL); +DECLARE_MTYPE(PIM_UPSTREAM); +DECLARE_MTYPE(PIM_SSMPINGD); +DECLARE_MTYPE(PIM_STATIC_ROUTE); +DECLARE_MTYPE(PIM_BR); +DECLARE_MTYPE(PIM_RP); +DECLARE_MTYPE(PIM_FILTER_NAME); +DECLARE_MTYPE(PIM_MSDP_PEER); +DECLARE_MTYPE(PIM_MSDP_MG_NAME); +DECLARE_MTYPE(PIM_MSDP_SA); +DECLARE_MTYPE(PIM_MSDP_MG); +DECLARE_MTYPE(PIM_MSDP_MG_MBR); +DECLARE_MTYPE(PIM_SEC_ADDR); +DECLARE_MTYPE(PIM_JP_AGG_GROUP); +DECLARE_MTYPE(PIM_JP_AGG_SOURCE); +DECLARE_MTYPE(PIM_PIM_INSTANCE); +DECLARE_MTYPE(PIM_NEXTHOP_CACHE); +DECLARE_MTYPE(PIM_SSM_INFO); DECLARE_MTYPE(PIM_PLIST_NAME); -DECLARE_MTYPE(PIM_VXLAN_SG) +DECLARE_MTYPE(PIM_VXLAN_SG); #endif /* _QUAGGA_PIM_MEMORY_H */ diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index b613937f59..9c3cdb2711 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -35,6 +35,8 @@ #include "pim_msdp.h" #include "pim_msdp_socket.h" +#include "sockopt.h" + /* increase socket send buffer size */ static void pim_msdp_update_sock_send_buffer_size(int fd) { @@ -194,6 +196,12 @@ int pim_msdp_sock_listen(struct pim_instance *pim) return rc; } + /* Set socket DSCP byte */ + if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { + zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", + sock, safe_strerror(errno)); + } + /* add accept thread */ listener->fd = sock; memcpy(&listener->su, &sin, socklen); @@ -272,6 +280,12 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp) return rc; } + /* Set socket DSCP byte */ + if (setsockopt_ipv4_tos(mp->fd, IPTOS_PREC_INTERNETCONTROL)) { + zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", + mp->fd, safe_strerror(errno)); + } + /* Connect to the remote mp. */ return (sockunion_connect(mp->fd, &mp->su_peer, htons(PIM_MSDP_TCP_PORT), 0)); diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index a7d7551cbd..475e393cf0 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1830,6 +1830,7 @@ int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args) pim_ifp = ifp->info; pim_ifp->pim_hello_period = yang_dnode_get_uint8(args->dnode, NULL); + pim_ifp->pim_default_holdtime = -1; break; } @@ -2394,13 +2395,6 @@ int lib_interface_pim_address_family_mroute_oif_modify( struct ipaddr group_addr; const struct lyd_node *if_dnode; - iif = nb_running_get_entry(args->dnode, NULL, true); - pim_iifp = iif->info; - pim = pim_iifp->pim; - - oifname = yang_dnode_get_string(args->dnode, NULL); - oif = if_lookup_by_name(oifname, pim->vrf_id); - switch (args->event) { case NB_EV_VALIDATE: if_dnode = yang_dnode_get_parent(args->dnode, "interface"); @@ -2411,6 +2405,17 @@ int lib_interface_pim_address_family_mroute_oif_modify( } #ifdef PIM_ENFORCE_LOOPFREE_MFC + iif = nb_running_get_entry(args->dnode, NULL, false); + if (!iif) { + return NB_OK; + } + + pim_iifp = iif->info; + pim = pim_iifp->pim; + + oifname = yang_dnode_get_string(args->dnode, NULL); + oif = if_lookup_by_name(oifname, pim->vrf_id); + if (oif && (iif->ifindex == oif->ifindex)) { strlcpy(args->errmsg, "% IIF same as OIF and loopfree enforcement is enabled; rejecting", @@ -2423,6 +2428,12 @@ int lib_interface_pim_address_family_mroute_oif_modify( case NB_EV_ABORT: break; case NB_EV_APPLY: + iif = nb_running_get_entry(args->dnode, NULL, true); + pim_iifp = iif->info; + pim = pim_iifp->pim; + + oifname = yang_dnode_get_string(args->dnode, NULL); + oif = if_lookup_by_name(oifname, pim->vrf_id); if (!oif) { snprintf(args->errmsg, args->errmsg_len, "No such interface name %s", diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index 8a808afa73..b0aa2b17c5 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -90,7 +90,7 @@ struct channel_counts { installed: indicate if this entry is installed in the kernel. */ -PREDECL_RBTREE_UNIQ(rb_pim_oil) +PREDECL_RBTREE_UNIQ(rb_pim_oil); struct channel_oil { struct pim_instance *pim; @@ -112,7 +112,7 @@ struct channel_oil { extern int pim_channel_oil_compare(const struct channel_oil *c1, const struct channel_oil *c2); DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb, - pim_channel_oil_compare) + pim_channel_oil_compare); extern struct list *pim_channel_oil_list; diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 8030835fb2..adea3cd9ef 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -373,7 +373,7 @@ void join_timer_start(struct pim_upstream *up); int pim_upstream_compare(const struct pim_upstream *up1, const struct pim_upstream *up2); DECLARE_RBTREE_UNIQ(rb_pim_upstream, struct pim_upstream, upstream_rb, - pim_upstream_compare) + pim_upstream_compare); void pim_upstream_register_reevaluate(struct pim_instance *pim); diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 89e7e5dc17..1ef64ff0de 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -43,10 +43,10 @@ #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" -DEFINE_MTYPE_STATIC(RIPD, RIP_INTERFACE, "RIP interface") -DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String") -DEFINE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc)) -DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc)) +DEFINE_MTYPE_STATIC(RIPD, RIP_INTERFACE, "RIP interface"); +DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String"); +DEFINE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc)); +DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc)); /* static prototypes */ static void rip_enable_apply(struct interface *); diff --git a/ripd/rip_interface.h b/ripd/rip_interface.h index 715daf2e50..fe26a78bdc 100644 --- a/ripd/rip_interface.h +++ b/ripd/rip_interface.h @@ -23,7 +23,7 @@ #include "memory.h" #include "zclient.h" -DECLARE_MTYPE(RIP_INTERFACE_STRING) +DECLARE_MTYPE(RIP_INTERFACE_STRING); extern int rip_interface_down(int, struct zclient *, zebra_size_t, vrf_id_t); extern int rip_interface_up(int, struct zclient *, zebra_size_t, vrf_id_t); diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 7e381887fc..2e5eec9844 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -128,7 +128,8 @@ FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT, .signals = ripd_signals, .n_signals = array_size(ripd_signals), .privs = &ripd_privs, .yang_modules = ripd_yang_modules, - .n_yang_modules = array_size(ripd_yang_modules), ) + .n_yang_modules = array_size(ripd_yang_modules), +); #define DEPRECATED_OPTIONS "" diff --git a/ripd/rip_offset.c b/ripd/rip_offset.c index 776f121d59..4034fe8424 100644 --- a/ripd/rip_offset.c +++ b/ripd/rip_offset.c @@ -29,7 +29,7 @@ #include "ripd/ripd.h" -DEFINE_MTYPE_STATIC(RIPD, RIP_OFFSET_LIST, "RIP offset list") +DEFINE_MTYPE_STATIC(RIPD, RIP_OFFSET_LIST, "RIP offset list"); #define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name) #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric) diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index 23599f0877..63493e2539 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -29,7 +29,7 @@ #include "ripd/ripd.h" -DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer") +DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer"); static struct rip_peer *rip_peer_new(void) { diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 4e6ed1400f..b922d66912 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -271,7 +271,7 @@ static struct interface *rip2IfLookup(struct variable *v, oid name[], if (ifp == NULL) return NULL; - oid_copy_addr(name + v->namelen, addr, sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, addr); *length = v->namelen + sizeof(struct in_addr); @@ -320,8 +320,8 @@ static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[], || (peer->domain > (int)name[v->namelen + sizeof(struct in_addr)])) { - oid_copy_addr(name + v->namelen, &peer->addr, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, + &peer->addr); name[v->namelen + sizeof(struct in_addr)] = peer->domain; *length = @@ -334,8 +334,7 @@ static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[], if (!peer) return NULL; - oid_copy_addr(name + v->namelen, &peer->addr, - sizeof(struct in_addr)); + oid_copy_in_addr(name + v->namelen, &peer->addr); name[v->namelen + sizeof(struct in_addr)] = peer->domain; *length = sizeof(struct in_addr) + v->namelen + 1; @@ -589,4 +588,5 @@ static int rip_snmp_module_init(void) FRR_MODULE_SETUP(.name = "ripd_snmp", .version = FRR_VERSION, .description = "ripd AgentX SNMP module", - .init = rip_snmp_module_init, ) + .init = rip_snmp_module_init, +); diff --git a/ripd/ripd.c b/ripd/ripd.c index 4a56efb6f8..1c23575bf3 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -56,11 +56,11 @@ /* UDP receive buffer size */ #define RIP_UDP_RCV_BUF 41600 -DEFINE_MGROUP(RIPD, "ripd") -DEFINE_MTYPE_STATIC(RIPD, RIP, "RIP structure") -DEFINE_MTYPE_STATIC(RIPD, RIP_VRF_NAME, "RIP VRF name") -DEFINE_MTYPE_STATIC(RIPD, RIP_INFO, "RIP route info") -DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance") +DEFINE_MGROUP(RIPD, "ripd"); +DEFINE_MTYPE_STATIC(RIPD, RIP, "RIP structure"); +DEFINE_MTYPE_STATIC(RIPD, RIP_VRF_NAME, "RIP VRF name"); +DEFINE_MTYPE_STATIC(RIPD, RIP_INFO, "RIP route info"); +DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance"); /* Prototypes. */ static void rip_output_process(struct connected *, struct sockaddr_in *, int, diff --git a/ripd/ripd.h b/ripd/ripd.h index 99718f7b9e..85aac985f5 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -97,7 +97,7 @@ #define RIP_INSTANCE "/frr-ripd:ripd/instance" #define RIP_IFACE "/frr-interface:lib/interface/frr-ripd:rip" -DECLARE_MGROUP(RIPD) +DECLARE_MGROUP(RIPD); /* RIP structure. */ struct rip { @@ -529,7 +529,7 @@ extern struct rip_instance_head rip_instances; /* Master thread strucutre. */ extern struct thread_master *master; -DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc)) -DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc)) +DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc)); +DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc)); #endif /* _ZEBRA_RIP_H */ diff --git a/ripd/subdir.am b/ripd/subdir.am index 875239e871..09d5590329 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -57,6 +57,6 @@ nodist_ripd_ripd_SOURCES = \ # end ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c -ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 ripd_ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic ripd_ripd_snmp_la_LIBADD = lib/libfrrsnmp.la diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 115d7a6b99..11a8fdff87 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -49,7 +49,7 @@ #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP #endif -DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface") +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface"); /* Static utility function. */ static void ripng_enable_apply(struct interface *); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 010bac851b..a5d837aa55 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -131,7 +131,8 @@ FRR_DAEMON_INFO(ripngd, RIPNG, .vty_port = RIPNG_VTY_PORT, .privs = &ripngd_privs, .yang_modules = ripngd_yang_modules, - .n_yang_modules = array_size(ripngd_yang_modules), ) + .n_yang_modules = array_size(ripngd_yang_modules), +); #define DEPRECATED_OPTIONS "" diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c index ba6e52fdda..3e9fa90938 100644 --- a/ripngd/ripng_nexthop.c +++ b/ripngd/ripng_nexthop.c @@ -39,7 +39,7 @@ #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" -DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data") +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data"); #define DEBUG 1 diff --git a/ripngd/ripng_offset.c b/ripngd/ripng_offset.c index 0094c993ad..efce8a0926 100644 --- a/ripngd/ripng_offset.c +++ b/ripngd/ripng_offset.c @@ -33,7 +33,7 @@ #include "ripngd/ripngd.h" -DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_OFFSET_LIST, "RIPng offset lst") +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_OFFSET_LIST, "RIPng offset lst"); #define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name) #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric) diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c index 0ac489c67e..554b1d68f6 100644 --- a/ripngd/ripng_peer.c +++ b/ripngd/ripng_peer.c @@ -34,7 +34,7 @@ #include "ripngd/ripngd.h" #include "ripngd/ripng_nexthop.h" -DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_PEER, "RIPng peer") +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_PEER, "RIPng peer"); static struct ripng_peer *ripng_peer_new(void) { @@ -163,8 +163,8 @@ void ripng_peer_display(struct vty *vty, struct ripng *ripng) char timebuf[RIPNG_UPTIME_LEN]; for (ALL_LIST_ELEMENTS(ripng->peer_list, node, nnode, peer)) { - vty_out(vty, " %s \n%14s %10d %10d %10d %s\n", - inet6_ntoa(peer->addr), " ", peer->recv_badpackets, + vty_out(vty, " %pI6 \n%14s %10d %10d %10d %s\n", + &peer->addr, " ", peer->recv_badpackets, peer->recv_badroutes, ZEBRA_RIPNG_DISTANCE_DEFAULT, ripng_peer_uptime(peer, timebuf, RIPNG_UPTIME_LEN)); } diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c index ed9d77a378..1eb1d0f31d 100644 --- a/ripngd/ripng_route.c +++ b/ripngd/ripng_route.c @@ -30,7 +30,7 @@ #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" -DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate") +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate"); static struct ripng_aggregate *ripng_aggregate_new(void) { diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 37e23046e8..0e83140149 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -44,10 +44,10 @@ #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" -DEFINE_MGROUP(RIPNGD, "ripngd") -DEFINE_MTYPE_STATIC(RIPNGD, RIPNG, "RIPng structure") -DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name") -DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_ROUTE, "RIPng route info") +DEFINE_MGROUP(RIPNGD, "ripngd"); +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG, "RIPng structure"); +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name"); +DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_ROUTE, "RIPng route info"); enum { ripng_all_route, ripng_changed_route, @@ -191,7 +191,7 @@ int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to, if (IS_RIPNG_DEBUG_SEND) { if (to) - zlog_debug("send to %s", inet6_ntoa(to->sin6_addr)); + zlog_debug("send to %pI6", &to->sin6_addr); zlog_debug(" send interface %s", ifp->name); zlog_debug(" send packet size %d", bufsize); } @@ -237,8 +237,8 @@ int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to, if (ret < 0) { if (to) flog_err_sys(EC_LIB_SOCKET, - "RIPng send fail on %s to %s: %s", - ifp->name, inet6_ntoa(to->sin6_addr), + "RIPng send fail on %s to %pI6: %s", + ifp->name, &to->sin6_addr, safe_strerror(errno)); else flog_err_sys(EC_LIB_SOCKET, "RIPng send fail on %s: %s", @@ -338,11 +338,11 @@ void ripng_packet_dump(struct ripng_packet *packet, int size, for (lim = (caddr_t)packet + size; (caddr_t)rte < lim; rte++) { if (rte->metric == RIPNG_METRIC_NEXTHOP) - zlog_debug(" nexthop %s/%d", inet6_ntoa(rte->addr), + zlog_debug(" nexthop %pI6/%d", &rte->addr, rte->prefixlen); else - zlog_debug(" %s/%d metric %d tag %" ROUTE_TAG_PRI, - inet6_ntoa(rte->addr), rte->prefixlen, + zlog_debug(" %pI6/%d metric %d tag %" ROUTE_TAG_PRI, + &rte->addr, rte->prefixlen, rte->metric, (route_tag_t)ntohs(rte->tag)); } } @@ -353,9 +353,9 @@ static void ripng_nexthop_rte(struct rte *rte, struct sockaddr_in6 *from, { /* Logging before checking RTE. */ if (IS_RIPNG_DEBUG_RECV) - zlog_debug("RIPng nexthop RTE address %s tag %" ROUTE_TAG_PRI + zlog_debug("RIPng nexthop RTE address %pI6 tag %" ROUTE_TAG_PRI " prefixlen %d", - inet6_ntoa(rte->addr), (route_tag_t)ntohs(rte->tag), + &rte->addr, (route_tag_t)ntohs(rte->tag), rte->prefixlen); /* RFC2080 2.1.1 Next Hop: @@ -364,14 +364,13 @@ static void ripng_nexthop_rte(struct rte *rte, struct sockaddr_in6 *from, if (ntohs(rte->tag) != 0) zlog_warn( "RIPng nexthop RTE with non zero tag value %" ROUTE_TAG_PRI - " from %s", - (route_tag_t)ntohs(rte->tag), - inet6_ntoa(from->sin6_addr)); + " from %pI6", + (route_tag_t)ntohs(rte->tag), &from->sin6_addr); if (rte->prefixlen != 0) zlog_warn( - "RIPng nexthop RTE with non zero prefixlen value %d from %s", - rte->prefixlen, inet6_ntoa(from->sin6_addr)); + "RIPng nexthop RTE with non zero prefixlen value %d from %pI6", + rte->prefixlen, &from->sin6_addr); /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a next hop RTE indicates that the next hop address should be the @@ -396,8 +395,8 @@ static void ripng_nexthop_rte(struct rte *rte, struct sockaddr_in6 *from, information is ignored, a possibly sub-optimal, but absolutely valid, route may be taken. If the received next hop address is not a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */ - zlog_warn("RIPng nexthop RTE with non link-local address %s from %pI6", - inet6_ntoa(rte->addr), &from->sin6_addr); + zlog_warn("RIPng nexthop RTE with non link-local address %pI6 from %pI6", + &rte->addr, &from->sin6_addr); nexthop->flag = RIPNG_NEXTHOP_UNSPEC; memset(&nexthop->address, 0, sizeof(struct in6_addr)); @@ -750,8 +749,8 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from, if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug( - "RIPng %s/%d is filtered by route-map in", - inet6_ntoa(p.prefix), p.prefixlen); + "RIPng %pFX is filtered by route-map in", + &p); return; } @@ -993,8 +992,8 @@ void ripng_redistribute_add(struct ripng *ripng, int type, int sub_type, p, ifindex2ifname(ifindex, ripng->vrf->vrf_id)); else zlog_debug( - "Redistribute new prefix %pFX with nexthop %s on the interface %s", - p, inet6_ntoa(*nexthop), + "Redistribute new prefix %pFX with nexthop %pI6 on the interface %s", + p, nexthop, ifindex2ifname(ifindex, ripng->vrf->vrf_id)); } @@ -1106,8 +1105,8 @@ static void ripng_response_process(struct ripng_packet *packet, int size, /* RFC2080 2.4.2 Response Messages: The Response must be ignored if it is not from the RIPng port. */ if (ntohs(from->sin6_port) != RIPNG_PORT_DEFAULT) { - zlog_warn("RIPng packet comes from non RIPng port %d from %s", - ntohs(from->sin6_port), inet6_ntoa(from->sin6_addr)); + zlog_warn("RIPng packet comes from non RIPng port %d from %pI6", + ntohs(from->sin6_port), &from->sin6_addr); ripng_peer_bad_packet(ripng, from); return; } @@ -1116,8 +1115,8 @@ static void ripng_response_process(struct ripng_packet *packet, int size, whether the datagram is from a valid neighbor; the source of the datagram must be a link-local address. */ if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) { - zlog_warn("RIPng packet comes from non link local address %s", - inet6_ntoa(from->sin6_addr)); + zlog_warn("RIPng packet comes from non link local address %pI6", + &from->sin6_addr); ripng_peer_bad_packet(ripng, from); return; } @@ -1129,8 +1128,8 @@ static void ripng_response_process(struct ripng_packet *packet, int size, and such datagrams must be ignored. */ if (ripng_lladdr_check(ifp, &from->sin6_addr)) { zlog_warn( - "RIPng packet comes from my own link local address %s", - inet6_ntoa(from->sin6_addr)); + "RIPng packet comes from my own link local address %pI6", + &from->sin6_addr); ripng_peer_bad_packet(ripng, from); return; } @@ -1141,8 +1140,8 @@ static void ripng_response_process(struct ripng_packet *packet, int size, packets) must be examined to ensure that the hop count is 255. */ if (hoplimit >= 0 && hoplimit != 255) { zlog_warn( - "RIPng packet comes with non 255 hop count %d from %s", - hoplimit, inet6_ntoa(from->sin6_addr)); + "RIPng packet comes with non 255 hop count %d from %pI6", + hoplimit, &from->sin6_addr); ripng_peer_bad_packet(ripng, from); return; } @@ -1173,25 +1172,22 @@ static void ripng_response_process(struct ripng_packet *packet, int size, should never be present in an RTE. */ if (IN6_IS_ADDR_MULTICAST(&rte->addr)) { zlog_warn( - "Destination prefix is a multicast address %s/%d [%d]", - inet6_ntoa(rte->addr), rte->prefixlen, - rte->metric); + "Destination prefix is a multicast address %pI6/%d [%d]", + &rte->addr, rte->prefixlen, rte->metric); ripng_peer_bad_route(ripng, from); continue; } if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) { zlog_warn( - "Destination prefix is a link-local address %s/%d [%d]", - inet6_ntoa(rte->addr), rte->prefixlen, - rte->metric); + "Destination prefix is a link-local address %pI6/%d [%d]", + &rte->addr, rte->prefixlen, rte->metric); ripng_peer_bad_route(ripng, from); continue; } if (IN6_IS_ADDR_LOOPBACK(&rte->addr)) { zlog_warn( - "Destination prefix is a loopback address %s/%d [%d]", - inet6_ntoa(rte->addr), rte->prefixlen, - rte->metric); + "Destination prefix is a loopback address %pI6/%d [%d]", + &rte->addr, rte->prefixlen, rte->metric); ripng_peer_bad_route(ripng, from); continue; } @@ -1199,17 +1195,17 @@ static void ripng_response_process(struct ripng_packet *packet, int size, /* - is the prefix length valid (i.e., between 0 and 128, inclusive) */ if (rte->prefixlen > 128) { - zlog_warn("Invalid prefix length %s/%d from %s%%%s", - inet6_ntoa(rte->addr), rte->prefixlen, - inet6_ntoa(from->sin6_addr), ifp->name); + zlog_warn("Invalid prefix length %pI6/%d from %pI6%%%s", + &rte->addr, rte->prefixlen, + &from->sin6_addr, ifp->name); ripng_peer_bad_route(ripng, from); continue; } /* - is the metric valid (i.e., between 1 and 16, inclusive) */ if (!(rte->metric >= 1 && rte->metric <= 16)) { - zlog_warn("Invalid metric %d from %s%%%s", rte->metric, - inet6_ntoa(from->sin6_addr), ifp->name); + zlog_warn("Invalid metric %d from %pI6%%%s", + rte->metric, &from->sin6_addr, ifp->name); ripng_peer_bad_route(ripng, from); continue; } @@ -1342,8 +1338,8 @@ static int ripng_read(struct thread *thread) /* Check RTE boundary. RTE size (Packet length - RIPng header size (4)) must be multiple size of one RTE size (20). */ if (((len - 4) % 20) != 0) { - zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len, - inet6_ntoa(from.sin6_addr), ripng->vrf_name); + zlog_warn("RIPng invalid packet size %d from %pI6 (VRF %s)", + len, &from.sin6_addr, ripng->vrf_name); ripng_peer_bad_packet(ripng, &from); return 0; } @@ -1354,8 +1350,8 @@ static int ripng_read(struct thread *thread) /* RIPng packet received. */ if (IS_RIPNG_DEBUG_EVENT) zlog_debug( - "RIPng packet received from %s port %d on %s (VRF %s)", - inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port), + "RIPng packet received from %pI6 port %d on %s (VRF %s)", + &from.sin6_addr, ntohs(from.sin6_port), ifp ? ifp->name : "unknown", ripng->vrf_name); /* Logging before packet checking. */ @@ -1581,8 +1577,8 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, if (IS_RIPNG_DEBUG_EVENT) { if (to) - zlog_debug("RIPng update routes to neighbor %s", - inet6_ntoa(to->sin6_addr)); + zlog_debug("RIPng update routes to neighbor %pI6", + &to->sin6_addr); else zlog_debug("RIPng update routes on interface %s", ifp->name); @@ -2089,8 +2085,8 @@ DEFUN (show_ipv6_ripng, #endif /* DEBUG */ vty_out(vty, "\n"); vty_out(vty, "%*s", 18, " "); - len = vty_out(vty, "%s", - inet6_ntoa(rinfo->nexthop)); + len = vty_out(vty, "%pI6", + &rinfo->nexthop); len = 28 - len; if (len > 0) diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 14ac29b3fe..12e5a6d4ac 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -86,7 +86,7 @@ #define RIPNG_INSTANCE "/frr-ripngd:ripngd/instance" #define RIPNG_IFACE "/frr-interface:lib/interface/frr-ripngd:ripng" -DECLARE_MGROUP(RIPNGD) +DECLARE_MGROUP(RIPNGD); /* RIPng structure. */ struct ripng { diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h index 52561fd451..0b3776cd90 100644 --- a/sharpd/sharp_globals.h +++ b/sharpd/sharp_globals.h @@ -22,7 +22,7 @@ #ifndef __SHARP_GLOBAL_H__ #define __SHARP_GLOBAL_H__ -DECLARE_MGROUP(SHARPD) +DECLARE_MGROUP(SHARPD); struct sharp_routes { /* The original prefix for route installation */ @@ -55,6 +55,9 @@ struct sharp_global { /* The list of nexthops that we are watching and data about them */ struct list *nhs; + + /* Traffic Engineering Database */ + struct ls_ted *ted; }; extern struct sharp_global sg; diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index fe7f9851f9..e93db34ffa 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -43,13 +43,14 @@ #include "libfrr.h" #include "routemap.h" #include "nexthop_group.h" +#include "link_state.h" #include "sharp_zebra.h" #include "sharp_vty.h" #include "sharp_globals.h" #include "sharp_nht.h" -DEFINE_MGROUP(SHARPD, "sharpd") +DEFINE_MGROUP(SHARPD, "sharpd"); zebra_capabilities_t _caps_p[] = { }; @@ -129,7 +130,8 @@ FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT, .n_signals = array_size(sharp_signals), .privs = &sharp_privs, .yang_modules = sharpd_yang_modules, - .n_yang_modules = array_size(sharpd_yang_modules), ) + .n_yang_modules = array_size(sharpd_yang_modules), +); struct sharp_global sg; @@ -137,6 +139,7 @@ static void sharp_global_init(void) { memset(&sg, 0, sizeof(sg)); sg.nhs = list_new(); + sg.ted = NULL; } static void sharp_start_configuration(void) diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c index bed0ebfa27..a90387186e 100644 --- a/sharpd/sharp_nht.c +++ b/sharpd/sharp_nht.c @@ -32,8 +32,8 @@ #include "sharp_globals.h" #include "sharp_zebra.h" -DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker") -DEFINE_MTYPE_STATIC(SHARPD, NHG, "Nexthop Group") +DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker"); +DEFINE_MTYPE_STATIC(SHARPD, NHG, "Nexthop Group"); struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p) { diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 940415b067..002336616c 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -29,6 +29,7 @@ #include "vrf.h" #include "zclient.h" #include "nexthop_group.h" +#include "link_state.h" #include "sharpd/sharp_globals.h" #include "sharpd/sharp_zebra.h" @@ -700,6 +701,142 @@ DEFPY (neigh_discover, return CMD_SUCCESS; } +DEFPY (import_te, + import_te_cmd, + "sharp import-te", + SHARP_STR + "Import Traffic Engineering\n") +{ + sg.ted = ls_ted_new(1, "Sharp", 0); + sharp_zebra_register_te(); + + return CMD_SUCCESS; +} + +DEFUN (show_sharp_ted, + show_sharp_ted_cmd, + "show sharp ted [<vertex [A.B.C.D]|edge [A.B.C.D]|subnet [A.B.C.D/M]>] [verbose|json]", + SHOW_STR + SHARP_STR + "Traffic Engineering Database\n" + "MPLS-TE Vertex\n" + "MPLS-TE router ID (as an IP address)\n" + "MPLS-TE Edge\n" + "MPLS-TE Edge ID (as an IP address)\n" + "MPLS-TE Subnet\n" + "MPLS-TE Subnet ID (as an IP prefix)\n" + "Verbose output\n" + JSON_STR) +{ + int idx = 0; + struct in_addr ip_addr; + struct prefix pref; + struct ls_vertex *vertex; + struct ls_edge *edge; + struct ls_subnet *subnet; + uint64_t key; + bool verbose = false; + bool uj = use_json(argc, argv); + json_object *json = NULL; + + if (sg.ted == NULL) { + vty_out(vty, "MPLS-TE import is not enabled\n"); + return CMD_WARNING; + } + + if (uj) + json = json_object_new_object(); + + if (argv[argc - 1]->arg && strmatch(argv[argc - 1]->text, "verbose")) + verbose = true; + + if (argv_find(argv, argc, "vertex", &idx)) { + /* Show Vertex */ + if (argv_find(argv, argc, "A.B.C.D", &idx)) { + if (!inet_aton(argv[idx + 1]->arg, &ip_addr)) { + vty_out(vty, + "Specified Router ID %s is invalid\n", + argv[idx + 1]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + /* Get the Vertex from the Link State Database */ + key = ((uint64_t)ip_addr.s_addr) & 0xffffffff; + vertex = ls_find_vertex_by_key(sg.ted, key); + if (!vertex) { + vty_out(vty, "No vertex found for ID %pI4\n", + &ip_addr); + return CMD_WARNING; + } + } else + vertex = NULL; + + if (vertex) + ls_show_vertex(vertex, vty, json, verbose); + else + ls_show_vertices(sg.ted, vty, json, verbose); + + } else if (argv_find(argv, argc, "edge", &idx)) { + /* Show Edge */ + if (argv_find(argv, argc, "A.B.C.D", &idx)) { + if (!inet_aton(argv[idx]->arg, &ip_addr)) { + vty_out(vty, + "Specified Edge ID %s is invalid\n", + argv[idx]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + /* Get the Edge from the Link State Database */ + key = ((uint64_t)ip_addr.s_addr) & 0xffffffff; + edge = ls_find_edge_by_key(sg.ted, key); + if (!edge) { + vty_out(vty, "No edge found for ID %pI4\n", + &ip_addr); + return CMD_WARNING; + } + } else + edge = NULL; + + if (edge) + ls_show_edge(edge, vty, json, verbose); + else + ls_show_edges(sg.ted, vty, json, verbose); + + } else if (argv_find(argv, argc, "subnet", &idx)) { + /* Show Subnet */ + if (argv_find(argv, argc, "A.B.C.D/M", &idx)) { + if (!str2prefix(argv[idx]->arg, &pref)) { + vty_out(vty, "Invalid prefix format %s\n", + argv[idx]->arg); + return CMD_WARNING_CONFIG_FAILED; + } + /* Get the Subnet from the Link State Database */ + subnet = ls_find_subnet(sg.ted, pref); + if (!subnet) { + vty_out(vty, "No subnet found for ID %pFX\n", + &pref); + return CMD_WARNING; + } + } else + subnet = NULL; + + if (subnet) + ls_show_subnet(subnet, vty, json, verbose); + else + ls_show_subnets(sg.ted, vty, json, verbose); + + } else { + /* Show the complete TED */ + ls_show_ted(sg.ted, vty, json, verbose); + } + + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; +} + void sharp_vty_init(void) { install_element(ENABLE_NODE, &install_routes_data_dump_cmd); @@ -718,8 +855,10 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &send_opaque_unicast_cmd); install_element(ENABLE_NODE, &send_opaque_reg_cmd); install_element(ENABLE_NODE, &neigh_discover_cmd); + install_element(ENABLE_NODE, &import_te_cmd); install_element(ENABLE_NODE, &show_debugging_sharpd_cmd); + install_element(ENABLE_NODE, &show_sharp_ted_cmd); return; } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 0095aed547..0f2c634049 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -30,6 +30,7 @@ #include "zclient.h" #include "nexthop.h" #include "nexthop_group.h" +#include "link_state.h" #include "sharp_globals.h" #include "sharp_nht.h" @@ -685,7 +686,8 @@ static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS) return 0; } - zlog_debug("Received update for %pFX", &nhr.prefix); + zlog_debug("Received update for %pFX metric: %u", &nhr.prefix, + nhr.metric); nht = sharp_nh_tracker_get(&nhr.prefix); nht->nhop_num = nhr.nexthop_num; @@ -768,11 +770,15 @@ int sharp_zclient_delete(uint32_t session_id) return 0; } +static const char *const type2txt[] = { "Generic", "Vertex", "Edge", "Subnet" }; +static const char *const status2txt[] = { "Unknown", "New", "Update", + "Delete", "Sync", "Orphan"}; /* Handler for opaque messages */ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) { struct stream *s; struct zapi_opaque_msg info; + struct ls_element *lse; s = zclient->ibuf; @@ -782,6 +788,18 @@ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) zlog_debug("%s: [%u] received opaque type %u", __func__, zclient->session_id, info.type); + if (info.type == LINK_STATE_UPDATE) { + lse = ls_stream2ted(sg.ted, s, false); + if (lse) + zlog_debug(" |- Got %s %s from Link State Database", + status2txt[lse->status], + type2txt[lse->type]); + else + zlog_debug( + "%s: Error to convert Stream into Link State", + __func__); + } + return 0; } @@ -852,6 +870,16 @@ void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance, } +/* Link State registration */ +void sharp_zebra_register_te(void) +{ + /* First register to received Link State Update messages */ + zclient_register_opaque(zclient, LINK_STATE_UPDATE); + + /* Then, request initial TED with SYNC message */ + ls_request_sync(zclient); +} + void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p) { zclient_send_neigh_discovery_req(zclient, ifp, p); diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index e7247f5373..ffddb9e780 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -60,4 +60,7 @@ void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance, extern void sharp_zebra_send_arp(const struct interface *ifp, const struct prefix *p); +/* Register Link State Opaque messages */ +extern void sharp_zebra_register_te(void); + #endif diff --git a/staticd/static_main.c b/staticd/static_main.c index 560814771d..1561b91efb 100644 --- a/staticd/static_main.c +++ b/staticd/static_main.c @@ -129,7 +129,7 @@ FRR_DAEMON_INFO(staticd, STATIC, .vty_port = STATIC_VTY_PORT, .privs = &static_privs, .yang_modules = staticd_yang_modules, .n_yang_modules = array_size(staticd_yang_modules), -) +); int main(int argc, char **argv, char **envp) { diff --git a/staticd/static_memory.c b/staticd/static_memory.c deleted file mode 100644 index 122cc9fce1..0000000000 --- a/staticd/static_memory.c +++ /dev/null @@ -1,28 +0,0 @@ -/* - * static memory code. - * Copyright (C) 2018 Cumulus Networks, Inc. - * Donald Sharp - * - * 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 <memory.h> - -#include "staticd/static_memory.h" - -DEFINE_MGROUP(STATIC, "staticd") - -DEFINE_MTYPE(STATIC, STATIC_NEXTHOP, "Static Nexthop"); diff --git a/staticd/static_routes.c b/staticd/static_routes.c index 9f7e19660d..cdafc4a76a 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -31,12 +31,71 @@ #include "static_vrf.h" #include "static_routes.h" -#include "static_memory.h" #include "static_zebra.h" #include "static_debug.h" -DEFINE_MTYPE(STATIC, STATIC_ROUTE, "Static Route Info"); -DEFINE_MTYPE(STATIC, STATIC_PATH, "Static Path"); +DEFINE_MGROUP(STATIC, "staticd"); + +DEFINE_MTYPE_STATIC(STATIC, STATIC_ROUTE, "Static Route Info"); +DEFINE_MTYPE_STATIC(STATIC, STATIC_PATH, "Static Path"); +DEFINE_MTYPE_STATIC(STATIC, STATIC_NEXTHOP, "Static Nexthop"); + +void zebra_stable_node_cleanup(struct route_table *table, + struct route_node *node) +{ + struct static_nexthop *nh; + struct static_path *pn; + struct static_route_info *si; + struct route_table *src_table; + struct route_node *src_node; + struct static_path *src_pn; + struct static_route_info *src_si; + + si = node->info; + + if (si) { + frr_each_safe(static_path_list, &si->path_list, pn) { + frr_each_safe(static_nexthop_list, &pn->nexthop_list, + nh) { + static_nexthop_list_del(&pn->nexthop_list, nh); + XFREE(MTYPE_STATIC_NEXTHOP, nh); + } + static_path_list_del(&si->path_list, pn); + XFREE(MTYPE_STATIC_PATH, pn); + } + + /* clean up for dst table */ + src_table = srcdest_srcnode_table(node); + if (src_table) { + /* This means the route_node is part of the top + * hierarchy and refers to a destination prefix. + */ + for (src_node = route_top(src_table); src_node; + src_node = route_next(src_node)) { + src_si = src_node->info; + + frr_each_safe(static_path_list, + &src_si->path_list, src_pn) { + frr_each_safe(static_nexthop_list, + &src_pn->nexthop_list, + nh) { + static_nexthop_list_del( + &src_pn->nexthop_list, + nh); + XFREE(MTYPE_STATIC_NEXTHOP, nh); + } + static_path_list_del(&src_si->path_list, + src_pn); + XFREE(MTYPE_STATIC_PATH, src_pn); + } + + XFREE(MTYPE_STATIC_ROUTE, src_node->info); + } + } + + XFREE(MTYPE_STATIC_ROUTE, node->info); + } +} /* Install static path into rib. */ void static_install_path(struct route_node *rn, struct static_path *pn, @@ -80,9 +139,6 @@ struct route_node *static_add_route(afi_t afi, safi_t safi, struct prefix *p, rn->info = si; - /* Mark as having FRR configuration */ - vrf_set_user_cfged(svrf->vrf); - return rn; } @@ -101,9 +157,6 @@ static void static_del_src_route(struct route_node *rn, safi_t safi, XFREE(MTYPE_STATIC_ROUTE, rn->info); route_unlock_node(rn); - /* If no other FRR config for this VRF, mark accordingly. */ - if (!static_vrf_has_config(svrf)) - vrf_reset_user_cfged(svrf->vrf); } void static_del_route(struct route_node *rn, safi_t safi, @@ -133,9 +186,6 @@ void static_del_route(struct route_node *rn, safi_t safi, } XFREE(MTYPE_STATIC_ROUTE, rn->info); route_unlock_node(rn); - /* If no other FRR config for this VRF, mark accordingly. */ - if (!static_vrf_has_config(svrf)) - vrf_reset_user_cfged(svrf->vrf); } bool static_add_nexthop_validate(const char *nh_vrf_name, static_types type, diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 0fbf0674d7..f64a40329d 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -22,6 +22,9 @@ #include "lib/mpls.h" #include "table.h" +#include "memory.h" + +DECLARE_MGROUP(STATIC); /* Static route label information */ struct static_nh_label { @@ -198,6 +201,9 @@ extern bool static_add_nexthop_validate(const char *nh_vrf_name, extern struct stable_info *static_get_stable_info(struct route_node *rn); extern void static_route_info_init(struct static_route_info *si); +extern void zebra_stable_node_cleanup(struct route_table *table, + struct route_node *node); + /* * Max string return via API static_get_nh_str in size_t */ diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c index 2133093bb3..96e5d37d68 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -24,7 +24,6 @@ #include "table.h" #include "srcdest_table.h" -#include "static_memory.h" #include "static_vrf.h" #include "static_routes.h" #include "static_zebra.h" @@ -32,63 +31,6 @@ DEFINE_MTYPE_STATIC(STATIC, STATIC_RTABLE_INFO, "Static Route Table Info"); -static void zebra_stable_node_cleanup(struct route_table *table, - struct route_node *node) -{ - struct static_nexthop *nh; - struct static_path *pn; - struct static_route_info *si; - struct route_table *src_table; - struct route_node *src_node; - struct static_path *src_pn; - struct static_route_info *src_si; - - si = node->info; - - if (si) { - frr_each_safe(static_path_list, &si->path_list, pn) { - frr_each_safe(static_nexthop_list, &pn->nexthop_list, - nh) { - static_nexthop_list_del(&pn->nexthop_list, nh); - XFREE(MTYPE_STATIC_NEXTHOP, nh); - } - static_path_list_del(&si->path_list, pn); - XFREE(MTYPE_STATIC_PATH, pn); - } - - /* clean up for dst table */ - src_table = srcdest_srcnode_table(node); - if (src_table) { - /* This means the route_node is part of the top - * hierarchy and refers to a destination prefix. - */ - for (src_node = route_top(src_table); src_node; - src_node = route_next(src_node)) { - src_si = src_node->info; - - frr_each_safe(static_path_list, - &src_si->path_list, src_pn) { - frr_each_safe(static_nexthop_list, - &src_pn->nexthop_list, - nh) { - static_nexthop_list_del( - &src_pn->nexthop_list, - nh); - XFREE(MTYPE_STATIC_NEXTHOP, nh); - } - static_path_list_del(&src_si->path_list, - src_pn); - XFREE(MTYPE_STATIC_PATH, src_pn); - } - - XFREE(MTYPE_STATIC_ROUTE, src_node->info); - } - } - - XFREE(MTYPE_STATIC_ROUTE, node->info); - } -} - static struct static_vrf *static_vrf_alloc(void) { struct route_table *table; @@ -228,27 +170,6 @@ static int static_vrf_config_write(struct vty *vty) return 0; } -int static_vrf_has_config(struct static_vrf *svrf) -{ - struct route_table *table; - safi_t safi; - afi_t afi; - - /* - * NOTE: This is a don't care for the default VRF, but we go through - * the motions to keep things consistent. - */ - FOREACH_AFI_SAFI (afi, safi) { - table = svrf->stable[afi][safi]; - if (!table) - continue; - if (route_table_count(table)) - return 1; - } - - return 0; -} - void static_vrf_init(void) { vrf_init(static_vrf_new, static_vrf_enable, diff --git a/staticd/static_vrf.h b/staticd/static_vrf.h index 81296f2864..3977899054 100644 --- a/staticd/static_vrf.h +++ b/staticd/static_vrf.h @@ -37,8 +37,6 @@ struct stable_info { struct static_vrf *static_vrf_lookup_by_name(const char *vrf_name); struct static_vrf *static_vrf_lookup_by_id(vrf_id_t vrf_id); -int static_vrf_has_config(struct static_vrf *svrf); - void static_vrf_init(void); struct route_table *static_vrf_static_table(afi_t afi, safi_t safi, diff --git a/staticd/static_vty.c b/staticd/static_vty.c index dd03f83778..33a2728cd0 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -33,7 +33,6 @@ #include "northbound_cli.h" #include "static_vrf.h" -#include "static_memory.h" #include "static_vty.h" #include "static_routes.h" #include "static_debug.h" diff --git a/staticd/subdir.am b/staticd/subdir.am index 9c630e8f5f..a0ae2569cb 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -13,7 +13,6 @@ endif staticd_libstatic_a_SOURCES = \ staticd/static_debug.c \ - staticd/static_memory.c \ staticd/static_nht.c \ staticd/static_routes.c \ staticd/static_zebra.c \ @@ -25,7 +24,6 @@ staticd_libstatic_a_SOURCES = \ noinst_HEADERS += \ staticd/static_debug.h \ - staticd/static_memory.h \ staticd/static_nht.h \ staticd/static_zebra.h \ staticd/static_routes.h \ diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c index 391ccd9268..fde0d6af52 100644 --- a/tests/lib/cxxcompat.c +++ b/tests/lib/cxxcompat.c @@ -107,7 +107,7 @@ #include "lib/zassert.h" #include "lib/zclient.h" -PREDECL_RBTREE_UNIQ(footree) +PREDECL_RBTREE_UNIQ(footree); struct foo { int dummy; struct footree_item item; @@ -116,7 +116,7 @@ static int foocmp(const struct foo *a, const struct foo *b) { return memcmp(&a->dummy, &b->dummy, sizeof(a->dummy)); } -DECLARE_RBTREE_UNIQ(footree, struct foo, item, foocmp) +DECLARE_RBTREE_UNIQ(footree, struct foo, item, foocmp); int main(int argc, char **argv) { diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c index 40837b4722..83dd9f2c59 100644 --- a/tests/lib/test_atomlist.c +++ b/tests/lib/test_atomlist.c @@ -41,18 +41,18 @@ static struct seqlock sqlo; -PREDECL_ATOMLIST(alist) -PREDECL_ATOMSORT_UNIQ(asort) +PREDECL_ATOMLIST(alist); +PREDECL_ATOMSORT_UNIQ(asort); struct item { uint64_t val1; struct alist_item chain; struct asort_item sortc; uint64_t val2; }; -DECLARE_ATOMLIST(alist, struct item, chain) +DECLARE_ATOMLIST(alist, struct item, chain); static int icmp(const struct item *a, const struct item *b); -DECLARE_ATOMSORT_UNIQ(asort, struct item, sortc, icmp) +DECLARE_ATOMSORT_UNIQ(asort, struct item, sortc, icmp); static int icmp(const struct item *a, const struct item *b) { diff --git a/tests/lib/test_heavy_wq.c b/tests/lib/test_heavy_wq.c index cffd52ee02..00aa7b80dd 100644 --- a/tests/lib/test_heavy_wq.c +++ b/tests/lib/test_heavy_wq.c @@ -37,9 +37,9 @@ #include "tests.h" -DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test") -DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node") -DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str") +DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test"); +DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node"); +DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str"); extern struct thread_master *master; static struct work_queue *heavy_wq; diff --git a/tests/lib/test_memory.c b/tests/lib/test_memory.c index 84be9cb769..9f04304a2b 100644 --- a/tests/lib/test_memory.c +++ b/tests/lib/test_memory.c @@ -19,8 +19,8 @@ #include <zebra.h> #include <memory.h> -DEFINE_MGROUP(TEST_MEMORY, "memory test") -DEFINE_MTYPE_STATIC(TEST_MEMORY, TEST, "generic test mtype") +DEFINE_MGROUP(TEST_MEMORY, "memory test"); +DEFINE_MTYPE_STATIC(TEST_MEMORY, TEST, "generic test mtype"); /* Memory torture tests * diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 24de3fa88d..21b3a916b8 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -59,21 +59,88 @@ static void printcmp(const char *fmt, ...) errors++; } -static void printchk(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); -static void printchk(const char *ref, const char *fmt, ...) +static int printchk(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); +static int printchk(const char *ref, const char *fmt, ...) { va_list ap; char bufrr[256]; + bool truncfail = false; + size_t i; + size_t expectlen; + memset(bufrr, 0xcc, sizeof(bufrr)); va_start(ap, fmt); - vsnprintfrr(bufrr, sizeof(bufrr), fmt, ap); + expectlen = vsnprintfrr(NULL, 0, fmt, ap); + va_end(ap); + + va_start(ap, fmt); + vsnprintfrr(bufrr, 7, fmt, ap); va_end(ap); - printf("fmt: \"%s\"\nref: \"%s\"\nfrr: \"%s\"\n%s\n\n", + if (strnlen(bufrr, 7) == 7) + truncfail = true; + if (strnlen(bufrr, 7) < 7 && strncmp(ref, bufrr, 6) != 0) + truncfail = true; + for (i = 7; i < sizeof(bufrr); i++) + if (bufrr[i] != (char)0xcc) { + truncfail = true; + break; + } + + if (truncfail) { + printf("truncation test FAILED:\n" + "fmt: \"%s\"\nref: \"%s\"\nfrr[:7]: \"%s\"\n%s\n\n", + fmt, ref, bufrr, strcmp(ref, bufrr) ? "ERROR" : "ok"); + errors++; + } + + struct fmt_outpos outpos[16]; + struct fbuf fb = { + .buf = bufrr, + .pos = bufrr, + .len = sizeof(bufrr) - 1, + .outpos = outpos, + .outpos_n = array_size(outpos), + }; + + va_start(ap, fmt); + vbprintfrr(&fb, fmt, ap); + fb.pos[0] = '\0'; + va_end(ap); + + printf("fmt: \"%s\"\nref: \"%s\"\nfrr: \"%s\"\n%s\n", fmt, ref, bufrr, strcmp(ref, bufrr) ? "ERROR" : "ok"); if (strcmp(ref, bufrr)) errors++; + if (strlen(bufrr) != expectlen) { + printf("return value <> length mismatch\n"); + errors++; + } + + for (size_t i = 0; i < fb.outpos_i; i++) + printf("\t[%zu: %u..%u] = \"%.*s\"\n", i, + outpos[i].off_start, + outpos[i].off_end, + (int)(outpos[i].off_end - outpos[i].off_start), + bufrr + outpos[i].off_start); + printf("\n"); + return 0; +} + +static void test_va(const char *ref, const char *fmt, ...) PRINTFRR(2, 3); +static void test_va(const char *ref, const char *fmt, ...) +{ + struct va_format vaf; + va_list ap; + + va_start(ap, fmt); + vaf.fmt = fmt; + vaf.va = ≈ + + printchk(ref, "VA [%pVA] %s", &vaf, "--"); + + va_end(ap); } int main(int argc, char **argv) @@ -112,9 +179,12 @@ int main(int argc, char **argv) inet_aton("192.168.1.2", &ip); printchk("192.168.1.2", "%pI4", &ip); printchk(" 192.168.1.2", "%20pI4", &ip); + printchk("192.168.1.2 ", "%-20pI4", &ip); printcmp("%p", &ip); + test_va("VA [192.168.1.2 1234] --", "%pI4 %u", &ip, 1234); + snprintfrr(buf, sizeof(buf), "test%s", "#1"); csnprintfrr(buf, sizeof(buf), "test%s", "#2"); assert(strcmp(buf, "test#1test#2") == 0); @@ -146,5 +216,42 @@ int main(int argc, char **argv) sg.src.s_addr = INADDR_ANY; printchk("(*,224.1.2.3)", "%pSG4", &sg); + uint8_t randhex[] = { 0x12, 0x34, 0x00, 0xca, 0xfe, 0x00, 0xaa, 0x55 }; + + FMT_NSTD(printchk("12 34 00 ca fe 00 aa 55", "%.8pHX", randhex)); + FMT_NSTD(printchk("12 34 00 ca fe 00 aa 55", "%.*pHX", + (int)sizeof(randhex), randhex)); + FMT_NSTD(printchk("12 34 00 ca", "%.4pHX", randhex)); + + printchk("12 34 00 ca fe 00 aa 55", "%8pHX", randhex); + printchk("12 34 00 ca fe 00 aa 55", "%*pHX", + (int)sizeof(randhex), randhex); + printchk("12 34 00 ca", "%4pHX", randhex); + + printchk("", "%pHX", randhex); + + printchk("12:34:00:ca:fe:00:aa:55", "%8pHXc", randhex); + printchk("123400cafe00aa55", "%8pHXn", randhex); + + printchk("/test/pa\\ th/\\~spe\\ncial\\x01/file.name", "%pSE", + "/test/pa th/~spe\ncial\x01/file.name"); + printchk("/test/pa\\ th/\\~spe\\n", "%17pSE", + "/test/pa th/~spe\ncial\x01/file.name"); + + char nulltest[] = { 'n', 'u', 0, 'l', 'l' }; + + printchk("nu\\x00ll", "%5pSE", nulltest); + printchk("nu\\x00ll", "%*pSE", 5, nulltest); + + printchk("bl\\\"ah\\x01te[st\\nab]c", "%pSQ", + "bl\"ah\x01te[st\nab]c"); + printchk("\"bl\\\"ah\\x01te[st\\nab]c\"", "%pSQq", + "bl\"ah\x01te[st\nab]c"); + printchk("\"bl\\\"ah\\x01te[st\\x0aab\\]c\"", "%pSQqs", + "bl\"ah\x01te[st\nab]c"); + printchk("\"\"", "%pSQqn", ""); + printchk("\"\"", "%pSQqn", (char *)NULL); + printchk("(null)", "%pSQq", (char *)NULL); + return !!errors; } diff --git a/tests/lib/test_table.c b/tests/lib/test_table.c index 290657bd56..9b6539e3bc 100644 --- a/tests/lib/test_table.c +++ b/tests/lib/test_table.c @@ -20,7 +20,7 @@ */ #include <zebra.h> - +#include "printfrr.h" #include "prefix.h" #include "table.h" @@ -113,7 +113,7 @@ static void print_subtree(struct route_node *rn, const char *legend, printf(" "); } - printf("%s: %pFX", legend, &rn->p); + printfrr("%s: %pFX", legend, &rn->p); if (!rn->info) { printf(" (internal)"); } diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h index f86cadd398..32331c14a0 100644 --- a/tests/lib/test_typelist.h +++ b/tests/lib/test_typelist.h @@ -47,7 +47,7 @@ #define REALTYPE TYPE #endif -PREDECL(REALTYPE, list) +PREDECL(REALTYPE, list); struct item { uint64_t val; struct list_item itm; @@ -59,7 +59,7 @@ static int list_cmp(const struct item *a, const struct item *b); #if IS_HASH(REALTYPE) static uint32_t list_hash(const struct item *a); -DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash) +DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash); static uint32_t list_hash(const struct item *a) { @@ -72,7 +72,7 @@ static uint32_t list_hash(const struct item *a) } #else -DECLARE(REALTYPE, list, struct item, itm, list_cmp) +DECLARE(REALTYPE, list, struct item, itm, list_cmp); #endif static int list_cmp(const struct item *a, const struct item *b) @@ -85,7 +85,7 @@ static int list_cmp(const struct item *a, const struct item *b) } #else /* !IS_SORTED */ -DECLARE(REALTYPE, list, struct item, itm) +DECLARE(REALTYPE, list, struct item, itm); #endif #define NITEM 10000 diff --git a/tests/lib/test_xref.c b/tests/lib/test_xref.c index 700950de1f..aa179141af 100644 --- a/tests/lib/test_xref.c +++ b/tests/lib/test_xref.c @@ -127,7 +127,7 @@ bool (*tests[])(void) = { test_logcall, }; -XREF_SETUP() +XREF_SETUP(); int main(int argc, char **argv) { diff --git a/tests/lib/test_zmq.c b/tests/lib/test_zmq.c index fe330d98d4..65195aa3e1 100644 --- a/tests/lib/test_zmq.c +++ b/tests/lib/test_zmq.c @@ -22,8 +22,8 @@ #include "sigevent.h" #include "frr_zmq.h" -DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer") -DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message") +DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer"); +DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message"); static struct thread_master *master; diff --git a/tests/ospfd/test_ospf_spf.c b/tests/ospfd/test_ospf_spf.c index a85f7e14ec..7808c3d47d 100644 --- a/tests/ospfd/test_ospf_spf.c +++ b/tests/ospfd/test_ospf_spf.c @@ -23,9 +23,9 @@ #include "common.h" DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item, - p_spaces_compare_func) + p_spaces_compare_func); DECLARE_RBTREE_UNIQ(q_spaces, struct q_space, q_spaces_item, - q_spaces_compare_func) + q_spaces_compare_func); static struct ospf *test_init(struct ospf_test_node *root) { diff --git a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json index bab24c4fa0..86a7e5139c 100644 --- a/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json @@ -6,14 +6,14 @@ "interface": "r1-eth1", "multihop": false, "peer": "172.16.100.2", - "receive-interval": 300, + "receive-interval": 800, "remote-detect-multiplier": 3, "remote-diagnostic": "ok", "remote-id": "*", "remote-receive-interval": 300, "remote-transmit-interval": 300, "status": "up", - "transmit-interval": 300, + "transmit-interval": 800, "uptime": "*", "vrf": "default" }, diff --git a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf index 4798d17c40..fcea5d48fc 100644 --- a/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf +++ b/tests/topotests/bfd-profiles-topo1/r1/ospfd.conf @@ -2,7 +2,7 @@ interface r1-eth1 ip ospf area 0 ip ospf hello-interval 2 ip ospf dead-interval 10 - ip ospf bfd + ip ospf bfd profile slowtx ! router ospf ospf router-id 10.254.254.1 diff --git a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json index 4e6fa869ba..ec973eb365 100644 --- a/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json +++ b/tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json @@ -10,8 +10,8 @@ "remote-detect-multiplier": 3, "remote-diagnostic": "ok", "remote-id": "*", - "remote-receive-interval": 300, - "remote-transmit-interval": 300, + "remote-receive-interval": 800, + "remote-transmit-interval": 800, "status": "up", "transmit-interval": 300, "uptime": "*", diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py b/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf new file mode 100644 index 0000000000..bf39152ea8 --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf @@ -0,0 +1,3 @@ +! +router bgp 65001 +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf new file mode 100644 index 0000000000..697765168d --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf @@ -0,0 +1,7 @@ +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! + diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf new file mode 100644 index 0000000000..abbd1b86fa --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf @@ -0,0 +1,5 @@ +! +router bgp 65001 + no bgp default ipv4-unicast + bgp default ipv6-unicast +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf new file mode 100644 index 0000000000..a405c047ca --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf @@ -0,0 +1,4 @@ +! +router bgp 65001 + bgp default ipv6-unicast +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf new file mode 100644 index 0000000000..e9fdfb70c5 --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf @@ -0,0 +1,6 @@ +! +interface r3-eth0 + ip address 192.168.255.3/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py b/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py new file mode 100644 index 0000000000..c1dbf0ebec --- /dev/null +++ b/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2021 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 `bgp default ipv4-unicast` and `bgp default ipv6-unicast` +commands work as expected. + +STEP 1: 'Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only' +STEP 2: 'Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only' +STEP 3: 'Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families' +""" + +import os +import sys +import json +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 +from lib.common_config import step + + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 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_default_ipv4_ipv6_unicast(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only") + + def _bgp_neighbor_ipv4_af_only(): + tgen.gears["r1"].vtysh_cmd( + "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external" + ) + + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp summary json")) + + if "ipv4Unicast" in output and "ipv6Unicast" not in output: + return True + return False + + assert _bgp_neighbor_ipv4_af_only() == True + + step("Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only") + + def _bgp_neighbor_ipv6_af_only(): + tgen.gears["r2"].vtysh_cmd( + "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external" + ) + + output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp summary json")) + + if "ipv4Unicast" not in output and "ipv6Unicast" in output: + return True + return False + + assert _bgp_neighbor_ipv6_af_only() == True + + step( + "Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families" + ) + + def _bgp_neighbor_ipv4_and_ipv6_af(): + tgen.gears["r3"].vtysh_cmd( + "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external" + ) + + output = json.loads(tgen.gears["r3"].vtysh_cmd("show bgp summary json")) + + if "ipv4Unicast" in output and "ipv6Unicast" in output: + return True + return False + + assert _bgp_neighbor_ipv4_and_ipv6_af() == True + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py index a6338d0c70..aa99ebf6d0 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py @@ -137,7 +137,7 @@ from lib.common_config import ( kill_mininet_routers_process, get_frr_ipv6_linklocal, create_route_maps, - required_linux_kernel_version, + required_linux_kernel_version ) # Reading the data from JSON File for topology and configuration creation @@ -258,10 +258,12 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, dut) + neighbor = topo["routers"][peer]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, peer) + neighbor = topo["routers"][dut]["links"]["r2-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) @@ -551,7 +553,7 @@ def test_BGP_GR_TC_46_p1(request): write_test_footer(tc_name) -def test_BGP_GR_TC_50_p1(request): +def BGP_GR_TC_50_p1(request): """ Test Objective : Transition from Peer-level helper to Global inherit helper Global Mode : None @@ -613,9 +615,6 @@ def test_BGP_GR_TC_50_p1(request): configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - result = verify_bgp_convergence_from_running_config(tgen) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - step("Verify on R2 that R1 advertises GR capabilities as a helper node") for addr_type in ADDR_TYPES: @@ -721,7 +720,12 @@ def test_BGP_GR_TC_50_p1(request): } } - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) @@ -979,7 +983,15 @@ def test_BGP_GR_TC_51_p1(request): } } - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) step("Verify on R2 that R1 advertises GR capabilities as a helper node") @@ -1695,10 +1707,10 @@ def test_BGP_GR_TC_6_1_2_p1(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r1") - clear_bgp(tgen, addr_type, "r2") + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) - result = verify_bgp_convergence_from_running_config(tgen, topo) + result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Verify GR stats @@ -2651,10 +2663,10 @@ def test_BGP_GR_TC_31_1_p1(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r1") - clear_bgp(tgen, addr_type, "r2") + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) - result = verify_bgp_convergence_from_running_config(tgen, topo) + result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Verify GR stats @@ -2932,10 +2944,10 @@ def test_BGP_GR_TC_31_2_p1(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r1") - clear_bgp(tgen, addr_type, "r2") + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) - result = verify_bgp_convergence_from_running_config(tgen, topo) + result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) # Verify GR stats @@ -5258,7 +5270,7 @@ def test_BGP_GR_TC_49_p1(request): write_test_footer(tc_name) -def test_BGP_GR_TC_52_p1(request): +def BGP_GR_TC_52_p1(request): """ Test Objective : Transition from Peer-level disbale to Global inherit helper Global Mode : None diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py index 2c5dd92f54..c7dca72570 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py @@ -136,7 +136,7 @@ from lib.common_config import ( kill_mininet_routers_process, get_frr_ipv6_linklocal, create_route_maps, - required_linux_kernel_version, + required_linux_kernel_version ) # Reading the data from JSON File for topology and configuration creation @@ -251,12 +251,14 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, dut) + neighbor = topo["routers"][peer]["links"][dut][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, peer) + neighbor = topo["routers"][dut]["links"][peer][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) - result = verify_bgp_convergence_from_running_config(tgen, topo) + result = verify_bgp_convergence_from_running_config(tgen) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) return True @@ -930,7 +932,7 @@ def test_BGP_GR_10_p2(request): write_test_footer(tc_name) -def test_BGP_GR_16_p2(request): +def BGP_GR_16_p2(request): """ Test Objective : Verify BGP-GR feature when restarting node is a transit router for it's iBGP peers. diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py index ac7ee44b25..464d6eb475 100644 --- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py +++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py @@ -115,7 +115,7 @@ sys.path.append(os.path.join(CWD, "../lib/")) # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from mininet.topo import Topo - +from lib.topotest import iproute2_is_vrf_capable from lib.common_config import ( step, verify_rib, @@ -215,6 +215,10 @@ def setup_module(mod): if result is not True: pytest.skip("Kernel requirements are not met") + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + testsuite_run_time = time.asctime(time.localtime(time.time())) logger.info("Testsuite start time: {}".format(testsuite_run_time)) logger.info("=" * 40) diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index c6e1792e84..10cf1c6ae8 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -71,7 +71,7 @@ sys.path.append(os.path.join(CWD, "../lib/")) # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from mininet.topo import Topo - +from lib.topotest import iproute2_is_vrf_capable from lib.common_config import ( step, verify_rib, @@ -164,6 +164,10 @@ def setup_module(mod): if result is not True: pytest.skip("Kernel requirements are not met") + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + testsuite_run_time = time.asctime(time.localtime(time.time())) logger.info("Testsuite start time: {}".format(testsuite_run_time)) logger.info("=" * 40) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/exabgp.env b/tests/topotests/bgp_peer-type_multipath-relax/exabgp.env new file mode 100644 index 0000000000..6c554f5fa8 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/exabgp.env @@ -0,0 +1,53 @@ + +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa-receive.py b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa-receive.py new file mode 100755 index 0000000000..031ff455ca --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin, argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open("/tmp/peer%s-received.log" % peer, "w") + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S - ") + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa_readpipe.py b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa_readpipe.py new file mode 100644 index 0000000000..9e689a27e3 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, "r") + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer1/exabgp.cfg b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exabgp.cfg new file mode 100644 index 0000000000..4a7dc48126 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer1/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer1.in"; + encoder text; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 1"; + receive-routes; + encoder text; + } + + neighbor 10.0.1.1 { + router-id 10.0.1.2; + local-address 10.0.1.2; + local-as 64510; + peer-as 64510; + } + +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa-receive.py b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa-receive.py new file mode 100755 index 0000000000..031ff455ca --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin, argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open("/tmp/peer%s-received.log" % peer, "w") + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S - ") + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa_readpipe.py b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa_readpipe.py new file mode 100644 index 0000000000..9e689a27e3 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, "r") + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer2/exabgp.cfg b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exabgp.cfg new file mode 100644 index 0000000000..b53b054550 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer2/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer2.in"; + encoder text; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 2"; + receive-routes; + encoder text; + } + + neighbor 10.0.2.1 { + router-id 10.0.2.2; + local-address 10.0.2.2; + local-as 64511; + peer-as 64511; + } + +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa-receive.py b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa-receive.py new file mode 100755 index 0000000000..031ff455ca --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin, argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open("/tmp/peer%s-received.log" % peer, "w") + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S - ") + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa_readpipe.py b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa_readpipe.py new file mode 100644 index 0000000000..9e689a27e3 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, "r") + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer3/exabgp.cfg b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exabgp.cfg new file mode 100644 index 0000000000..6a1cc2fb3f --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer3/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer3.in"; + encoder text; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 3"; + receive-routes; + encoder text; + } + + neighbor 10.0.3.1 { + router-id 10.0.3.2; + local-address 10.0.3.2; + local-as 64502; + peer-as 64501; + } + +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa-receive.py b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa-receive.py new file mode 100755 index 0000000000..031ff455ca --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa-receive.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +""" +exa-receive.py: Save received routes form ExaBGP into file +""" + +from sys import stdin, argv +from datetime import datetime + +# 1st arg is peer number +peer = int(argv[1]) + +# When the parent dies we are seeing continual newlines, so we only access so many before stopping +counter = 0 + +routesavefile = open("/tmp/peer%s-received.log" % peer, "w") + +while True: + try: + line = stdin.readline() + timestamp = datetime.now().strftime("%Y%m%d_%H:%M:%S - ") + routesavefile.write(timestamp + line) + routesavefile.flush() + + if line == "": + counter += 1 + if counter > 100: + break + continue + + counter = 0 + except KeyboardInterrupt: + pass + except IOError: + # most likely a signal during readline + pass + +routesavefile.close() diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa_readpipe.py b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa_readpipe.py new file mode 100644 index 0000000000..9e689a27e3 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exa_readpipe.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +"Helper script to read api commands from a pipe and feed them to ExaBGP" + +import sys + +if len(sys.argv) != 2: + sys.exit(1) +fifo = sys.argv[1] + +while True: + pipe = open(fifo, "r") + with pipe: + line = pipe.readline().strip() + if line != "": + sys.stdout.write("{}\n".format(line)) + sys.stdout.flush() + pipe.close() + +sys.exit(0) diff --git a/tests/topotests/bgp_peer-type_multipath-relax/peer4/exabgp.cfg b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exabgp.cfg new file mode 100644 index 0000000000..2cc26cb80f --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/peer4/exabgp.cfg @@ -0,0 +1,21 @@ +group controller { + + process announce-routes { + run "/etc/exabgp/exa_readpipe.py /var/run/exabgp_peer4.in"; + encoder text; + } + + process receive-routes { + run "/etc/exabgp/exa-receive.py 4"; + receive-routes; + encoder text; + } + + neighbor 10.0.4.1 { + router-id 10.0.4.2; + local-address 10.0.4.2; + local-as 64503; + peer-as 64501; + } + +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/bgpd.conf b/tests/topotests/bgp_peer-type_multipath-relax/r1/bgpd.conf new file mode 100644 index 0000000000..038f108aa8 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/bgpd.conf @@ -0,0 +1,16 @@ +! +router bgp 64510 + bgp router-id 10.0.1.1 + no bgp ebgp-requires-policy + bgp confederation identifier 64501 + bgp confederation peers 64511 + bgp bestpath as-path multipath-relax + bgp bestpath compare-routerid + bgp bestpath peer-type multipath-relax + neighbor 10.0.1.2 remote-as 64510 + neighbor 10.0.3.2 remote-as 64502 + neighbor 10.0.4.2 remote-as 64503 + neighbor 10.0.5.2 remote-as 64511 +! +line vty +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/multipath.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/multipath.json new file mode 100644 index 0000000000..11dad786f2 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/multipath.json @@ -0,0 +1,50 @@ +{ + "routes": { "203.0.113.0/30": [ + { + "valid":true, + "multipath":true, + "pathFrom":"external", + "peerId":"10.0.5.2" + }, + { + "valid":true, + "bestpath":true, + "selectionReason":"Peer Type", + "pathFrom":"external", + "peerId":"10.0.4.2" + }, + { + "valid":true, + "multipath":true, + "pathFrom":"internal", + "peerId":"10.0.1.2" + } +],"203.0.113.4/30": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"Confed Peer Type", + "pathFrom":"external", + "peerId":"10.0.5.2" + }, + { + "valid":true, + "multipath":true, + "pathFrom":"internal", + "peerId":"10.0.1.2" + } +],"203.0.113.8/30": [ + { + "valid":true, + "multipath":true, + "pathFrom":"external", + "peerId":"10.0.4.2" + }, + { + "valid":true, + "bestpath":true, + "selectionReason":"Router ID", + "pathFrom":"external", + "peerId":"10.0.3.2" + } +] } } diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/not-multipath.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/not-multipath.json new file mode 100644 index 0000000000..c621832157 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/not-multipath.json @@ -0,0 +1,50 @@ +{ + "routes": { "203.0.113.0/30": [ + { + "valid":true, + "multipath":null, + "pathFrom":"external", + "peerId":"10.0.5.2" + }, + { + "valid":true, + "bestpath":true, + "selectionReason":"Peer Type", + "pathFrom":"external", + "peerId":"10.0.4.2" + }, + { + "valid":true, + "multipath":null, + "pathFrom":"internal", + "peerId":"10.0.1.2" + } +],"203.0.113.4/30": [ + { + "valid":true, + "bestpath":true, + "selectionReason":"Confed Peer Type", + "pathFrom":"external", + "peerId":"10.0.5.2" + }, + { + "valid":true, + "multipath":null, + "pathFrom":"internal", + "peerId":"10.0.1.2" + } +],"203.0.113.8/30": [ + { + "valid":true, + "multipath":true, + "pathFrom":"external", + "peerId":"10.0.4.2" + }, + { + "valid":true, + "bestpath":true, + "selectionReason":"Router ID", + "pathFrom":"external", + "peerId":"10.0.3.2" + } +] } } diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-confed.json new file mode 100644 index 0000000000..22ec2c298b --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-confed.json @@ -0,0 +1,33 @@ +{ + "203.0.113.0\/30":[ + { + "prefix":"203.0.113.0\/30", + "protocol":"bgp", + "installed":true, + "internalNextHopNum":4, + "internalNextHopActiveNum":4, + "nexthops":[ + { + "ip":"198.51.100.2", + "active":true, + "recursive":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "active":true + }, + { + "ip":"198.51.100.10", + "active":true, + "recursive":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-iBGP.json new file mode 100644 index 0000000000..facddcda46 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-eBGP-iBGP.json @@ -0,0 +1,33 @@ +{ + "203.0.113.0\/30":[ + { + "prefix":"203.0.113.0\/30", + "protocol":"bgp", + "installed":true, + "internalNextHopNum":4, + "internalNextHopActiveNum":4, + "nexthops":[ + { + "ip":"198.51.100.1", + "active":true, + "recursive":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "active":true + }, + { + "ip":"198.51.100.10", + "active":true, + "recursive":true + }, + { + "fib":true, + "ip":"10.0.3.2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-no-recursive.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-no-recursive.json new file mode 100644 index 0000000000..5399ceefcc --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-no-recursive.json @@ -0,0 +1,35 @@ +{ + "prefix":"203.0.113.0\/30", + "paths":[ + { + "valid":false, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "valid":true, + "multipath":true, + "bestpath":{ + "overall":true, + "selectionReason":"Confed Peer Type" + }, + "peer":{ + "peerId":"10.0.5.2", + "routerId":"10.0.5.2", + "type":"confed-external" + } + }, + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.1.2", + "routerId":"10.0.1.2", + "type":"confed-internal" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-recursive.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-recursive.json new file mode 100644 index 0000000000..7da95aed1c --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1-recursive.json @@ -0,0 +1,36 @@ +{ + "prefix":"203.0.113.0\/30", + "paths":[ + { + "valid":true, + "multipath":true, + "bestpath":{ + "overall":true, + "selectionReason":"Peer Type" + }, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.5.2", + "routerId":"10.0.5.2", + "type":"confed-external" + } + }, + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.1.2", + "routerId":"10.0.1.2", + "type":"confed-internal" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1.json new file mode 100644 index 0000000000..a90669a474 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix1.json @@ -0,0 +1,33 @@ +{ + "prefix":"203.0.113.0\/30", + "paths":[ + { + "multipath":true, + "peer":{ + "peerId":"10.0.5.2", + "routerId":"10.0.5.2", + "type":"confed-external" + } + }, + { + "multipath":true, + "bestpath":{ + "overall":true, + "selectionReason":"Peer Type" + }, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "multipath":true, + "peer":{ + "peerId":"10.0.1.2", + "routerId":"10.0.1.2", + "type":"confed-internal" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-ip-route.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-ip-route.json new file mode 100644 index 0000000000..1bf38efcc5 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-ip-route.json @@ -0,0 +1,23 @@ +{ + "203.0.113.8\/30":[ + { + "prefix":"203.0.113.8\/30", + "protocol":"bgp", + "installed":true, + "internalNextHopNum":2, + "internalNextHopActiveNum":1, + "nexthops":[ + { + "fib":true, + "ip":"10.0.3.2", + "active":true + }, + { + "fib":null, + "ip":"198.51.100.10", + "active":null + } + ] + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-no-recursive.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-no-recursive.json new file mode 100644 index 0000000000..33d0f2d1ce --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-no-recursive.json @@ -0,0 +1,21 @@ +{ + "prefix":"203.0.113.8\/30", + "paths":[ + { + "valid":false, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "valid":true, + "peer":{ + "peerId":"10.0.3.2", + "routerId":"10.0.3.2", + "type":"external" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-recursive.json b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-recursive.json new file mode 100644 index 0000000000..6ac2512a60 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/prefix3-recursive.json @@ -0,0 +1,23 @@ +{ + "prefix":"203.0.113.8\/30", + "paths":[ + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.4.2", + "routerId":"10.0.4.2", + "type":"external" + } + }, + { + "valid":true, + "multipath":true, + "peer":{ + "peerId":"10.0.3.2", + "routerId":"10.0.3.2", + "type":"external" + } + } + ] +} diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r1/zebra.conf b/tests/topotests/bgp_peer-type_multipath-relax/r1/zebra.conf new file mode 100644 index 0000000000..911aa1c39d --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r1/zebra.conf @@ -0,0 +1,27 @@ +! +hostname r1 +! +interface r1-eth0 + description ExaBGP iBGP peer1 + ip address 10.0.1.1/24 + no link-detect +! +interface r1-eth1 + description ExaBGP peer3 + ip address 10.0.3.1/24 + no link-detect +! +interface r1-eth2 + description ExaBGP peer4 + ip address 10.0.4.1/24 + no link-detect +! +interface r1-eth3 + description r2 confed peer + ip address 10.0.5.1/24 + no link-detect +! +ip forwarding +! +line vty +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r2/bgpd.conf b/tests/topotests/bgp_peer-type_multipath-relax/r2/bgpd.conf new file mode 100644 index 0000000000..2362a19f26 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r2/bgpd.conf @@ -0,0 +1,19 @@ +! +!log file bgpd.log +! +router bgp 64511 + bgp confederation identifier 64501 + bgp confederation peers 64510 + bgp router-id 10.0.5.2 + no bgp ebgp-requires-policy + neighbor 10.0.2.2 remote-as 64511 + neighbor 10.0.5.1 remote-as 64510 + ! + address-family ipv4 unicast + neighbor 10.0.5.1 route-map dropall in + exit-address-family +! +route-map dropall deny 10 +! +line vty +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r2/staticd.conf b/tests/topotests/bgp_peer-type_multipath-relax/r2/staticd.conf new file mode 100644 index 0000000000..35ebe0dc66 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r2/staticd.conf @@ -0,0 +1,4 @@ +hostname r2 +! +ip route 198.51.100.0/24 10.0.2.2 +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/r2/zebra.conf b/tests/topotests/bgp_peer-type_multipath-relax/r2/zebra.conf new file mode 100644 index 0000000000..900e7d4fbc --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/r2/zebra.conf @@ -0,0 +1,19 @@ +! +! +hostname r2 +! +interface r2-eth0 + description ExaBGP peer + ip address 10.0.2.1/24 + no link-detect +! +interface r2-eth1 + description r1 confed peer + ip address 10.0.5.2/24 + no link-detect +! +ip forwarding +! +! +line vty +! diff --git a/tests/topotests/bgp_peer-type_multipath-relax/test_bgp_peer-type_multipath-relax.py b/tests/topotests/bgp_peer-type_multipath-relax/test_bgp_peer-type_multipath-relax.py new file mode 100755 index 0000000000..39a0beeb11 --- /dev/null +++ b/tests/topotests/bgp_peer-type_multipath-relax/test_bgp_peer-type_multipath-relax.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python + +# +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 Arista Networks, Inc. +# +# 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 Arista Networks 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_bgp_peer-type_multipath-relax.py: + +Test the effects of the "bgp bestpath peer-type multipath-relax" command + +- enabling the command allows eBGP, iBGP, and confed routes to be multipath +- the choice of best path is not affected +- disabling the command removes iBGP/confed routes from multipath +- enabling the command does not forgive eBGP routes of the requirement + (when enabled) that next hops resolve over connected routes +- a mixed-type multipath next hop, when published to zebra, does not + require resolving next hops over connected routes +- with the command enabled, an all-eBGP multipath next hop still requires + resolving next hops over connected routes when published to zebra + +Topology used by the test: + + eBGP +------+ iBGP + peer1 ---- | r1 | ---- peer3 + | | +peer2 ---- r2 ---- | | ---- peer4 + iBGP confed +------+ eBGP + +r2 is present in this topology because ExaBGP does not currently support +confederations so we use FRR to advertise the required AS_CONFED_SEQUENCE. + +Routes are advertised from different peers to form interesting multipaths. + + peer1 peer2 peer3 peer4 multipath on r1 + +203.0.113.0/30 x x x all 3 +203.0.113.4/30 x x confed-iBGP +203.0.113.8/30 x x eBGP-only + +There is also a BGP-advertised route used only for recursively resolving +next hops. +""" + +import functools +import json +import os +import pytest +import sys + +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 PeerTypeRelaxTopo(Topo): + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Set up routers + tgen.add_router("r1") # DUT + tgen.add_router("r2") + + # Set up peers + for peern in range(1, 5): + peer = tgen.add_exabgp_peer( + "peer{}".format(peern), + ip="10.0.{}.2/24".format(peern), + defaultRoute="via 10.0.{}.1".format(peern), + ) + if peern == 2: + tgen.add_link(tgen.gears["r2"], peer) + else: + tgen.add_link(tgen.gears["r1"], peer) + tgen.add_link(tgen.gears["r1"], tgen.gears["r2"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(PeerTypeRelaxTopo, mod.__name__) + tgen.start_topology() + + # For all registered routers, load the zebra configuration file + for rname, router in tgen.routers().items(): + router.run("/bin/bash {}/setup_vrfs".format(CWD)) + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + + # Start up exabgp peers + peers = tgen.exabgp_peers() + for peer in peers: + fifo_in = "/var/run/exabgp_{}.in".format(peer) + if os.path.exists(fifo_in): + os.remove(fifo_in) + os.mkfifo(fifo_in, 0o777) + logger.info("Starting ExaBGP on peer {}".format(peer)) + peer_dir = os.path.join(CWD, peer) + env_file = os.path.join(CWD, "exabgp.env") + peers[peer].start(peer_dir, env_file) + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_bgp_peer_type_multipath_relax(): + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def exabgp_cmd(peer, cmd): + pipe = open("/run/exabgp_{}.in".format(peer), "w") + with pipe: + pipe.write(cmd) + pipe.close() + + # Prefixes used in the test + prefix1 = "203.0.113.0/30" + prefix2 = "203.0.113.4/30" + prefix3 = "203.0.113.8/30" + # Next hops used for iBGP/confed routes + resolved_nh1 = "198.51.100.1" + resolved_nh2 = "198.51.100.2" + # BGP route used for recursive resolution + bgp_resolving_prefix = "198.51.100.0/24" + # Next hop that will require non-connected recursive resolution + ebgp_resolved_nh = "198.51.100.10" + + # Send a non-connected route to resolve others + exabgp_cmd( + "peer3", "announce route {} next-hop self\n".format(bgp_resolving_prefix) + ) + router = tgen.gears["r1"] + + # It seems that if you write to the exabgp socket too quickly in + # succession, requests get lost. So verify prefix1 now instead of + # after all the prefixes are advertised. + logger.info("Create and verify mixed-type multipaths") + exabgp_cmd( + "peer1", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh1 + ), + ) + exabgp_cmd( + "peer2", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh2 + ), + ) + exabgp_cmd("peer4", "announce route {} next-hop self\n".format(prefix1)) + reffile = os.path.join(CWD, "r1/prefix1.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Mixed-type multipath not found" + assert res is None, assertMsg + + logger.info("Create and verify eBGP and iBGP+confed multipaths") + exabgp_cmd( + "peer1", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix2, resolved_nh1 + ), + ) + exabgp_cmd( + "peer2", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix2, resolved_nh2 + ), + ) + exabgp_cmd("peer3", "announce route {} next-hop self".format(prefix3)) + exabgp_cmd("peer4", "announce route {} next-hop self".format(prefix3)) + reffile = os.path.join(CWD, "r1/multipath.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Not all expected multipaths found" + assert res is None, assertMsg + + logger.info("Toggle peer-type multipath-relax and verify the changes") + router.vtysh_cmd( + "conf\n router bgp 64510\n no bgp bestpath peer-type multipath-relax\n" + ) + # This file verifies "multipath" is not set + reffile = os.path.join(CWD, "r1/not-multipath.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Disabling peer-type multipath-relax did not take effect" + assert res is None, assertMsg + + router.vtysh_cmd( + "conf\n router bgp 64510\n bgp bestpath peer-type multipath-relax\n" + ) + reffile = os.path.join(CWD, "r1/multipath.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, router, "show ip bgp json", expected + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Reenabling peer-type multipath-relax did not take effect" + assert res is None, assertMsg + + logger.info("Check recursive resolution of eBGP next hops is not affected") + # eBGP next hop resolution rejects recursively resolved next hops by + # default, even with peer-type multipath-relax + exabgp_cmd( + "peer4", "announce route {} next-hop {}\n".format(prefix3, ebgp_resolved_nh) + ) + reffile = os.path.join(CWD, "r1/prefix3-no-recursive.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix3), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix3) + assert res is None, assertMsg + + exabgp_cmd( + "peer4", "announce route {} next-hop {}\n".format(prefix1, ebgp_resolved_nh) + ) + reffile = os.path.join(CWD, "r1/prefix1-no-recursive.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix1) + assert res is None, assertMsg + + # When other config allows recursively resolved eBGP next hops, + # such next hops in all-eBGP multipaths should be valid + router.vtysh_cmd("conf\n router bgp 64510\n neighbor 10.0.4.2 ebgp-multihop\n") + reffile = os.path.join(CWD, "r1/prefix3-recursive.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix3), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix3) + assert res is None, assertMsg + + reffile = os.path.join(CWD, "r1/prefix1-recursive.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip bgp {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "Recursive eBGP next hop not as expected for {}".format(prefix1) + assert res is None, assertMsg + + logger.info("Check mixed-type multipath next hop recursive resolution in FIB") + # There are now two eBGP-learned routes with a recursively resolved next; + # hop; one is all-eBGP multipath, and the other is iBGP/eBGP/ + # confed-external. The peer-type multipath-relax feature only enables + # recursive resolution in FIB if any next hop is iBGP/confed-learned. The + # all-eBGP multipath will have only one valid next hop in the FIB. + reffile = os.path.join(CWD, "r1/prefix3-ip-route.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip route {} json".format(prefix3), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "FIB next hops mismatch for all-eBGP multipath" + assert res is None, assertMsg + + # check confed-external enables recursively resolved next hops by itself + exabgp_cmd( + "peer1", + "withdraw route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh1 + ), + ) + reffile = os.path.join(CWD, "r1/prefix1-eBGP-confed.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip route {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "FIB next hops mismatch for eBGP+confed-external multipath" + assert res is None, assertMsg + + # check iBGP by itself + exabgp_cmd( + "peer1", + "announce route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh1 + ), + ) + exabgp_cmd( + "peer2", + "withdraw route {} next-hop {} as-path [ 64499 ]\n".format( + prefix1, resolved_nh2 + ), + ) + reffile = os.path.join(CWD, "r1/prefix1-eBGP-iBGP.json") + expected = json.loads(open(reffile).read()) + test_func = functools.partial( + topotest.router_json_cmp, + router, + "show ip route {} json".format(prefix1), + expected, + ) + _, res = topotest.run_and_expect(test_func, None, count=10, wait=1) + assertMsg = "FIB next hops mismatch for eBGP+iBGP multipath" + assert res is None, assertMsg + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index 04e9961f10..7ad5d8c9ab 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -2,13 +2,14 @@ Topotest conftest.py file. """ +import os +import pdb +import pytest + from lib.topogen import get_topogen, diagnose_env from lib.topotest import json_cmp_result +from lib.topotest import g_extra_config as topotest_extra_config from lib.topolog import logger -import pytest - -topology_only = False - def pytest_addoption(parser): """ @@ -16,20 +17,72 @@ def pytest_addoption(parser): only run the setup_module() to setup the topology without running any tests. """ parser.addoption( + "--gdb-breakpoints", + metavar="SYMBOL[,SYMBOL...]", + help="Comma-separated list of functions to set gdb breakpoints on", + ) + + parser.addoption( + "--gdb-daemons", + metavar="DAEMON[,DAEMON...]", + help="Comma-separated list of daemons to spawn gdb on, or 'all'", + ) + + parser.addoption( + "--gdb-routers", + metavar="ROUTER[,ROUTER...]", + help="Comma-separated list of routers to spawn gdb on, or 'all'", + ) + + parser.addoption( + "--mininet-on-error", + action="store_true", + help="Mininet cli on test failure", + ) + + parser.addoption( + "--pause-after", + action="store_true", + help="Pause after each test", + ) + + parser.addoption( + "--shell", + metavar="ROUTER[,ROUTER...]", + help="Comma-separated list of routers to spawn shell on, or 'all'", + ) + + parser.addoption( + "--shell-on-error", + action="store_true", + help="Spawn shell on all routers on test failure", + ) + + parser.addoption( "--topology-only", action="store_true", help="Only set up this topology, don't run tests", ) + parser.addoption( + "--vtysh", + metavar="ROUTER[,ROUTER...]", + help="Comma-separated list of routers to spawn vtysh on, or 'all'", + ) + + parser.addoption( + "--vtysh-on-error", + action="store_true", + help="Spawn vtysh on all routers on test failure", + ) + def pytest_runtest_call(): """ This function must be run after setup_module(), it does standarized post setup routines. It is only being used for the 'topology-only' option. """ - global topology_only - - if topology_only: + if topotest_extra_config["topology_only"]: tgen = get_topogen() if tgen is not None: # Allow user to play with the setup. @@ -42,6 +95,8 @@ def pytest_assertrepr_compare(op, left, right): """ Show proper assertion error message for json_cmp results. """ + del op + json_result = left if not isinstance(json_result, json_cmp_result): json_result = right @@ -52,43 +107,105 @@ def pytest_assertrepr_compare(op, left, right): def pytest_configure(config): - "Assert that the environment is correctly configured." - - global topology_only + """ + Assert that the environment is correctly configured, and get extra config. + """ if not diagnose_env(): - pytest.exit("enviroment has errors, please read the logs") + pytest.exit("environment has errors, please read the logs") + + gdb_routers = config.getoption("--gdb-routers") + gdb_routers = gdb_routers.split(",") if gdb_routers else [] + topotest_extra_config["gdb_routers"] = gdb_routers + + gdb_daemons = config.getoption("--gdb-daemons") + gdb_daemons = gdb_daemons.split(",") if gdb_daemons else [] + topotest_extra_config["gdb_daemons"] = gdb_daemons + + gdb_breakpoints = config.getoption("--gdb-breakpoints") + gdb_breakpoints = gdb_breakpoints.split(",") if gdb_breakpoints else [] + topotest_extra_config["gdb_breakpoints"] = gdb_breakpoints + + mincli_on_error = config.getoption("--mininet-on-error") + topotest_extra_config["mininet_on_error"] = mincli_on_error - if config.getoption("--topology-only"): - topology_only = True + shell = config.getoption("--shell") + topotest_extra_config["shell"] = shell.split(",") if shell else [] + + pause_after = config.getoption("--pause-after") + + shell_on_error = config.getoption("--shell-on-error") + topotest_extra_config["shell_on_error"] = shell_on_error + + vtysh = config.getoption("--vtysh") + topotest_extra_config["vtysh"] = vtysh.split(",") if vtysh else [] + + vtysh_on_error = config.getoption("--vtysh-on-error") + topotest_extra_config["vtysh_on_error"] = vtysh_on_error + + topotest_extra_config["pause_after"] = ( + pause_after or shell or vtysh + ) + + topotest_extra_config["topology_only"] = config.getoption("--topology-only") def pytest_runtest_makereport(item, call): "Log all assert messages to default logger with error level" - # Nothing happened - if call.excinfo is None: - return - parent = item.parent - modname = parent.module.__name__ + # Nothing happened + if call.when == "call": + pause = topotest_extra_config["pause_after"] + else: + pause = False - # Treat skips as non errors - if call.excinfo.typename != "AssertionError": - logger.info( - 'assert skipped at "{}/{}": {}'.format( - modname, item.name, call.excinfo.value + if call.excinfo is None: + error = False + else: + parent = item.parent + modname = parent.module.__name__ + + # Treat skips as non errors, don't pause after + if call.excinfo.typename != "AssertionError": + pause = False + error = False + logger.info( + 'assert skipped at "{}/{}": {}'.format( + modname, item.name, call.excinfo.value + ) + ) + else: + error = True + # Handle assert failures + parent._previousfailed = item # pylint: disable=W0212 + logger.error( + 'assert failed at "{}/{}": {}'.format(modname, item.name, call.excinfo.value) ) - ) - return - - # Handle assert failures - parent._previousfailed = item - logger.error( - 'assert failed at "{}/{}": {}'.format(modname, item.name, call.excinfo.value) - ) - # (topogen) Set topology error to avoid advancing in the test. - tgen = get_topogen() - if tgen is not None: - # This will cause topogen to report error on `routers_have_failure`. - tgen.set_error("{}/{}".format(modname, item.name)) + # (topogen) Set topology error to avoid advancing in the test. + tgen = get_topogen() + if tgen is not None: + # This will cause topogen to report error on `routers_have_failure`. + tgen.set_error("{}/{}".format(modname, item.name)) + + + if error and topotest_extra_config["shell_on_error"]: + for router in tgen.routers(): + pause = True + tgen.net[router].runInWindow(os.getenv("SHELL", "bash")) + + if error and topotest_extra_config["vtysh_on_error"]: + for router in tgen.routers(): + pause = True + tgen.net[router].runInWindow("vtysh") + + if error and topotest_extra_config["mininet_on_error"]: + tgen.mininet_cli() + + if pause: + try: + user = raw_input('Testing paused, "pdb" to debug, "Enter" to continue: ') + except NameError: + user = input('Testing paused, "pdb" to debug, "Enter" to continue: ') + if user.strip() == "pdb": + pdb.set_trace() diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py index 6ab78c385e..ae904ba69e 100644 --- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py @@ -40,6 +40,8 @@ sys.path.append(os.path.join(CWD, "../")) from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger +from lib.topotest import iproute2_is_vrf_capable +from lib.common_config import required_linux_kernel_version from mininet.topo import Topo @@ -193,18 +195,21 @@ def test_isis_route_installation(): def test_isis_linux_route_installation(): - - dist = platform.dist() - - if dist[1] == "16.04": - pytest.skip("Kernel not supported for vrf") - "Check whether all expected routes are present and installed in the OS" tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + logger.info("Checking routers for installed ISIS vrf routes in OS") # Check for routes in `ip route show vrf {}-cust1` for rname, router in tgen.routers().items(): @@ -236,18 +241,21 @@ def test_isis_route6_installation(): def test_isis_linux_route6_installation(): - - dist = platform.dist() - - if dist[1] == "16.04": - pytest.skip("Kernel not supported for vrf") - "Check whether all expected routes are present and installed in the OS" tgen = get_topogen() # Don't run this test if we have any failure. if tgen.routers_have_failure(): pytest.skip(tgen.errors) + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + # iproute2 needs to support VRFs for this suite to run. + if not iproute2_is_vrf_capable(): + pytest.skip("Installed iproute2 version does not support VRFs") + logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS") # Check for routes in `ip -6 route show vrf {}-cust1` for rname, router in tgen.routers().items(): diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 55b11dab3c..83ee866636 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -43,6 +43,7 @@ from lib.common_config import ( run_frr_cmd, FRRCFG_FILE, retry, + get_ipv6_linklocal_address ) LOGDIR = "/tmp/topotests/" @@ -446,7 +447,7 @@ def __create_bgp_unicast_neighbor( cmd = "redistribute {}".format(redistribute["redist_type"]) redist_attr = redistribute.setdefault("attribute", None) if redist_attr: - if isinstance(redist_attr, dict): + if type(redist_attr) is dict: for key, value in redist_attr.items(): cmd = "{} {} {}".format(cmd, key, value) else: @@ -528,7 +529,7 @@ def __create_l2vpn_evpn_address_family( if advertise_data: for address_type, unicast_type in advertise_data.items(): - if isinstance(unicast_type, dict): + if type(unicast_type) is dict: for key, value in unicast_type.items(): cmd = "advertise {} {}".format(address_type, key) @@ -555,7 +556,7 @@ def __create_l2vpn_evpn_address_family( "ipv4" ].split("/")[0] - if isinstance(action, dict): + if type(action) is dict: next_hop_self = action.setdefault("next_hop_self", None) route_maps = action.setdefault("route_maps", {}) @@ -977,10 +978,6 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict): router_list[router].run(cmd) except Exception as e: - # handle any exception - logger.error("Error %s occured. Arguments %s.", e.message, e.args) - - # Traceback errormsg = traceback.format_exc() logger.error(errormsg) return errormsg @@ -1085,10 +1082,10 @@ def verify_bgp_convergence(tgen, topo, dut=None): logger.debug("Entering lib API: verify_bgp_convergence()") for router, rnode in tgen.routers().items(): - if "bgp" not in topo["routers"][router]: + if dut is not None and dut != router: continue - if dut is not None and dut != router: + if "bgp" not in topo["routers"][router]: continue logger.info("Verifying BGP Convergence on router %s:", router) @@ -1114,59 +1111,7 @@ def verify_bgp_convergence(tgen, topo, dut=None): # To find neighbor ip type bgp_addr_type = bgp_data["address_family"] - if "l2vpn" in bgp_addr_type: - total_evpn_peer = 0 - - if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]: - continue - - bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"] - total_evpn_peer += len(bgp_neighbors) - - no_of_evpn_peer = 0 - for bgp_neighbor, peer_data in bgp_neighbors.items(): - for _addr_type, dest_link_dict in peer_data.items(): - data = topo["routers"][bgp_neighbor]["links"] - for dest_link in dest_link_dict.keys(): - if dest_link in data: - peer_details = peer_data[_addr_type][dest_link] - - neighbor_ip = data[dest_link][_addr_type].split("/")[0] - nh_state = None - - if ( - "ipv4Unicast" in show_bgp_json[vrf] - or "ipv6Unicast" in show_bgp_json[vrf] - ): - errormsg = ( - "[DUT: %s] VRF: %s, " - "ipv4Unicast/ipv6Unicast" - " address-family present" - " under l2vpn" % (router, vrf) - ) - return errormsg - - l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][ - "peers" - ] - nh_state = l2VpnEvpn_data[neighbor_ip]["state"] - - if nh_state == "Established": - no_of_evpn_peer += 1 - - if no_of_evpn_peer == total_evpn_peer: - logger.info( - "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers", - router, - vrf, - ) - else: - errormsg = ( - "[DUT: %s] VRF: %s, BGP is not converged " - "for evpn peers" % (router, vrf) - ) - return errormsg - else: + if "ipv4" in bgp_addr_type or "ipv6" in bgp_addr_type: for addr_type in bgp_addr_type.keys(): if not check_address_types(addr_type): continue @@ -1216,32 +1161,102 @@ def verify_bgp_convergence(tgen, topo, dut=None): nh_state = None if addr_type == "ipv4": - ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][ - "peers" - ] - nh_state = ipv4_data[neighbor_ip]["state"] + if "ipv4Unicast" in show_bgp_json[vrf]: + ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][ + "peers" + ] + nh_state = ipv4_data[neighbor_ip]["state"] else: - ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][ - "peers" - ] - nh_state = ipv6_data[neighbor_ip]["state"] - + if "ipv6Unicast" in show_bgp_json[vrf]: + ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][ + "peers" + ] + nh_state = ipv6_data[neighbor_ip]["state"] if nh_state == "Established": no_of_peer += 1 - if no_of_peer == total_peer: - logger.info( - "[DUT: %s] VRF: %s, BGP is Converged for %s address-family", - router, - vrf, - addr_type, - ) + if "l2vpn" in bgp_addr_type: + if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]: + if no_of_peer == total_peer: + logger.info( + "[DUT: %s] VRF: %s, BGP is Converged for %s address-family", + router, + vrf, + addr_type, + ) + else: + errormsg = ( + "[DUT: %s] VRF: %s, BGP is not converged for %s address-family" + % (router, vrf, addr_type) + ) + return errormsg else: - errormsg = ( - "[DUT: %s] VRF: %s, BGP is not converged for %s address-family" - % (router, vrf, addr_type) - ) - return errormsg + if no_of_peer == total_peer: + logger.info( + "[DUT: %s] VRF: %s, BGP is Converged for %s address-family", + router, + vrf, + addr_type, + ) + else: + errormsg = ( + "[DUT: %s] VRF: %s, BGP is not converged for %s address-family" + % (router, vrf, addr_type) + ) + return errormsg + + if "l2vpn" in bgp_addr_type: + total_evpn_peer = 0 + + if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]: + continue + + bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"] + total_evpn_peer += len(bgp_neighbors) + + no_of_evpn_peer = 0 + for bgp_neighbor, peer_data in bgp_neighbors.items(): + for _addr_type, dest_link_dict in peer_data.items(): + data = topo["routers"][bgp_neighbor]["links"] + for dest_link in dest_link_dict.keys(): + if dest_link in data: + peer_details = peer_data[_addr_type][dest_link] + + neighbor_ip = data[dest_link][_addr_type].split("/")[0] + nh_state = None + + if ( + "ipv4Unicast" in show_bgp_json[vrf] + or "ipv6Unicast" in show_bgp_json[vrf] + ): + errormsg = ( + "[DUT: %s] VRF: %s, " + "ipv4Unicast/ipv6Unicast" + " address-family present" + " under l2vpn" % (router, vrf) + ) + return errormsg + + l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][ + "peers" + ] + nh_state = l2VpnEvpn_data[neighbor_ip]["state"] + + if nh_state == "Established": + no_of_evpn_peer += 1 + + if no_of_evpn_peer == total_evpn_peer: + logger.info( + "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers", + router, + vrf, + ) + else: + errormsg = ( + "[DUT: %s] VRF: %s, BGP is not converged " + "for evpn peers" % (router, vrf) + ) + return errormsg logger.debug("Exiting API: verify_bgp_convergence()") return True @@ -1400,10 +1415,6 @@ def modify_as_number(tgen, topo, input_dict): create_router_bgp(tgen, new_topo) except Exception as e: - # handle any exception - logger.error("Error %s occured. Arguments %s.", e.message, e.args) - - # Traceback errormsg = traceback.format_exc() logger.error(errormsg) return errormsg @@ -1571,7 +1582,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None): return True -def clear_bgp(tgen, addr_type, router, vrf=None): +def clear_bgp(tgen, addr_type, router, vrf=None, neighbor=None): """ This API is to clear bgp neighborship by running clear ip bgp */clear bgp ipv6 * command, @@ -1582,6 +1593,7 @@ def clear_bgp(tgen, addr_type, router, vrf=None): * `addr_type`: ip type ipv4/ipv6 * `router`: device under test * `vrf`: vrf name + * `neighbor`: Neighbor for which bgp needs to be cleared Usage ----- @@ -1605,12 +1617,16 @@ def clear_bgp(tgen, addr_type, router, vrf=None): if vrf: for _vrf in vrf: run_frr_cmd(rnode, "clear ip bgp vrf {} *".format(_vrf)) + elif neighbor: + run_frr_cmd(rnode, "clear bgp ipv4 {}".format(neighbor)) else: run_frr_cmd(rnode, "clear ip bgp *") elif addr_type == "ipv6": if vrf: for _vrf in vrf: run_frr_cmd(rnode, "clear bgp vrf {} ipv6 *".format(_vrf)) + elif neighbor: + run_frr_cmd(rnode, "clear bgp ipv6 {}".format(neighbor)) else: run_frr_cmd(rnode, "clear bgp ipv6 *") else: @@ -2621,7 +2637,7 @@ def verify_bgp_rib( found_routes.append(st_rt) if next_hop and multi_nh and st_found: - if not isinstance(next_hop, list): + if type(next_hop) is not list: next_hop = [next_hop] list1 = next_hop @@ -2661,7 +2677,7 @@ def verify_bgp_rib( nh_found = True elif next_hop and multi_nh is None: - if not isinstance(next_hop, list): + if type(next_hop) is not list: next_hop = [next_hop] list1 = next_hop found_hops = [ @@ -4092,7 +4108,7 @@ def verify_attributes_for_evpn_routes( errormsg = ( "[DUT: %s] RD: %s, Route : %s " "is not present in cli json " - "output " % (dut, route) + "output " % (dut, _rd, route) ) return errormsg @@ -4170,7 +4186,7 @@ def verify_evpn_routes( return errormsg for key, route_data_json in evpn_value_json.items(): - if isinstance(route_data_json, dict): + if type(route_data_json) is dict: rd_keys += 1 if prefix not in route_data_json: missing_routes[key] = prefix @@ -4184,7 +4200,7 @@ def verify_evpn_routes( return errormsg for key, route_data_json in evpn_value_json.items(): - if isinstance(route_data_json, dict): + if type(route_data_json) is dict: if prefix not in route_data_json: continue diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 9174389bea..2224b4f3a3 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -72,6 +72,59 @@ config.read(PYTESTINI_PATH) config_section = "topogen" +# Debug logs for daemons +DEBUG_LOGS = { + "pimd": [ + 'debug msdp events', + 'debug msdp packets', + 'debug igmp events', + 'debug igmp trace', + 'debug mroute', + 'debug mroute detail', + 'debug pim events', + 'debug pim packets', + 'debug pim trace', + 'debug pim zebra', + 'debug pim bsm', + 'debug pim packets joins', + 'debug pim packets register', + 'debug pim nht' + ], + "bgpd": [ + 'debug bgp neighbor-events', + 'debug bgp updates', + 'debug bgp zebra', + 'debug bgp nht', + 'debug bgp neighbor-events', + 'debug bgp graceful-restart', + 'debug bgp update-groups', + 'debug bgp vpn leak-from-vrf', + 'debug bgp vpn leak-to-vrf', + 'debug bgp zebr', + 'debug bgp updates', + 'debug bgp nht', + 'debug bgp neighbor-events', + 'debug vrf' + ], + "zebra": [ + 'debug zebra events', + 'debug zebra rib', + 'debug zebra vxlan', + 'debug zebra nht' + ], + "ospf": [ + 'debug ospf event', + 'debug ospf ism', + 'debug ospf lsa', + 'debug ospf nsm', + 'debug ospf nssa', + 'debug ospf packet all', + 'debug ospf sr', + 'debug ospf te', + 'debug ospf zebra', + ] +} + if config.has_option("topogen", "verbosity"): loglevel = config.get("topogen", "verbosity") loglevel = loglevel.upper() @@ -249,6 +302,7 @@ def create_common_configuration( config_map = OrderedDict( { "general_config": "! FRR General Config\n", + "debug_log_config": "! Debug log Config\n", "interface_config": "! Interfaces Config\n", "static_route": "! Static Route Config\n", "prefix_list": "! Prefix List Config\n", @@ -1052,6 +1106,92 @@ def tcpdump_capture_stop(tgen, router): return True +def create_debug_log_config(tgen, input_dict, build=False): + """ + Enable/disable debug logs for any protocol with defined debug + options and logs would be saved to created log file + + Parameters + ---------- + * `tgen` : Topogen object + * `input_dict` : details to enable debug logs for protocols + * `build` : Only for initial setup phase this is set as True. + + + Usage: + ------ + input_dict = { + "r2": { + "debug":{ + "log_file" : "debug.log", + "enable": ["pimd", "zebra"], + "disable": { + "bgpd":[ + 'debug bgp neighbor-events', + 'debug bgp updates', + 'debug bgp zebra', + ] + } + } + } + } + + result = create_debug_log_config(tgen, input_dict) + + Returns + ------- + True or False + """ + + result = False + try: + for router in input_dict.keys(): + debug_config = [] + if "debug" in input_dict[router]: + debug_dict = input_dict[router]["debug"] + + disable_logs = debug_dict.setdefault("disable", None) + enable_logs = debug_dict.setdefault("enable", None) + log_file = debug_dict.setdefault("log_file", None) + + if log_file: + _log_file = os.path.join(LOGDIR, tgen.modname, + log_file) + debug_config.append("log file {} \n".\ + format(_log_file)) + + if type(enable_logs) is list: + for daemon in enable_logs: + for debug_log in DEBUG_LOGS[daemon]: + debug_config.append("{}".format(debug_log)) + elif type(enable_logs) is dict: + for daemon, debug_logs in enable_logs.items(): + for debug_log in debug_logs: + debug_config.append("{}".format(debug_log)) + + if type(disable_logs) is list: + for daemon in disable_logs: + for debug_log in DEBUG_LOGS[daemon]: + debug_config.append("no {}".format(debug_log)) + elif type(disable_logs) is dict: + for daemon, debug_logs in disable_logs.items(): + for debug_log in debug_logs: + debug_config.append("no {}".format(debug_log)) + + result = create_common_configuration(tgen, router, + debug_config, + "debug_log_config", + build=build) + except InvalidCLIError: + # Traceback + errormsg = traceback.format_exc() + logger.error(errormsg) + return errormsg + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return result + + ############################################# # Common APIs, will be used by all protocols ############################################# @@ -1373,13 +1513,13 @@ def generate_ips(network, no_of_ips): if start_ip == "0.0.0.0" and mask == 0 and no_of_ips == 1: ipaddress_list.append("{}/{}".format(start_ip, mask)) return ipaddress_list - start_ip = ipaddress.IPv4Address(unicode(start_ip)) + start_ip = ipaddress.IPv4Address(frr_unicode(start_ip)) step = 2 ** (32 - mask) elif addr_type == "ipv6": if start_ip == "0::0" and mask == 0 and no_of_ips == 1: ipaddress_list.append("{}/{}".format(start_ip, mask)) return ipaddress_list - start_ip = ipaddress.IPv6Address(unicode(start_ip)) + start_ip = ipaddress.IPv6Address(frr_unicode(start_ip)) step = 2 ** (128 - mask) else: return [] @@ -1480,10 +1620,6 @@ def interface_status(tgen, topo, input_dict): load_config_to_router(tgen, router) except Exception as e: - # handle any exception - logger.error("Error %s occured. Arguments %s.", e.message, e.args) - - # Traceback errormsg = traceback.format_exc() logger.error(errormsg) return errormsg @@ -2442,51 +2578,6 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False): interface_set_status(router_list[dut], intf_name, ifaceaction) -def stop_router(tgen, router): - """ - Router's current config would be saved to /tmp/topotest/<suite>/<router> - for each daemon and router and its daemons would be stopped. - - * `tgen` : topogen object - * `router`: Device under test - """ - - router_list = tgen.routers() - - # Saving router config to /etc/frr, which will be loaded to router - # when it starts - router_list[router].vtysh_cmd("write memory") - - # Stop router - router_list[router].stop() - - -def start_router(tgen, router): - """ - Router will be started and config would be loaded from - /tmp/topotest/<suite>/<router> for each daemon - - * `tgen` : topogen object - * `router`: Device under test - """ - - logger.debug("Entering lib API: start_router") - - try: - router_list = tgen.routers() - - # Router and its daemons would be started and config would - # be loaded to router for each daemon from /etc/frr - router_list[router].start() - - except Exception as e: - errormsg = traceback.format_exc() - logger.error(errormsg) - return errormsg - - logger.debug("Exiting lib API: start_router()") - - def addKernelRoute( tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None ): @@ -3754,6 +3845,43 @@ def verify_bgp_community(tgen, addr_type, router, network, input_dict=None): return True +def get_ipv6_linklocal_address(topo, node, intf): + """ + API to get the link local ipv6 address of a perticular interface + + Parameters + ---------- + * `node`: node on which link local ip to be fetched. + * `intf` : interface for which link local ip needs to be returned. + * `topo` : base topo + + Usage + ----- + result = get_ipv6_linklocal_address(topo, 'r1', 'r2') + + Returns link local ip of interface between r1 and r2. + + Returns + ------- + 1) link local ipv6 address from the interface + 2) errormsg - when link local ip not found + """ + tgen = get_topogen() + ext_nh = tgen.net[node].get_ipv6_linklocal() + req_nh = topo[node]['links'][intf]['interface'] + llip = None + for llips in ext_nh: + if llips[0] == req_nh: + llip = llips[1] + logger.info("Link local ip found = %s", llip) + return llip + + errormsg = "Failed: Link local ip not found on router {}, "\ + "interface {}".format(node, intf) + + return errormsg + + def verify_create_community_list(tgen, input_dict): """ API is to verify if large community list is created for any given DUT in diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 79e4d97448..9f642411b5 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -344,10 +344,9 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= for lnk in input_dict[router]["links"].keys(): if "ospf" not in input_dict[router]["links"][lnk]: logger.debug( - "Router %s: ospf configs is not present in" - "input_dict, passed input_dict", - router, - input_dict, + "Router %s: ospf config is not present in" + "input_dict", + router ) continue ospf_data = input_dict[router]["links"][lnk]["ospf"] @@ -724,7 +723,7 @@ def verify_ospf6_neighbor(tgen, topo): nh_state = neighbor["state"] break else: - return "[DUT: {}] OSPF6 peer {} missing".format(router, data_rid) + return "[DUT: {}] OSPF6 peer {} missing".format(router, ospf_nbr_rid) if nh_state == "Full": no_of_peer += 1 diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 5cc1a6981d..104b215078 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -50,7 +50,9 @@ from mininet.node import Node, OVSSwitch, Host from mininet.log import setLogLevel, info from mininet.cli import CLI from mininet.link import Intf +from mininet.term import makeTerm +g_extra_config = {} def gdb_core(obj, daemon, corefiles): gdbcmds = """ @@ -516,6 +518,44 @@ def normalize_text(text): return text +def is_linux(): + """ + Parses unix name output to check if running on GNU/Linux. + + Returns True if running on Linux, returns False otherwise. + """ + + if os.uname()[0] == "Linux": + return True + return False + + +def iproute2_is_vrf_capable(): + """ + Checks if the iproute2 version installed on the system is capable of + handling VRFs by interpreting the output of the 'ip' utility found in PATH. + + Returns True if capability can be detected, returns False otherwise. + """ + + if is_linux(): + try: + subp = subprocess.Popen( + ["ip", "route", "show", "vrf"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + encoding="utf-8" + ) + iproute2_err = subp.communicate()[1].splitlines()[0].split()[0] + + if iproute2_err != "Error:": + return True + except Exception: + pass + return False + + def module_present_linux(module, load): """ Returns whether `module` is present. @@ -1303,6 +1343,37 @@ class Router(Node): logger.info("No daemon {} known".format(daemon)) # print "Daemons after:", self.daemons + # Run a command in a new window (gnome-terminal, screen, tmux, xterm) + def runInWindow(self, cmd, title=None): + topo_terminal = os.getenv("FRR_TOPO_TERMINAL") + if topo_terminal or ( + "TMUX" not in os.environ and "STY" not in os.environ + ): + term = topo_terminal if topo_terminal else "xterm" + makeTerm( + self, + title=title if title else cmd, + term=term, + cmd=cmd) + else: + nscmd = "sudo nsenter -m -n -t {} {}".format(self.pid, cmd) + if "TMUX" in os.environ: + self.cmd("tmux select-layout main-horizontal") + wcmd = "tmux split-window -h" + cmd = "{} {}".format(wcmd, nscmd) + elif "STY" in os.environ: + if os.path.exists( + "/run/screen/S-{}/{}".format( + os.environ['USER'], os.environ['STY'] + ) + ): + wcmd = "screen" + else: + wcmd = "sudo -u {} screen".format(os.environ["SUDO_USER"]) + cmd = "{} {}".format(wcmd, nscmd) + self.cmd(cmd) + + def startRouter(self, tgen=None): # Disable integrated-vtysh-config self.cmd( @@ -1355,6 +1426,14 @@ class Router(Node): return "LDP/MPLS Tests need mpls kernel modules" self.cmd("echo 100000 > /proc/sys/net/mpls/platform_labels") + shell_routers = g_extra_config["shell"] + if "all" in shell_routers or self.name in shell_routers: + self.runInWindow(os.getenv("SHELL", "bash")) + + vtysh_routers = g_extra_config["vtysh"] + if "all" in vtysh_routers or self.name in vtysh_routers: + self.runInWindow("vtysh") + if self.daemons["eigrpd"] == 1: eigrpd_path = os.path.join(self.daemondir, "eigrpd") if not os.path.isfile(eigrpd_path): @@ -1381,6 +1460,10 @@ class Router(Node): def startRouterDaemons(self, daemons=None): "Starts all FRR daemons for this router." + gdb_breakpoints = g_extra_config["gdb_breakpoints"] + gdb_daemons = g_extra_config["gdb_daemons"] + gdb_routers = g_extra_config["gdb_routers"] + bundle_data = "" if os.path.exists("/etc/frr/support_bundle_commands.conf"): @@ -1410,7 +1493,7 @@ class Router(Node): # If `daemons` was specified then some upper API called us with # specific daemons, otherwise just use our own configuration. daemons_list = [] - if daemons != None: + if daemons is not None: daemons_list = daemons else: # Append all daemons configured. @@ -1418,47 +1501,67 @@ class Router(Node): if self.daemons[daemon] == 1: daemons_list.append(daemon) - # Start Zebra first - if "zebra" in daemons_list: - zebra_path = os.path.join(self.daemondir, "zebra") - zebra_option = self.daemons_options["zebra"] - self.cmd( - "ASAN_OPTIONS=log_path=zebra.asan {0} {1} --log file:zebra.log --log-level debug -s 90000000 -d > zebra.out 2> zebra.err".format( - zebra_path, zebra_option + def start_daemon(daemon, extra_opts=None): + daemon_opts = self.daemons_options.get(daemon, "") + rediropt = " > {0}.out 2> {0}.err".format(daemon) + if daemon == "snmpd": + binary = "/usr/sbin/snmpd" + cmdenv = "" + cmdopt = "{} -C -c /etc/frr/snmpd.conf -p ".format( + daemon_opts + ) + "/var/run/{}/snmpd.pid -x /etc/frr/agentx".format(self.routertype) + else: + binary = os.path.join(self.daemondir, daemon) + cmdenv = "ASAN_OPTIONS=log_path={0}.asan".format(daemon) + cmdopt = "{} --log file:{}.log --log-level debug".format( + daemon_opts, daemon ) - ) - logger.debug("{}: {} zebra started".format(self, self.routertype)) + if extra_opts: + cmdopt += " " + extra_opts + + if ( + (gdb_routers or gdb_daemons) + and (not gdb_routers + or self.name in gdb_routers + or "all" in gdb_routers) + and (not gdb_daemons + or daemon in gdb_daemons + or "all" in gdb_daemons) + ): + if daemon == "snmpd": + cmdopt += " -f " + + cmdopt += rediropt + gdbcmd = "sudo -E gdb " + binary + if gdb_breakpoints: + gdbcmd += " -ex 'set breakpoint pending on'" + for bp in gdb_breakpoints: + gdbcmd += " -ex 'b {}'".format(bp) + gdbcmd += " -ex 'run {}'".format(cmdopt) + + self.runInWindow(gdbcmd, daemon) + else: + if daemon != "snmpd": + cmdopt += " -d " + cmdopt += rediropt + self.cmd(" ".join([cmdenv, binary, cmdopt])) + logger.info("{}: {} {} started".format(self, self.routertype, daemon)) + - # Remove `zebra` so we don't attempt to start it again. + # Start Zebra first + if "zebra" in daemons_list: + start_daemon("zebra", "-s 90000000") while "zebra" in daemons_list: daemons_list.remove("zebra") # Start staticd next if required if "staticd" in daemons_list: - staticd_path = os.path.join(self.daemondir, "staticd") - staticd_option = self.daemons_options["staticd"] - self.cmd( - "ASAN_OPTIONS=log_path=staticd.asan {0} {1} --log file:staticd.log --log-level debug -d > staticd.out 2> staticd.err".format( - staticd_path, staticd_option - ) - ) - logger.debug("{}: {} staticd started".format(self, self.routertype)) - - # Remove `staticd` so we don't attempt to start it again. + start_daemon("staticd") while "staticd" in daemons_list: daemons_list.remove("staticd") if "snmpd" in daemons_list: - snmpd_path = "/usr/sbin/snmpd" - snmpd_option = self.daemons_options["snmpd"] - self.cmd( - "{0} {1} -C -c /etc/frr/snmpd.conf -p /var/run/{2}/snmpd.pid -x /etc/frr/agentx > snmpd.out 2> snmpd.err".format( - snmpd_path, snmpd_option, self.routertype - ) - ) - logger.info("{}: {} snmpd started".format(self, self.routertype)) - - # Remove `snmpd` so we don't attempt to start it again. + start_daemon("snmpd") while "snmpd" in daemons_list: daemons_list.remove("snmpd") @@ -1470,17 +1573,9 @@ class Router(Node): # Now start all the other daemons for daemon in daemons_list: - # Skip disabled daemons and zebra if self.daemons[daemon] == 0: continue - - daemon_path = os.path.join(self.daemondir, daemon) - self.cmd( - "ASAN_OPTIONS=log_path={2}.asan {0} {1} --log file:{2}.log --log-level debug -d > {2}.out 2> {2}.err".format( - daemon_path, self.daemons_options.get(daemon, ""), daemon - ) - ) - logger.debug("{}: {} {} started".format(self, self.routertype, daemon)) + start_daemon(daemon) # Check if daemons are running. rundaemons = self.cmd("ls -1 /var/run/%s/*.pid" % self.routertype) diff --git a/tests/topotests/ospf-te-topo1/__init__.py b/tests/topotests/ospf-te-topo1/__init__.py new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/__init__.py diff --git a/tests/topotests/ospf-te-topo1/r1/ospfd.conf b/tests/topotests/ospf-te-topo1/r1/ospfd.conf new file mode 100644 index 0000000000..312dd2697e --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r1/ospfd.conf @@ -0,0 +1,23 @@ +! +interface lo + ip ospf area 0.0.0.0 +! +interface r1-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +interface r1-eth1 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.255.1 + capability opaque + mpls-te on + mpls-te router-address 10.0.255.1 +! + diff --git a/tests/topotests/ospf-te-topo1/r1/zebra.conf b/tests/topotests/ospf-te-topo1/r1/zebra.conf new file mode 100644 index 0000000000..7c5dc3ffe0 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r1/zebra.conf @@ -0,0 +1,21 @@ +! +interface lo + ip address 10.0.255.1/32 +! +interface r1-eth0 + ip address 10.0.0.1/24 + link-params + metric 20 + delay 10000 + ava-bw 1.25e+08 + enable + exit-link-params +! +interface r1-eth1 + ip address 10.0.1.1/24 + link-params + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/ospf-te-topo1/r2/ospfd.conf b/tests/topotests/ospf-te-topo1/r2/ospfd.conf new file mode 100644 index 0000000000..e9c3f65bc2 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r2/ospfd.conf @@ -0,0 +1,34 @@ +! +interface lo + ip ospf area 0.0.0.0 +! +interface r2-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +interface r2-eth1 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +interface r2-eth2 + ip ospf network point-to-point + ip ospf area 0.0.0.0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +interface r2-eth3 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +router ospf + ospf router-id 10.0.255.2 + capability opaque + mpls-te on + mpls-te router-address 10.0.255.2 +! diff --git a/tests/topotests/ospf-te-topo1/r2/zebra.conf b/tests/topotests/ospf-te-topo1/r2/zebra.conf new file mode 100644 index 0000000000..69e10191f3 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r2/zebra.conf @@ -0,0 +1,33 @@ +! +interface lo + ip address 10.0.255.2/32 +! +interface r2-eth0 + ip address 10.0.0.2/24 + link-params + enable + exit-link-params +! +interface r2-eth1 + ip address 10.0.1.2/24 + link-params + enable + exit-link-params +! +interface r2-eth2 + ip address 10.0.3.2/24 + link-params + enable + exit-link-params +! +interface r2-eth3 + ip address 10.0.4.2/24 + link-params + metric 30 + delay 25000 + use-bw 1.25e+8 + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/ospf-te-topo1/r3/ospfd.conf b/tests/topotests/ospf-te-topo1/r3/ospfd.conf new file mode 100644 index 0000000000..caa5f1e1eb --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r3/ospfd.conf @@ -0,0 +1,24 @@ +! +interface lo + ip ospf area 0.0.0.0 +! +interface r3-eth0 + ip ospf network point-to-point + ip ospf area 0.0.0.0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +interface r3-eth1 + ip ospf network point-to-point + ip ospf area 0.0.0.0 + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +! +router ospf + ospf router-id 10.0.255.3 + capability opaque + mpls-te on + mpls-te router-address 10.0.255.3 + mpls-te inter-as as +! diff --git a/tests/topotests/ospf-te-topo1/r3/zebra.conf b/tests/topotests/ospf-te-topo1/r3/zebra.conf new file mode 100644 index 0000000000..4cf9077085 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r3/zebra.conf @@ -0,0 +1,22 @@ +! +interface lo + ip address 10.0.255.3/32 +! +interface r3-eth0 + ip address 10.0.3.1/24 + link-params + enable + admin-grp 0x20 + exit-link-params +! +interface r3-eth1 + ip address 10.0.5.1/24 + link-params + enable + metric 10 + delay 50000 + neighbor 10.0.255.5 as 65535 + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/ospf-te-topo1/r4/ospfd.conf b/tests/topotests/ospf-te-topo1/r4/ospfd.conf new file mode 100644 index 0000000000..e454673153 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r4/ospfd.conf @@ -0,0 +1,22 @@ +! +interface lo + ip ospf area 0.0.0.0 +! +interface r4-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 + ip ospf area 0.0.0.0 +! +! +router ospf + ospf router-id 10.0.255.4 + capability opaque + mpls-te on + mpls-te router-address 10.0.255.4 + segment-routing on + segment-routing local-block 5000 5999 + segment-routing global-block 10000 19999 + segment-routing node-msd 12 + segment-routing prefix 10.0.255.4/32 index 400 no-php-flag +! diff --git a/tests/topotests/ospf-te-topo1/r4/zebra.conf b/tests/topotests/ospf-te-topo1/r4/zebra.conf new file mode 100644 index 0000000000..18c003b230 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/r4/zebra.conf @@ -0,0 +1,12 @@ +! +interface lo + ip address 10.0.255.4/32 +! +interface r4-eth0 + ip address 10.0.4.1/24 + link-params + enable + exit-link-params +! +ip forwarding +! diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step1.json b/tests/topotests/ospf-te-topo1/reference/ted_step1.json new file mode 100644 index 0000000000..9624292ccd --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step1.json @@ -0,0 +1,577 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":5, + "edgesCount":9, + "subnetsCount":14, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard" + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard" + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + }, + { + "vertex-id":167837445, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.5", + "vertex-type":"Remote ASBR", + "asn":65535 + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + } + }, + { + "edge-id":167773441, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837445, + "metric":0, + "edge-attributes":{ + "te-metric":10, + "local-address":"10.0.5.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "remote-asn":65535, + "remote-as-address":"10.0.255.5", + "delay":50000 + } + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.5.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + }, + { + "subnet-id":"10.0.255.5\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.5", + "vertex-id":167837445, + "metric":10 + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step2.json b/tests/topotests/ospf-te-topo1/reference/ted_step2.json new file mode 100644 index 0000000000..623d1dc7e0 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step2.json @@ -0,0 +1,477 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":5, + "edgesCount":7, + "subnetsCount":12, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard" + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard" + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + }, + { + "vertex-id":167837445, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.5", + "vertex-type":"Remote ASBR", + "asn":65535 + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + } + }, + { + "edge-id":167773441, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837445, + "metric":0, + "edge-attributes":{ + "te-metric":10, + "local-address":"10.0.5.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "remote-asn":65535, + "remote-as-address":"10.0.255.5", + "delay":50000 + } + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.5.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + }, + { + "subnet-id":"10.0.255.5\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.5", + "vertex-id":167837445, + "metric":10 + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step3.json b/tests/topotests/ospf-te-topo1/reference/ted_step3.json new file mode 100644 index 0000000000..117011a43a --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step3.json @@ -0,0 +1,409 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":4, + "edgesCount":6, + "subnetsCount":10, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard" + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard" + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + } + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + } + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0 + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0 + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step4.json b/tests/topotests/ospf-te-topo1/reference/ted_step4.json new file mode 100644 index 0000000000..5c2dee1e4b --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step4.json @@ -0,0 +1,490 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":4, + "edgesCount":6, + "subnetsCount":10, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":4000, + "srgb-lower":20000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":15000 + } + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":8000, + "srgb-lower":16000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":2000, + "srlb-lower":5000, + "msd":16 + } + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":15001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":5005, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5004, + "flags":"0xe0", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0, + "segment-routing":{ + "pref-sid":10, + "algo":0, + "flags":"0x0" + } + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0, + "segment-routing":{ + "pref-sid":20, + "algo":0, + "flags":"0x50" + } + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step5.json b/tests/topotests/ospf-te-topo1/reference/ted_step5.json new file mode 100644 index 0000000000..47e747f3ca --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step5.json @@ -0,0 +1,614 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":4, + "edgesCount":8, + "subnetsCount":12, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":4000, + "srgb-lower":20000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":15000 + } + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":8000, + "srgb-lower":16000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":2000, + "srlb-lower":5000, + "msd":16 + } + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":15001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":15003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5007, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5006, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000, + "utilized-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":5005, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5004, + "flags":"0xe0", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0, + "segment-routing":{ + "pref-sid":10, + "algo":0, + "flags":"0x0" + } + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0, + "segment-routing":{ + "pref-sid":20, + "algo":0, + "flags":"0x50" + } + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step6.json b/tests/topotests/ospf-te-topo1/reference/ted_step6.json new file mode 100644 index 0000000000..74bd83fbdb --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step6.json @@ -0,0 +1,615 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":4, + "edgesCount":8, + "subnetsCount":12, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":4000, + "srgb-lower":20000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":15000 + } + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":8000, + "srgb-lower":16000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":2000, + "srlb-lower":5000, + "msd":16 + } + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + }, + { + "vertex-id":167837444, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.4", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":10000, + "srgb-lower":10000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":5000, + "msd":12 + } + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":15001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":15003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5007, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5006, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773185, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "local-vertex-id":167837444, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.4.1", + "remote-address":"10.0.4.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":20000, + "jitter":10000 + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167773186, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837444, + "metric":10, + "edge-attributes":{ + "te-metric":30, + "local-address":"10.0.4.2", + "remote-address":"10.0.4.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":25000 + }, + "segment-routing":[ + { + "adj-sid":5005, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5004, + "flags":"0xe0", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.4.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":10 + }, + { + "subnet-id":"10.0.4.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0, + "segment-routing":{ + "pref-sid":10, + "algo":0, + "flags":"0x0" + } + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0, + "segment-routing":{ + "pref-sid":20, + "algo":0, + "flags":"0x50" + } + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + }, + { + "subnet-id":"10.0.255.4\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.4", + "vertex-id":167837444, + "metric":0, + "segment-routing":{ + "pref-sid":400, + "algo":0, + "flags":"0x40" + } + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/reference/ted_step7.json b/tests/topotests/ospf-te-topo1/reference/ted_step7.json new file mode 100644 index 0000000000..1cea9f0455 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/reference/ted_step7.json @@ -0,0 +1,456 @@ +{ + "ted":{ + "name":"OSPF", + "key":1, + "verticesCount":3, + "edgesCount":6, + "subnetsCount":9, + "vertices":[ + { + "vertex-id":167837441, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.1", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":4000, + "srgb-lower":20000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":1000, + "srlb-lower":15000 + } + }, + { + "vertex-id":167837442, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.2", + "vertex-type":"Standard", + "segment-routing":{ + "srgb-size":8000, + "srgb-lower":16000, + "algorithms":[ + { + "0":"SPF" + } + ], + "srlb-size":2000, + "srlb-lower":5000, + "msd":16 + } + }, + { + "vertex-id":167837443, + "status":"Sync", + "origin":"OSPFv2", + "router-id":"10.0.255.3", + "vertex-type":"ASBR" + } + ], + "edges":[ + { + "edge-id":167772161, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":20, + "local-address":"10.0.0.1", + "remote-address":"10.0.0.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ], + "delay":10000, + "available-bandwidth":125000000.0 + }, + "segment-routing":[ + { + "adj-sid":15001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772162, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.0.2", + "remote-address":"10.0.0.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5001, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5000, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772417, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "local-vertex-id":167837441, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.1", + "remote-address":"10.0.1.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":15003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":15002, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772418, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837441, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.1.2", + "remote-address":"10.0.1.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5007, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5006, + "flags":"0xe0", + "weight":0 + } + ] + }, + { + "edge-id":167772929, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "local-vertex-id":167837443, + "remote-vertex-id":167837442, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "admin-group":32, + "local-address":"10.0.3.1", + "remote-address":"10.0.3.2", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + } + }, + { + "edge-id":167772930, + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "local-vertex-id":167837442, + "remote-vertex-id":167837443, + "metric":10, + "edge-attributes":{ + "te-metric":0, + "local-address":"10.0.3.2", + "remote-address":"10.0.3.1", + "max-link-bandwidth":176258176.0, + "max-resv-link-bandwidth":176258176.0, + "unreserved-bandwidth":[ + { + "class-type-0":176258176.0 + }, + { + "class-type-1":176258176.0 + }, + { + "class-type-2":176258176.0 + }, + { + "class-type-3":176258176.0 + }, + { + "class-type-4":176258176.0 + }, + { + "class-type-5":176258176.0 + }, + { + "class-type-6":176258176.0 + }, + { + "class-type-7":176258176.0 + } + ] + }, + "segment-routing":[ + { + "adj-sid":5003, + "flags":"0x60", + "weight":0 + }, + { + "adj-sid":5002, + "flags":"0xe0", + "weight":0 + } + ] + } + ], + "subnets":[ + { + "subnet-id":"10.0.0.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.0.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.1.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":10 + }, + { + "subnet-id":"10.0.1.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.3.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":10 + }, + { + "subnet-id":"10.0.3.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":10 + }, + { + "subnet-id":"10.0.255.1\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.1", + "vertex-id":167837441, + "metric":0, + "segment-routing":{ + "pref-sid":10, + "algo":0, + "flags":"0x0" + } + }, + { + "subnet-id":"10.0.255.2\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.2", + "vertex-id":167837442, + "metric":0, + "segment-routing":{ + "pref-sid":20, + "algo":0, + "flags":"0x50" + } + }, + { + "subnet-id":"10.0.255.3\/32", + "status":"Sync", + "origin":"OSPFv2", + "advertised-router":"10.0.255.3", + "vertex-id":167837443, + "metric":0 + } + ] + } +} diff --git a/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py b/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py new file mode 100644 index 0000000000..1d69f5d699 --- /dev/null +++ b/tests/topotests/ospf-te-topo1/test_ospf_te_topo1.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python + +# +# test_ospf_te_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by Orange +# Author: Olivier Dugeon <olivier.dugeon@orange.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_ospf_te_topo1.py: Test the FRR OSPF with Traffic Engineering. + + +------------+ + | | + | R1 | + | 10.0.225.1 | + | | + +------------+ + r1-eth0| |r1-eth1 + | | + 10.0.0.0/24| |10.0.1.0/24 + | | + r2-eth0| |r2-eth1 + +------------+ +------------+ + | | | | + | R2 |r2-eth2 r3-eth0| R3 | + | 10.0.255.2 +------------------+ 10.0.255.3 | + | | 10.0.3.0/24 | | + +------------+ +------+-----+ + r2-eth3| r3-eth1| + | | + 10.0.4.0/24| 10.0.5.0/24| + | | + r4-eth0| V + +------------+ ASBR 10.0.255.5 + | | + | R4 | + | 10.0.255.4 | + | | + +------------+ + +""" + +import os +import sys +import json +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# and Finally pytest +import pytest + +pytestmark = [pytest.mark.ospfd] + +class OspfTeTopo(Topo): + "Test topology builder" + + def build(self): + "Build function" + tgen = get_topogen(self) + + # Create 4 routers + for routern in range(1, 5): + tgen.add_router("r{}".format(routern)) + + # Interconect router 1 and 2 with 2 links + 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["r1"]) + switch.add_link(tgen.gears["r2"]) + + # Interconect router 3 and 2 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r2"]) + + # Interconect router 4 and 2 + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r2"]) + + # Interconnect router 3 with next AS + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + logger.info("\n\n---- Starting OSPF TE tests ----\n") + + tgen = Topogen(OspfTeTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(): + "Teardown the pytest environment" + + tgen = get_topogen() + tgen.stop_topology() + + logger.info("\n\n---- OSPF TE tests End ----\n") + + +def compare_ted_json_output(tgen, rname, fileref): + "Compare TED JSON output" + + logger.info('Comparing router "%s" TED output', rname) + + filename = "{}/reference/{}".format(CWD, fileref) + expected = json.loads(open(filename).read()) + command = "show ip ospf mpls-te database json" + + # Run test function until we get an result. Wait at most 60 seconds. + test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) + _, diff = topotest.run_and_expect(test_func, None, count=60, wait=2) + assertmsg = '"{}" TED JSON output mismatches the expected result'.format(rname) + assert diff is None, assertmsg + + +def setup_testcase(msg): + "Setup test case" + + logger.info(msg) + tgen = get_topogen() + + # Skip if previous fatal error condition is raised + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + return tgen + + +# Note that all routers must discover the same Network Topology, so the same TED. + +def test_step1(): + "Step1: Check initial topology" + + tgen = setup_testcase("Step1: test initial OSPF TE Data Base") + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step1.json") + + +def test_step2(): + "Step2: Shutdown interface between r1 and r2 and verify that \ + corresponding Edges are removed from the TED on all routers " + + tgen = setup_testcase("Step2: Shutdown interface between r1 & r2") + + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "interface r1-eth1" -c "shutdown"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "interface r2-eth1" -c "shutdown"' + ) + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step2.json") + + +def test_step3(): + "Step3: Disable Inter-AS on r3 and verify that corresponding Edge and \ + remote ASBR are removed from the TED on all routers" + + tgen = setup_testcase("Step3: Disable Inter-AS on r3") + + tgen.net["r3"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "no mpls-te inter-as"' + ) + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step3.json") + + +def test_step4(): + "Step4: Enable Segment Routing on r1 and r2 and verify that corresponding \ + Edges are updated with Adjacency SID and Subnets with Prefix SID in the \ + TED on all routers" + + tgen = setup_testcase("Step4: Enable Segment Routing on r1 & r2") + + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing on"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing global-block 20000 23999"' + ) + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 10.0.255.1/32 index 10"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing on"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing node-msd 16"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing local-block 5000 6999"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "router ospf" -c "segment-routing prefix 10.0.255.2/32 index 20 explicit-null"' + ) + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step4.json") + + +def test_step5(): + "Step5: Re-enable interface between r1 & r2 and verify that corresponding \ + Edges are added in the TED on all routers" + + tgen = setup_testcase("Step5: Re-enable interface between r1 & r2") + + tgen.net["r1"].cmd( + 'vtysh -c "conf t" -c "interface r1-eth1" -c "no shutdown"' + ) + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "interface r2-eth1" -c "no shutdown"' + ) + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step5.json") + + +def test_step6(): + "Step6: Set delay and jitter for interface r4-eth0 on r4, remove use-bw \ + for interface r2-eth3 on r2 and verify that corresponding Edges are \ + updated in the TED on all routers" + + tgen = setup_testcase("Step6: Modify link parameters on r2 & r4") + + tgen.net["r2"].cmd( + 'vtysh -c "conf t" -c "interface r2-eth3" -c "link-params" -c "no use-bw"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay 20000"' + ) + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "interface r4-eth0" -c "link-params" -c "delay-variation 10000"' + ) + + for rname in ["r1", "r2", "r3", "r4"]: + compare_ted_json_output(tgen, rname, "ted_step6.json") + + +def test_step7(): + "Step7: Disable OSPF on r4 and verify that corresponding Vertex, Edges and \ + Subnets are removed from the TED on all remaining routers" + + tgen = setup_testcase("Step7: Disable OSPF on r4") + + tgen.net["r4"].cmd( + 'vtysh -c "conf t" -c "no router ospf"' + ) + + for rname in ["r1", "r2", "r3"]: + compare_ted_json_output(tgen, rname, "ted_step7.json") + + +def test_memory_leak(): + "Run the memory leak test and report results." + + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf6-topo2/r1/ospf6d.conf b/tests/topotests/ospf6-topo2/r1/ospf6d.conf new file mode 100644 index 0000000000..c403fcd8dc --- /dev/null +++ b/tests/topotests/ospf6-topo2/r1/ospf6d.conf @@ -0,0 +1,9 @@ +interface r1-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +router ospf6 + ospf6 router-id 10.254.254.1 + area 0.0.0.1 stub + interface r1-eth0 area 0.0.0.1 +! diff --git a/tests/topotests/ospf6-topo2/r1/zebra.conf b/tests/topotests/ospf6-topo2/r1/zebra.conf new file mode 100644 index 0000000000..7fee2da8ba --- /dev/null +++ b/tests/topotests/ospf6-topo2/r1/zebra.conf @@ -0,0 +1,5 @@ +ipv6 forwarding +! +interface r1-eth0 + ipv6 address 2001:db8:1::2/64 +! diff --git a/tests/topotests/ospf6-topo2/r2/ospf6d.conf b/tests/topotests/ospf6-topo2/r2/ospf6d.conf new file mode 100644 index 0000000000..d4bb0e2a41 --- /dev/null +++ b/tests/topotests/ospf6-topo2/r2/ospf6d.conf @@ -0,0 +1,17 @@ +interface r2-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +interface r2-eth1 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +router ospf6 + ospf6 router-id 10.254.254.2 + redistribute connected + redistribute static + default-information originate always metric 123 + area 0.0.0.1 stub + interface r2-eth0 area 0.0.0.1 + interface r2-eth1 area 0.0.0.0 +! diff --git a/tests/topotests/ospf6-topo2/r2/zebra.conf b/tests/topotests/ospf6-topo2/r2/zebra.conf new file mode 100644 index 0000000000..891945a4e7 --- /dev/null +++ b/tests/topotests/ospf6-topo2/r2/zebra.conf @@ -0,0 +1,8 @@ +ipv6 forwarding +! +interface r2-eth0 + ipv6 address 2001:db8:1::1/64 +! +interface r2-eth1 + ipv6 address 2001:db8:2::2/64 +! diff --git a/tests/topotests/ospf6-topo2/r3/ospf6d.conf b/tests/topotests/ospf6-topo2/r3/ospf6d.conf new file mode 100644 index 0000000000..aaef00d5bb --- /dev/null +++ b/tests/topotests/ospf6-topo2/r3/ospf6d.conf @@ -0,0 +1,10 @@ +interface r3-eth0 + ipv6 ospf6 hello-interval 2 + ipv6 ospf6 dead-interval 10 +! +router ospf6 + ospf6 router-id 10.254.254.3 + redistribute connected + redistribute static + interface r3-eth0 area 0.0.0.0 +! diff --git a/tests/topotests/ospf6-topo2/r3/zebra.conf b/tests/topotests/ospf6-topo2/r3/zebra.conf new file mode 100644 index 0000000000..dea2fe4778 --- /dev/null +++ b/tests/topotests/ospf6-topo2/r3/zebra.conf @@ -0,0 +1,8 @@ +ipv6 forwarding +! +interface r3-eth0 + ipv6 address 2001:db8:2::1/64 +! +ipv6 route fc00:1::/64 fc00:100::1234 +ipv6 route fc00:2::/64 fc00:100::1234 +ipv6 route fc00:3::/64 fc00:100::1234 diff --git a/tests/topotests/ospf6-topo2/test_ospf6_topo2.dot b/tests/topotests/ospf6-topo2/test_ospf6_topo2.dot new file mode 100644 index 0000000000..ba7a36f2b5 --- /dev/null +++ b/tests/topotests/ospf6-topo2/test_ospf6_topo2.dot @@ -0,0 +1,71 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph template { + label="ospf6-topo2"; + + # Routers + r1 [ + shape=doubleoctagon, + label="r1", + fillcolor="#f08080", + style=filled, + ]; + r2 [ + shape=doubleoctagon + label="r2", + fillcolor="#f08080", + style=filled, + ]; + r3 [ + shape=doubleoctagon + label="r3", + fillcolor="#f08080", + style=filled, + ]; + + # Switches + sw1 [ + shape=oval, + label="sw1\n2001:db8:1::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw2 [ + shape=oval, + label="sw2\n2001:db8:2::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + sw3 [ + shape=oval, + label="sw3\n2001:db8:3::/64", + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + subgraph cluster0 { + label="area 0.0.0.1"; + r1 -- sw1 [label="eth0\n.2"]; + } + + subgraph cluster1 { + label="area 0.0.0.0"; + r2 -- sw1 [label="eth0\n.1"]; + r2 -- sw2 [label="eth1\n.2"]; + r3 -- sw2 [label="eth0\n.1"]; + r3 -- sw3 [label="eth1\n.2"]; + } +} diff --git a/tests/topotests/ospf6-topo2/test_ospf6_topo2.png b/tests/topotests/ospf6-topo2/test_ospf6_topo2.png Binary files differnew file mode 100644 index 0000000000..ee1de60736 --- /dev/null +++ b/tests/topotests/ospf6-topo2/test_ospf6_topo2.png diff --git a/tests/topotests/ospf6-topo2/test_ospf6_topo2.py b/tests/topotests/ospf6-topo2/test_ospf6_topo2.py new file mode 100644 index 0000000000..32aff05982 --- /dev/null +++ b/tests/topotests/ospf6-topo2/test_ospf6_topo2.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python + +# +# test_ospf6_topo2.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by +# Network Device Education Foundation, Inc. ("NetDEF") +# +# 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_ospf6_topo2.py: Test the FRR OSPFv3 daemon. +""" + +import os +import sys +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +pytestmark = [pytest.mark.ospf6d] + + +class OSPFv3Topo2(Topo): + "Test topology builder" + + def build(self, *_args, **_opts): + "Build function" + tgen = get_topogen(self) + + # Create 3 routers + 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): + "Sets up the pytest environment" + tgen = Topogen(OSPFv3Topo2, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + daemon_file = "{}/{}/ospf6d.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_OSPF6, daemon_file) + + # Initialize all routers. + tgen.start_router() + + +def test_wait_protocol_convergence(): + "Wait for OSPFv3 to converge" + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for protocols to converge") + + def expect_neighbor_full(router, neighbor): + "Wait until OSPFv3 convergence." + logger.info("waiting OSPFv3 router '{}'".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 ospf6 neighbor json", + {"neighbors": [{"neighborId": neighbor, "state": "Full"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + expect_neighbor_full("r1", "10.254.254.2") + expect_neighbor_full("r2", "10.254.254.1") + expect_neighbor_full("r2", "10.254.254.3") + expect_neighbor_full("r3", "10.254.254.2") + + +def test_ospf6_default_route(): + "Wait for OSPFv3 default route in stub area." + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("waiting for default route") + + def expect_route(router, route, metric): + "Test OSPF6 route existence." + logger.info("waiting OSPFv3 router '{}' routes".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 route json", + {route: [{"metric": metric}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + def expect_lsa(router, area, prefix, metric): + "Test OSPF6 LSA existence." + logger.info("waiting OSPFv3 router '{}' LSA".format(router)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ipv6 ospf6 database inter-prefix detail json", + {"areaScopedLinkStateDb": [{ + "areaId": area, + "lsa": [{ + "prefix": prefix, + "metric": metric, + }]}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=4, wait=1) + assertmsg = '"{}" convergence failure'.format(router) + assert result is None, assertmsg + + metric = 123 + expect_lsa("r1", "0.0.0.1", "::/0", metric) + expect_route("r1", "::/0", metric + 10) + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + tgen.stop_topology() + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_suppress_fa/__init__.py b/tests/topotests/ospf_suppress_fa/__init__.py new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/__init__.py diff --git a/tests/topotests/ospf_suppress_fa/r1/ospfd.conf b/tests/topotests/ospf_suppress_fa/r1/ospfd.conf new file mode 100644 index 0000000000..c02be35b14 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r1/ospfd.conf @@ -0,0 +1,9 @@ +! +interface r1-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +router ospf + network 10.0.12.0/24 area 0 +! diff --git a/tests/topotests/ospf_suppress_fa/r1/zebra.conf b/tests/topotests/ospf_suppress_fa/r1/zebra.conf new file mode 100644 index 0000000000..c1e31fb474 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r1/zebra.conf @@ -0,0 +1,4 @@ +! +interface r1-eth0 + ip address 10.0.12.1/24 +! diff --git a/tests/topotests/ospf_suppress_fa/r2/ospfd.conf b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf new file mode 100644 index 0000000000..ebc7d252fd --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r2/ospfd.conf @@ -0,0 +1,16 @@ +! +interface r2-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +interface r2-eth1 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +router ospf + network 10.0.12.0/24 area 0 + network 10.0.23.0/24 area 1 + area 1 nssa +! diff --git a/tests/topotests/ospf_suppress_fa/r2/zebra.conf b/tests/topotests/ospf_suppress_fa/r2/zebra.conf new file mode 100644 index 0000000000..9f1a26349e --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r2/zebra.conf @@ -0,0 +1,7 @@ +! +interface r2-eth0 + ip address 10.0.12.2/24 +! +interface r2-eth1 + ip address 10.0.23.2/24 +! diff --git a/tests/topotests/ospf_suppress_fa/r3/ospfd.conf b/tests/topotests/ospf_suppress_fa/r3/ospfd.conf new file mode 100644 index 0000000000..08be11a7b7 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r3/ospfd.conf @@ -0,0 +1,11 @@ +! +interface r3-eth0 + ip ospf network point-to-point + ip ospf hello-interval 2 + ip ospf dead-interval 10 +! +router ospf + redistribute static + network 10.0.23.0/24 area 1 + area 1 nssa +! diff --git a/tests/topotests/ospf_suppress_fa/r3/zebra.conf b/tests/topotests/ospf_suppress_fa/r3/zebra.conf new file mode 100644 index 0000000000..f76cbf74d2 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/r3/zebra.conf @@ -0,0 +1,8 @@ +! +ip route 3.3.1.1/32 Null0 +ip route 3.3.2.2/32 Null0 +ip route 3.3.3.3/32 Null0 +! +interface r3-eth0 + ip address 10.0.23.3/24 +! diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot new file mode 100644 index 0000000000..1036658f1a --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot @@ -0,0 +1,66 @@ +## Color coding: +######################### +## Main FRR: #f08080 red +## Switches: #d0e0d0 gray +## RIP: #19e3d9 Cyan +## RIPng: #fcb314 dark yellow +## OSPFv2: #32b835 Green +## OSPFv3: #19e3d9 Cyan +## ISIS IPv4 #fcb314 dark yellow +## ISIS IPv6 #9a81ec purple +## BGP IPv4 #eee3d3 beige +## BGP IPv6 #fdff00 yellow +##### Colors (see http://www.color-hex.com/) + +graph ospf_topo1 { + label="ospf suppress-fa"; + + # Routers + r1 [ + label="r1\nrtr-id 10.0.12.1", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r2 [ + label="r2 (ABR)\nrtr-id 10.0.23.2", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + r3 [ + label="r3 (ASBR)\nrtr-id 10.0.23.3", + shape=doubleoctagon, + fillcolor="#f08080", + style=filled, + ]; + + # Switches + s1 [ + label="s1\n10.0.12.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + s2 [ + label="s2\n10.0.23.0/24", + shape=oval, + fillcolor="#d0e0d0", + style=filled, + ]; + + # Connections + subgraph cluster0 { + label="area 0" + r1 -- s1 [label="eth1\n.1"]; + r2 -- s1 [label="eth1\n.2"]; + } + + subgraph cluster1 { + label="area 1\nNSSA" + r2 -- s2 [label="eth2\n.2"]; + r3 -- s2 [label="eth1\n.3"]; + } + + { rank=same; r1; r2; r3; } +} diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg Binary files differnew file mode 100644 index 0000000000..2907d799f5 --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.dot.jpg diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py new file mode 100644 index 0000000000..74d609c57e --- /dev/null +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python + +# +# test_ospf_suppres_fa.py +# Carles Kishimoto +# +# 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_ospf_suppres_fa.py: Test OSPF suppress-fa feature +- Topology: r1 --- R2 (ABR) --- R3 (redistribute static) + +test_ospf_set_suppress_fa() + 1) R1: Get a dict[LSA_ID] = fwd_addr for all type 5 LSA + 2) R2: Configure: area 1 nssa suppress-fa + 3) R1: Get a dict[LSA_ID] and compare fwd_address with 0.0.0.0 + +test_ospf_unset_suppress_fa() + 4) R2: Configure: no area 1 nssa suppress-fa + 5) R1: Get a dict[LSA_ID] = fwd_addr and compare it with the dict obtained in 1) +""" + +import os +import sys +import re +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + + +class NetworkTopo(Topo): + "OSPF topology builder" + + def build(self, *_args, **_opts): + "Build function" + + tgen = get_topogen(self) + + # Create routers + for router in range(1, 4): + tgen.add_router("r{}".format(router)) + + # R1-R2 backbone area + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + # R2-R3 NSSA area + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + tgen = Topogen(NetworkTopo, mod.__name__) + tgen.start_topology() + + # This is a sample of configuration loading. + router_list = tgen.routers() + + # For all registred routers, load the zebra and ospf configuration file + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname)) + ) + + tgen.start_router() + +def teardown_module(_mod): + "Teardown the pytest environment" + + tgen = get_topogen() + tgen.stop_topology() + +def test_converge_protocols(): + "Wait for protocol convergence" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + topotest.sleep(10, "Waiting for OSPF convergence") + +def ospf_configure_suppress_fa(router_name, area): + "Configure OSPF suppress-fa in router_name" + + tgen = get_topogen() + router = tgen.gears[router_name] + router.vtysh_cmd("conf t\nrouter ospf\narea {} nssa suppress-fa\nexit\n".format(area)) + +def ospf_unconfigure_suppress_fa(router_name, area): + "Remove OSPF suppress-fa in router_name" + + tgen = get_topogen() + router = tgen.gears[router_name] + router.vtysh_cmd("conf t\nrouter ospf\nno area {} nssa suppress-fa\nexit\n".format(area)) + +def ospf_get_lsa_type5(router_name): + "Return a dict with link state id as key and forwarding addresses as value" + + result = dict() + tgen = get_topogen() + router = tgen.gears[router_name] + cmd = "show ip ospf database external\n" + output = topotest.normalize_text(router.vtysh_cmd(cmd)) + for line in output.splitlines(): + re0 = re.match(r"\s+Link State ID: (\S+) \(External Network Number\)", line) + if re0: + lsa = re0.group(1) + re1 = re.match(r"\s+Forward Address: (\S+)", line) + if re1: + result[lsa] = re1.group(1) + return result + +@pytest.fixture(scope='module', name='original') +def test_ospf_set_suppress_fa(): + "Test OSPF area [x] nssa suppress-fa" + + # Get current forwarding address for each LSA type-5 in r1 + initial = ospf_get_lsa_type5("r1") + + # Configure suppres-fa in r2 area 1 + ospf_configure_suppress_fa("r2", "1") + topotest.sleep(10, "Waiting for OSPF convergence") + + # Check forwarding address on r1 for all statics is 0.0.0.0 + assertmsg = "Forwarding address is not 0.0.0.0 after enabling OSPF suppress-fa" + suppress = ospf_get_lsa_type5("r1") + for prefix in suppress: + assert suppress[prefix] == "0.0.0.0", assertmsg + + # Return the original forwarding addresses so we can compare them + # in the test_ospf_unset_supress_fa + return initial + +def test_ospf_unset_supress_fa(original): + "Test OSPF no area [x] nssa suppress-fa" + + # Remove suppress-fa in r2 area 1 + ospf_unconfigure_suppress_fa("r2", "1") + topotest.sleep(10, "Waiting for OSPF convergence") + + # Check forwarding address is the original value on r1 for all statics + assertmsg = "Forwarding address is not correct after removing OSPF suppress-fa" + restore = ospf_get_lsa_type5("r1") + for prefix in restore: + assert restore[prefix] == original[prefix], assertmsg + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons index f6d512be72..b1526888ed 100644 --- a/tools/etc/frr/daemons +++ b/tools/etc/frr/daemons @@ -30,6 +30,7 @@ pbrd=no bfdd=no fabricd=no vrrpd=no +pathd=no # # If this option is set the /etc/init.d/frr script automatically loads @@ -55,6 +56,7 @@ staticd_options="-A 127.0.0.1" bfdd_options=" -A 127.0.0.1" fabricd_options="-A 127.0.0.1" vrrpd_options=" -A 127.0.0.1" +pathd_options=" -A 127.0.0.1" # configuration profile # diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf index 0bc6547994..f902d3dd21 100644 --- a/tools/etc/frr/support_bundle_commands.conf +++ b/tools/etc/frr/support_bundle_commands.conf @@ -84,6 +84,25 @@ CMD_LIST_END # CMD_LIST_END # PIM Support Bundle Command List -# PROC_NAME:pim -# CMD_LIST_START -# CMD_LIST_END +PROC_NAME:pim +CMD_LIST_START +show ip multicast +show ip pim interface +show ip pim interface traffic +show ip pim nexthop +show ip pim neighbor +show ip pim bsr +show ip pim bsrp-info +show ip pim bsm-database +show ip pim rp-info +show ip igmp groups +show ip igmp interface +show ip igmp join +show ip igmp sources +show ip pim upstream +show ip mroute +show ip pim join +show ip pim state +show ip pim statistics +show ip pim rpf +CMD_LIST_END diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 1461e0f296..f4b832691e 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -108,7 +108,7 @@ class Vtysh(object): stdout, stderr = proc.communicate() if proc.wait() != 0: if stdouts is not None: - stdouts.append(stdout.decode('UTF-8')) + stdouts.append(stdout.decode("UTF-8")) raise VtyshException( 'vtysh returned status %d for command "%s"' % (proc.returncode, command) ) @@ -279,6 +279,35 @@ class Config(object): if ":" in line: line = get_normalized_mac_ip_line(line) + """ + vrf static routes can be added in two ways. The old way is: + + "ip route x.x.x.x/x y.y.y.y vrf <vrfname>" + + but it's rendered in the configuration as the new way:: + + vrf <vrf-name> + ip route x.x.x.x/x y.y.y.y + exit-vrf + + this difference causes frr-reload to not consider them a + match and delete vrf static routes incorrectly. + fix the old way to match new "show running" output so a + proper match is found. + """ + if ( + line.startswith("ip route ") or line.startswith("ipv6 route ") + ) and " vrf " in line: + newline = line.split(" ") + vrf_index = newline.index("vrf") + vrf_ctx = newline[vrf_index] + " " + newline[vrf_index + 1] + del newline[vrf_index : vrf_index + 2] + newline = " ".join(newline) + self.lines.append(vrf_ctx) + self.lines.append(newline) + self.lines.append("exit-vrf") + line = "end" + self.lines.append(line) self.load_contexts() @@ -460,6 +489,23 @@ class Config(object): ): key[0] = re.sub(r"\s+null0(\s*$)", " Null0", key[0]) + """ + Similar to above, but when the static is in a vrf, it turns into a + blackhole nexthop for both null0 and Null0. Fix it accordingly + """ + if lines and key[0].startswith("vrf "): + newlines = [] + for line in lines: + if line.startswith("ip route ") or line.startswith("ipv6 route "): + if "null0" in line: + line = re.sub(r"\s+null0(\s*$)", " blackhole", line) + elif "Null0" in line: + line = re.sub(r"\s+Null0(\s*$)", " blackhole", line) + newlines.append(line) + else: + newlines.append(line) + lines = newlines + if lines: if tuple(key) not in self.contexts: ctx = Context(tuple(key), lines) @@ -582,11 +628,13 @@ end if line.startswith("!") or line.startswith("#"): continue - if (len(ctx_keys) == 2 - and ctx_keys[0].startswith('bfd') - and ctx_keys[1].startswith('profile ') - and line == 'end'): - log.debug('LINE %-50s: popping from sub context, %-50s', line, ctx_keys) + if ( + len(ctx_keys) == 2 + and ctx_keys[0].startswith("bfd") + and ctx_keys[1].startswith("profile ") + and line == "end" + ): + log.debug("LINE %-50s: popping from sub context, %-50s", line, ctx_keys) if main_ctx_key: self.save_contexts(ctx_keys, current_context_lines) @@ -907,9 +955,9 @@ end ctx_keys.append(line) elif ( - line.startswith('profile ') + line.startswith("profile ") and len(ctx_keys) == 1 - and ctx_keys[0].startswith('bfd') + and ctx_keys[0].startswith("bfd") ): # Save old context first @@ -918,7 +966,7 @@ end main_ctx_key = copy.deepcopy(ctx_keys) log.debug( "LINE %-50s: entering BFD profile sub-context, append to ctx_keys", - line + line, ) ctx_keys.append(line) @@ -1067,6 +1115,16 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): for (ctx_keys, line) in lines_to_del: deleted = False + # If there is a change in the segment routing block ranges, do it + # in-place, to avoid requesting spurious label chunks which might fail + if line and "segment-routing global-block" in line: + for (add_key, add_line) in lines_to_add: + if ctx_keys[0] == add_key[0] and add_line and "segment-routing global-block" in add_line: + lines_to_del_to_del.append((ctx_keys, line)) + break + continue + + if ctx_keys[0].startswith("router bgp") and line: if line.startswith("neighbor "): diff --git a/tools/frr.service.in b/tools/frr.service.in index 836ce06be7..f67bc41b09 100644 --- a/tools/frr.service.in +++ b/tools/frr.service.in @@ -4,7 +4,7 @@ Documentation=https://frrouting.readthedocs.io/en/latest/setup.html Wants=network.target After=network-pre.target systemd-sysctl.service Before=network.target -OnFailure=heartbeat-failed@%n.service +OnFailure=heartbeat-failed@%n [Service] Nice=-5 diff --git a/tools/frr@.service.in b/tools/frr@.service.in index 1e5d252325..7b94a11f5b 100644 --- a/tools/frr@.service.in +++ b/tools/frr@.service.in @@ -4,7 +4,7 @@ Documentation=https://frrouting.readthedocs.io/en/latest/setup.html Wants=network.target After=network-pre.target systemd-sysctl.service Before=network.target -OnFailure=heartbeat-failed@%n.service +OnFailure=heartbeat-failed@%n [Service] Nice=-5 diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in index 3dbc6a1b43..475e56cf72 100644 --- a/tools/frrcommon.sh.in +++ b/tools/frrcommon.sh.in @@ -35,7 +35,7 @@ FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter # - keep zebra first # - watchfrr does NOT belong in this list -DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd" +DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd fabricd vrrpd pathd" RELOAD_SCRIPT="$D_PATH/frr-reload.py" # @@ -149,6 +149,10 @@ daemon_prep() { daemon_start() { local dmninst daemon inst args instopt wrap bin + + all=false + [ "$1" = "--all" ] && { all=true; shift; } + daemon_inst "$1" ulimit -n $MAX_FDS > /dev/null 2> /dev/null @@ -165,7 +169,11 @@ daemon_start() { if eval "$all_wrap $wrap $bin $nsopt -d $frr_global_options $instopt $args"; then log_success_msg "Started $dmninst" - vtysh_b "$daemon" + if $all; then + debug "Skipping startup of vtysh until all have started" + else + vtysh_b "$daemon" + fi else log_failure_msg "Failed to start $dmninst!" fi @@ -237,8 +245,9 @@ print_status() { all_start() { daemon_list daemons for dmninst in $daemons; do - daemon_start "$dmninst" + daemon_start --all "$dmninst" done + vtysh_b } all_stop() { diff --git a/tools/gcc-plugins/frr-format.c b/tools/gcc-plugins/frr-format.c index 6d91d2cdcd..e9f397f225 100644 --- a/tools/gcc-plugins/frr-format.c +++ b/tools/gcc-plugins/frr-format.c @@ -2343,7 +2343,7 @@ check_argument_type (const format_char_info *fci, /* note printf extension type checks are *additional* - %p must always * be pointer compatible, %d always int compatible. */ - if (!kef) + if (first_wanted_type->kind != CF_KIND_FORMAT || !kef) return true; const struct kernel_ext_fmt *kef_now; @@ -4241,6 +4241,11 @@ handle_finish_parse (void *event_data, void *data) continue; } node = TREE_TYPE (node); + + if (etab->t_unsigned) + node = c_common_unsigned_type (node); + else if (etab->t_signed) + node = c_common_signed_type (node); } etab->type = node; @@ -4357,9 +4362,17 @@ handle_pragma_printfrr_ext (cpp_reader *dummy) ttype = pragma_lex (&token, &loc); /* qualifiers */ - if (ttype == CPP_NAME && !strcmp (IDENTIFIER_POINTER (token), "const")) + while (ttype == CPP_NAME) { - etab->t_const = true; + if (!strcmp (IDENTIFIER_POINTER (token), "const")) + etab->t_const = true; + else if (!strcmp (IDENTIFIER_POINTER (token), "signed")) + etab->t_signed = true; + else if (!strcmp (IDENTIFIER_POINTER (token), "unsigned")) + etab->t_unsigned = true; + else + break; + ttype = pragma_lex (&token, &loc); } diff --git a/tools/gcc-plugins/frr-format.h b/tools/gcc-plugins/frr-format.h index 87d2049ed4..599dbc56f9 100644 --- a/tools/gcc-plugins/frr-format.h +++ b/tools/gcc-plugins/frr-format.h @@ -113,6 +113,8 @@ struct kernel_ext_fmt tree_code type_code; int ptrlevel; bool t_const; + bool t_unsigned; + bool t_signed; bool warned; const char *type_str; diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index f4f489c3dd..775611b3e3 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -40,8 +40,8 @@ #define VRRP_LOGPFX "[CORE] " -DEFINE_MTYPE_STATIC(VRRPD, VRRP_IP, "VRRP IP address") -DEFINE_MTYPE_STATIC(VRRPD, VRRP_RTR, "VRRP Router") +DEFINE_MTYPE_STATIC(VRRPD, VRRP_IP, "VRRP IP address"); +DEFINE_MTYPE_STATIC(VRRPD, VRRP_RTR, "VRRP Router"); /* statics */ struct hash *vrrp_vrouters_hash; diff --git a/vrrpd/vrrp.h b/vrrpd/vrrp.h index 502d7b82b6..c181c2159b 100644 --- a/vrrpd/vrrp.h +++ b/vrrpd/vrrp.h @@ -58,7 +58,7 @@ /* User compatibility constant */ #define CS2MS 10 -DECLARE_MGROUP(VRRPD) +DECLARE_MGROUP(VRRPD); /* Northbound */ extern const struct frr_yang_module_info frr_vrrpd_info; diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c index 94f10757a2..a5ad37aa0c 100644 --- a/vrrpd/vrrp_main.c +++ b/vrrpd/vrrp_main.c @@ -40,7 +40,7 @@ #include "vrrp_vty.h" #include "vrrp_zebra.h" -DEFINE_MGROUP(VRRPD, "vrrpd") +DEFINE_MGROUP(VRRPD, "vrrpd"); char backup_config_file[256]; @@ -128,7 +128,7 @@ FRR_DAEMON_INFO(vrrpd, VRRP, .vty_port = VRRP_VTY_PORT, .privs = &vrrp_privs, .yang_modules = vrrp_yang_modules, .n_yang_modules = array_size(vrrp_yang_modules), -) +); int main(int argc, char **argv, char **envp) { diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index 3cb13bd71b..991c030196 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -30,7 +30,7 @@ #include "vrrp_debug.h" #include "vrrp_packet.h" -DEFINE_MTYPE_STATIC(VRRPD, VRRP_PKT, "VRRP packet") +DEFINE_MTYPE_STATIC(VRRPD, VRRP_PKT, "VRRP packet"); /* clang-format off */ static const char *const vrrp_packet_names[16] = { diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in index 81c9770e55..4855c23f4b 100755 --- a/vtysh/extract.pl.in +++ b/vtysh/extract.pl.in @@ -42,7 +42,7 @@ sub scan_file { $cppadd = $fabricd ? "-DFABRICD=1" : ""; - open (FH, "@CPP@ -P -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ $cppadd $file |"); + open (FH, "@CPP@ -P -std=gnu11 -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ $cppadd $file |"); local $/; undef $/; $line = <FH>; if (!close (FH)) { diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 6e809a0713..3764188292 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -48,7 +48,7 @@ #include "json.h" #include "ferr.h" -DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy") +DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy"); /* Struct VTY. */ struct vty *vty; @@ -2237,7 +2237,7 @@ DEFUNSH(VTYSH_BFDD, bfd_peer_enter, bfd_peer_enter_cmd, } DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd, - "profile WORD", + "profile BFDPROF", BFD_PROFILE_STR BFD_PROFILE_NAME_STR) { @@ -2851,7 +2851,7 @@ DEFUN (vtysh_show_error_code, } /* Northbound. */ -DEFUN (show_config_running, +DEFUN_HIDDEN (show_config_running, show_config_running_cmd, "show configuration running\ [<json|xml> [translate WORD]]\ diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h index 20e1e1b0e9..7c8d9315e1 100644 --- a/vtysh/vtysh.h +++ b/vtysh/vtysh.h @@ -22,7 +22,7 @@ #define VTYSH_H #include "memory.h" -DECLARE_MGROUP(MVTYSH) +DECLARE_MGROUP(MVTYSH); #define VTYSH_ZEBRA 0x00001 #define VTYSH_RIPD 0x00002 diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 47f426b5e0..498d3e5f67 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -28,9 +28,9 @@ #include "vtysh/vtysh.h" #include "vtysh/vtysh_user.h" -DEFINE_MGROUP(MVTYSH, "vtysh") -DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration") -DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line") +DEFINE_MGROUP(MVTYSH, "vtysh"); +DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration"); +DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line"); vector configvec; @@ -91,9 +91,9 @@ static uint32_t config_hash(const struct config *c) return string_hash_make(c->name); } -DECLARE_LIST(config_master, struct config, rbt_item) +DECLARE_LIST(config_master, struct config, rbt_item); DECLARE_HASH(config_master_hash, struct config, hash_item, config_cmp, - config_hash) + config_hash); /* * The config_master_head is a list for order of receipt diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index 5f4d564507..faf1777d7f 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -61,8 +61,8 @@ #define PING_TOKEN "PING" -DEFINE_MGROUP(WATCHFRR, "watchfrr") -DEFINE_MTYPE_STATIC(WATCHFRR, WATCHFRR_DAEMON, "watchfrr daemon entry") +DEFINE_MGROUP(WATCHFRR, "watchfrr"); +DEFINE_MTYPE_STATIC(WATCHFRR, WATCHFRR_DAEMON, "watchfrr daemon entry"); /* Needs to be global, referenced somewhere inside libfrr. */ struct thread_master *master; @@ -1336,7 +1336,8 @@ FRR_DAEMON_INFO(watchfrr, WATCHFRR, .signals = watchfrr_signals, .n_signals = array_size(watchfrr_signals), - .privs = &watchfrr_privs, ) + .privs = &watchfrr_privs, +); #define DEPRECATED_OPTIONS "aAezR:" diff --git a/watchfrr/watchfrr.h b/watchfrr/watchfrr.h index ba6e94960f..4df1bf74af 100644 --- a/watchfrr/watchfrr.h +++ b/watchfrr/watchfrr.h @@ -23,7 +23,7 @@ #include "lib/memory.h" -DECLARE_MGROUP(WATCHFRR) +DECLARE_MGROUP(WATCHFRR); extern void watchfrr_vty_init(void); diff --git a/yang/frr-bgp-common.yang b/yang/frr-bgp-common.yang index 1840e3728c..1a19d52965 100644 --- a/yang/frr-bgp-common.yang +++ b/yang/frr-bgp-common.yang @@ -393,7 +393,7 @@ submodule frr-bgp-common { container global-neighbor-config { leaf dynamic-neighbors-limit { type uint32 { - range "1..5000"; + range "1..65535"; } description "Maximum number of BGP Dynamic Neighbors that can be created."; diff --git a/yang/frr-bgp-filter.yang b/yang/frr-bgp-filter.yang new file mode 100644 index 0000000000..199e70997f --- /dev/null +++ b/yang/frr-bgp-filter.yang @@ -0,0 +1,329 @@ +module frr-bgp-filter { + yang-version 1.1; + namespace "http://frrouting.org/yang/bgp-filter"; + prefix frr-bgp-filter; + + import frr-filter { + prefix frr-filter; + } + + import ietf-routing-types { + prefix rt-types; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines filter settings"; + + revision 2020-01-15 { + description + "Initial revision"; + } + + typedef list-sequence { + type uint32 { + range "1..4294967295"; + } + description + "List instance priority (low number means higher priority)"; + } + + typedef list-action { + type enumeration { + enum "deny" { + value 0; + description + "Deny an entry"; + } + enum "permit" { + value 1; + description + "Accept an entry"; + } + } + description + "Return action on match"; + } + + typedef bgp-list-name { + type string; + description + "List name"; + } + + typedef community-string { + type string { + pattern "(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{0,3}|0)|((6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{0,3}|0):(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{0,3}|0))|(local-AS)|(no-advertise)|(no-export)|(internet)"; + } + description + "The BGP community string"; + } + + typedef large-community-string { + type string { + pattern "(429496729[0-5]|42949672[0-8][0-9]|4294967[01][0-9]{2}|429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|4294[0-8][0-9]{5}|429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|[1-3][0-9]{9}|[1-9][0-9]{0,8}|0)|(429496729[0-5]|42949672[0-8][0-9]|4294967[01][0-9]{2}|429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|4294[0-8][0-9]{5}|429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):(429496729[0-5]|42949672[0-8][0-9]|4294967[01][0-9]{2}|429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|4294[0-8][0-9]{5}|429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|[1-3][0-9]{9}|[1-9][0-9]{0,8}|0)|(429496729[0-5]|42949672[0-8][0-9]|4294967[01][0-9]{2}|429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|4294[0-8][0-9]{5}|429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):(429496729[0-5]|42949672[0-8][0-9]|4294967[01][0-9]{2}|429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|4294[0-8][0-9]{5}|429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|[1-3][0-9]{9}|[1-9][0-9]{0,8}|0):(429496729[0-5]|42949672[0-8][0-9]|4294967[01][0-9]{2}|429496[0-6][0-9]{3}|42949[0-5][0-9]{4}|4294[0-8][0-9]{5}|429[0-3][0-9]{6}|42[0-8][0-9]{7}|4[01][0-9]{8}|[1-3][0-9]{9}|[1-9][0-9]{0,8}|0)"; + } + description + "The BGP large-community string"; + } + + augment "/frr-filter:lib" { + list community-list { + key "name"; + description + "Community-list instance"; + leaf name { + type string; + } + + list entry { + key "sequence"; + description + "Community-list entry"; + leaf sequence { + type list-sequence; + } + + leaf action { + type list-action; + } + + leaf type { + type enumeration { + enum "community-list-standard" { + value 0; + description + "Standard community-list name/identifier"; + } + enum "community-list-extended" { + value 1; + description + "Expanded community-list name/identifier"; + } + } + mandatory true; + description + "Community-list instance name/identifier"; + } + + choice community-string { + description + "Community string"; + case standard { + when "./type = 'community-list-standard'"; + leaf-list standard-community-string { + type community-string; + description + "Community string"; + } + } + + case expanded { + when "./type = 'community-list-extended'"; + leaf expanded-community-string { + type string; + description + "Community string reg-ex"; + } + } + } + } + } + + list large-community-list { + key "name"; + description + "Large community-list instance"; + leaf name { + type string; + } + + list entry { + key "sequence"; + description + "Large community-list entry"; + leaf sequence { + type list-sequence; + } + + leaf action { + type list-action; + } + + leaf type { + type enumeration { + enum "large-community-list-standard-id" { + value 0; + description + "Standard large-community-list identifier"; + } + enum "large-community-list-extended-id" { + value 1; + description + "Expanded large-community-list identifier"; + } + enum "large-community-list-standard-name" { + value 2; + description + "Standard large-community-list name"; + } + enum "large-community-list-extended-name" { + value 3; + description + "Expanded large-community-list name"; + } + } + mandatory true; + description + "Large community-list instance name/identifier"; + } + + choice large-community-string { + description + "Large community string"; + case standard { + when "./type = 'large-community-list-standard-id' or " + + "./type = 'large-community-list-standard-name'"; + leaf-list standard-large-community-string { + type large-community-string; + description + "Large community string"; + } + } + + case expanded { + when "./type = 'large-community-list-extended-id' or " + + "./type = 'large-community-list-extended-name'"; + leaf expanded-large-community-string { + type string; + description + "Large community string reg-ex"; + } + } + } + } + } + + list extcommunity-list { + key "name"; + description + "Extcommunity-list instance"; + leaf name { + type string; + } + + list entry { + key "sequence"; + description + "Extcommunity-list entry"; + leaf sequence { + type list-sequence; + } + + leaf action { + type list-action; + } + + leaf type { + type enumeration { + enum "extcommunity-list-standard-id" { + value 0; + description + "Standard extcommunity-list identifier"; + } + enum "extcommunity-list-extended-id" { + value 1; + description + "Expanded extcommunity-list identifier"; + } + enum "extcommunity-list-standard-name" { + value 2; + description + "Standard extcommunity-list name"; + } + enum "extcommunity-list-extended-name" { + value 3; + description + "Expanded extcommunity-list name"; + } + } + mandatory true; + description + "Extcommunity-list instance name/identifier"; + } + + choice extcommunity-string { + description + "Extcommunity string"; + case standard { + when "./type = 'extcommunity-list-standard-id' or " + + "./type = 'extcommunity-list-standard-name'"; + choice standard-extcommunity-string { + description + "Value of the ext-community"; + case extcommunity-rt { + description + "Set BGP ext-community route-target attribute"; + leaf-list extcommunity-rt { + type rt-types:route-target; + } + } + + case extcommunity-soo { + description + "Set BGP ext-community site-of-origin attribute"; + leaf-list extcommunity-soo { + type rt-types:route-target; + } + } + } + } + + case expanded { + when "./type = 'extcommunity-list-extended-id' or " + + "./type = 'extcommunity-list-extended-name'"; + leaf expanded-extcommunity-string { + type string; + description + "Extcommunity string reg-ex"; + } + } + } + } + } + + list as-path-list { + key "name"; + description + "AS-path access-list instance"; + leaf name { + type string; + description + "AS-path access-list instance name/identifier"; + } + + list entry { + key "sequence"; + description + "AS-path access-list entry"; + leaf sequence { + type list-sequence; + } + + leaf action { + type list-action; + } + + leaf as-path { + type string; + description + "AS-path access-list string reg-ex"; + } + } + } + } +} diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang new file mode 100644 index 0000000000..96505b08a8 --- /dev/null +++ b/yang/frr-bgp-route-map.yang @@ -0,0 +1,820 @@ +module frr-bgp-route-map { + yang-version 1.1; + namespace "http://frrouting.org/yang/bgp-route-map"; + prefix frr-bgp-route-map; + + import ietf-inet-types { + prefix inet; + } + + import frr-route-map { + prefix frr-route-map; + } + + import frr-filter { + prefix filter; + } + + import frr-bgp-filter { + prefix bgp-filter; + } + + import ietf-routing-types { + prefix rt-types; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines bgp route map settings"; + + revision 2020-01-02 { + description + "Initial revision"; + } + + identity match-local-preference { + base frr-route-map:rmap-match-type; + description + "Match local-preference of routes"; + } + + identity match-script { + base frr-route-map:rmap-match-type; + description + "Match script of routes"; + } + + identity match-origin { + base frr-route-map:rmap-match-type; + description + "Match BGP route origin code"; + } + + identity rpki { + base frr-route-map:rmap-match-type; + description + "Control rpki specific settings"; + } + + identity probability { + base frr-route-map:rmap-match-type; + description + "Match portion of routes defined by percentage value"; + } + + identity source-vrf { + base frr-route-map:rmap-match-type; + description + "Match source vrf of routes"; + } + + identity peer { + base frr-route-map:rmap-match-type; + description + "Match peer address"; + } + + identity mac-address-list { + base frr-route-map:rmap-match-type; + description + "Match MAC address access-list"; + } + + identity ip-route-source { + base frr-route-map:rmap-match-type; + description + "Match advertising source address of route"; + } + + identity ip-route-source-prefix-list { + base frr-route-map:rmap-match-type; + description + "Match advertising source address of route"; + } + + identity evpn-route-type { + base frr-route-map:rmap-match-type; + description + "Match EVPN route type"; + } + + identity evpn-default-route { + base frr-route-map:rmap-match-type; + description + "Match EVPN default Type-5 route"; + } + + identity evpn-vni { + base frr-route-map:rmap-match-type; + description + "Match EVPN VNI"; + } + + identity evpn-rd { + base frr-route-map:rmap-match-type; + description + "Match EVPN route distinguisher"; + } + + identity match-community { + base frr-route-map:rmap-match-type; + description + "Match BGP community list"; + } + + identity match-large-community { + base frr-route-map:rmap-match-type; + description + "Match BGP large-community list"; + } + + identity match-extcommunity { + base frr-route-map:rmap-match-type; + description + "Match BGP extcommunity list"; + } + + identity as-path-list { + base frr-route-map:rmap-match-type; + description + "Match BGP AS path list"; + } + + identity ipv4-nexthop { + base frr-route-map:rmap-match-type; + description + "Match IPv4 next hop address"; + } + + identity ipv6-nexthop { + base frr-route-map:rmap-match-type; + description + "Match IPv6 next hop address"; + } + + identity distance { + base frr-route-map:rmap-set-type; + description + "Set BGP administrative distance to use"; + } + + identity set-extcommunity-rt { + base frr-route-map:rmap-set-type; + description + "Set BGP extended community attribute"; + } + + identity set-extcommunity-soo { + base frr-route-map:rmap-set-type; + description + "Set BGP extended community attribute"; + } + + identity set-extcommunity-lb { + base frr-route-map:rmap-set-type; + description + "Set BGP extended community attribute"; + } + + identity set-ipv4-nexthop { + base frr-route-map:rmap-set-type; + description + "Set the IPv4 next-hop to peer-address/unchanged"; + } + + identity ipv4-vpn-address { + base frr-route-map:rmap-set-type; + description + "Set IPv4 VPN next-hop address"; + } + + identity ipv6-nexthop-global { + base frr-route-map:rmap-set-type; + description + "Set IPv6 next-hop global address"; + } + + identity ipv6-prefer-global { + base frr-route-map:rmap-set-type; + description + "Set IPv6 next-hop to prefer global address"; + } + + identity ipv6-peer-address { + base frr-route-map:rmap-set-type; + description + "Set IPv6 next-hop peer address"; + } + + identity ipv6-vpn-address { + base frr-route-map:rmap-set-type; + description + "Set IPv6 VPN next-hop address"; + } + + identity label-index { + base frr-route-map:rmap-set-type; + description + "Set the label index to associate with the prefixs"; + } + + identity set-local-preference { + base frr-route-map:rmap-set-type; + description + "Set the BGP local preference path attribute"; + } + + identity set-origin { + base frr-route-map:rmap-set-type; + description + "Set BGP route origin code"; + } + + identity weight { + base frr-route-map:rmap-set-type; + description + "Set the BGP weight attribute"; + } + + identity originator-id { + base frr-route-map:rmap-set-type; + description + "Set the BGP originator ID attribute"; + } + + identity table { + base frr-route-map:rmap-set-type; + description + "Export route to non-main kernel table"; + } + + identity atomic-aggregate { + base frr-route-map:rmap-set-type; + description + "Set BGP atomic-aggregate attribute"; + } + + identity as-path-prepend { + base frr-route-map:rmap-set-type; + description + "Set the BGP AS-path attribute"; + } + + identity as-path-exclude { + base frr-route-map:rmap-set-type; + description + "Set the BGP AS-path attribute"; + } + + identity set-community { + base frr-route-map:rmap-set-type; + description + "Set the BGP community attribute"; + } + + identity set-large-community { + base frr-route-map:rmap-set-type; + description + "Set the BGP large-community attribute"; + } + + identity aggregator { + base frr-route-map:rmap-set-type; + description + "Set the BGP aggregator attribute"; + } + + identity comm-list-delete { + base frr-route-map:rmap-set-type; + description + "Set BGP community list (for deletion)"; + } + + identity large-comm-list-delete { + base frr-route-map:rmap-set-type; + description + "Set BGP large community list (for deletion)"; + } + + grouping extcommunity-non-transitive-types { + leaf two-octet-as-specific { + type boolean; + description + "Non-Transitive Two-Octet AS-Specific Extended Community"; + } + } + + typedef extcommunity-lb-type { + type enumeration { + enum "explicit-bandwidth" { + value 0; + description + "Bandwidth value in Mbps"; + } + enum "cumulative-bandwidth" { + value 1; + description + "Cumulative bandwidth of all multipaths (outbound-only)"; + } + enum "computed-bandwidth" { + value 2; + description + "Internally computed bandwidth based on number of multipaths (outbound-only)"; + } + } + description + "ext-community link bandwidth types."; + } + + augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:rmap-match-condition/frr-route-map:match-condition" { + case local-preference { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'match-local-preference')"; + leaf local-preference { + type uint32 { + range "0..4294967295"; + } + } + } + + case script { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'match-script')"; + leaf script { + type string; + } + } + + case origin { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'match-origin')"; + leaf origin { + type enumeration { + enum "egp" { + value 0; + description + "Remote EGP"; + } + enum "igp" { + value 1; + description + "Local IGP"; + } + enum "incomplete" { + value 2; + description + "Unknown heritage"; + } + } + } + } + + case rpki { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'rpki')"; + leaf rpki { + type enumeration { + enum "invalid" { + value 0; + description + "Invalid prefix"; + } + enum "notfound" { + value 1; + description + "Prefix not found"; + } + enum "valid" { + value 2; + description + "Valid prefix"; + } + } + } + } + + case probability { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'probability')"; + leaf probability { + type uint8 { + range "0..100"; + } + } + } + + case source-vrf { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'source-vrf')"; + leaf source-vrf { + type string; + } + } + + case peer { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'peer')"; + choice peer { + description + "Value of the peer"; + case peer-ipv4-address { + description + "IP address of peer"; + leaf peer-ipv4-address { + type inet:ipv4-address; + } + } + + case peer-interface { + description + "Interface name of peer"; + leaf peer-interface { + type string; + } + } + + case peer-ipv6-address { + description + "IPv6 address of peer"; + leaf peer-ipv6-address { + type inet:ipv6-address; + } + } + + case peer-local { + description + "Static or Redistributed routes"; + leaf peer-local { + type boolean; + } + } + } + } + + case access-list-name { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'mac-address-list') or " + + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'as-path-list') or " + + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'ip-route-source') or " + + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'ip-route-source-prefix-list')"; + description + "Access-list name"; + leaf list-name { + type filter:access-list-name; + } + } + + case evpn-default-route { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'evpn-default-route')"; + description + "Match default EVPN type-5 route"; + leaf evpn-default-route { + type empty; + } + } + + case evpn-vni { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'evpn-vni')"; + description + "Match eVPN VNI"; + leaf evpn-vni { + type uint32 { + range "1..16777215"; + } + } + } + + case evpn-route-type { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'evpn-route-type')"; + description + "Match eVPN route-type"; + leaf evpn-route-type { + type enumeration { + enum "macip" { + value 0; + description + "Mac-IP route"; + } + enum "multicast" { + value 1; + description + "IMET route"; + } + enum "prefix" { + value 2; + description + "Prefix route"; + } + } + } + } + + case evpn-rd { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'evpn-rd')"; + description + "Match eVPN route-distinguisher"; + leaf route-distinguisher { + type rt-types:route-distinguisher; + } + } + + case comm-list-name { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'match-community') or " + + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'match-large-community') or " + + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'match-extcommunity')"; + container comm-list { + leaf comm-list-name { + type bgp-filter:bgp-list-name; + } + + leaf comm-list-name-exact-match { + type boolean; + description + "Do exact matching of communities"; + } + } + } + + case ipv4-address { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'ipv4-nexthop')"; + leaf ipv4-address { + type inet:ipv4-address; + description + "IPv4 address"; + } + } + + case ipv6-address { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'ipv6-nexthop')"; + leaf ipv6-address { + type inet:ipv6-address; + description + "IPv6 address"; + } + } + } + + augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" { + case distance { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'distance')"; + leaf distance { + type uint8 { + range "0..255"; + } + } + } + + case extcommunity-rt { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'set-extcommunity-rt')"; + description + "Value of the ext-community"; + leaf extcommunity-rt { + type string; + description + "Set BGP ext-community route-target attribute"; + } + } + + case extcommunity-soo { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'set-extcommunity-soo')"; + description + "Value of the ext-community"; + leaf extcommunity-soo { + type string; + description + "Set BGP ext-community site-of-origin attribute"; + } + } + + case extcommunity-lb { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'set-extcommunity-lb')"; + container extcommunity-lb { + description + "Value of the ext-community."; + leaf lb-type { + type frr-bgp-route-map:extcommunity-lb-type; + } + + leaf bandwidth { + when "../lb-type = 'explicit-bandwidth'"; + type uint16 { + range "1..25600"; + } + description + "Bandwidth value in Mbps"; + } + uses extcommunity-non-transitive-types; + } + } + + case ipv4-address { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'ipv4-vpn-address')"; + description + "Set the IPv4 address"; + leaf ipv4-address { + type inet:ipv4-address; + } + } + + case ipv4-nexthop { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'set-ipv4-nexthop')"; + leaf ipv4-nexthop { + type string; + } + } + + case ipv6-address { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'ipv6-nexthop-global') or " + + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'ipv6-vpn-address')"; + description + "Set the IPv6 address"; + leaf ipv6-address { + type inet:ipv6-address; + } + } + + case preference { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'ipv6-prefer-global') or " + + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'ipv6-peer-address')"; + leaf preference { + type boolean; + } + } + + case label-index { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'label-index')"; + leaf label-index { + type uint32 { + range "0..1048560"; + } + } + } + + case local-pref { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'set-local-preference')"; + leaf local-pref { + type string; + } + } + + case weight { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'weight')"; + leaf weight { + type uint32 { + range "0..4294967295"; + } + } + } + + case origin { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'set-origin')"; + leaf origin { + type enumeration { + enum "egp" { + value 0; + description + "Remote EGP"; + } + enum "igp" { + value 1; + description + "Local IGP"; + } + enum "incomplete" { + value 2; + description + "Unknown heritage"; + } + } + } + } + + case originator-id { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'originator-id')"; + leaf originator-id { + type inet:ipv4-address; + } + } + + case table { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'table')"; + leaf table { + type uint32 { + range "1..4294967295"; + } + } + } + + case atomic-aggregate { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'atomic-aggregate')"; + leaf atomic-aggregate { + type empty; + } + } + + case as-path-prepend { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'as-path-prepend')"; + choice as-path-prepend { + description + "Value of the BGP AS-path attribute"; + case prepend-as { + description + "Prepend the mentioned AS-path"; + leaf prepend-as-path { + type string; + } + } + + case last-as { + description + "Prepend the last ASN in the AS-path"; + leaf last-as { + type uint8 { + range "1..10"; + } + } + } + } + } + + case as-path-exclude { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'as-path-exclude')"; + leaf exclude-as-path { + type string; + description + "Exclude the mentioned AS-path"; + } + } + + case community { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'set-community')"; + choice community { + description + "Value of the BGP community attribute"; + case none { + description + "No community attribute"; + leaf community-none { + type boolean; + } + } + + case community-string { + description + "Community string"; + leaf community-string { + type string; + } + } + } + } + + case large-community { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'set-large-community')"; + choice large-community { + description + "Value of the BGP large-community attribute"; + case none { + description + "No large-community attribute"; + leaf large-community-none { + type boolean; + } + } + + case large-community-string { + description + "Large-Community string"; + leaf large-community-string { + type string; + } + } + } + } + + case aggregator { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'aggregator')"; + container aggregator { + leaf aggregator-asn { + type uint32 { + range "1..4294967295"; + } + description + "ASN of the aggregator"; + } + + leaf aggregator-address { + when "../aggregator-asn > 0 or " + + "../aggregator-asn <= 4294967295"; + type inet:ipv4-address; + description + "IPv4 address of the aggregator"; + } + } + } + + case comm-list-name { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'comm-list-delete') or " + + "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'large-comm-list-delete')"; + leaf comm-list-name { + type bgp-filter:bgp-list-name; + } + } + } +} diff --git a/yang/frr-bgp.yang b/yang/frr-bgp.yang index 24998a470d..ae44447df7 100644 --- a/yang/frr-bgp.yang +++ b/yang/frr-bgp.yang @@ -1057,6 +1057,8 @@ module frr-bgp { uses structure-neighbor-route-server; uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; } augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/neighbors/unnumbered-neighbor/afi-safis/afi-safi/ipv4-flowspec" { @@ -1332,6 +1334,8 @@ module frr-bgp { uses structure-neighbor-route-server; uses structure-neighbor-group-soft-reconfiguration; + + uses structure-neighbor-group-filter-config; } augment "/frr-rt:routing/frr-rt:control-plane-protocols/frr-rt:control-plane-protocol/bgp/peer-groups/peer-group/afi-safis/afi-safi/ipv4-flowspec" { diff --git a/yang/frr-ospf-route-map.yang b/yang/frr-ospf-route-map.yang new file mode 100644 index 0000000000..ad7ba5c1ba --- /dev/null +++ b/yang/frr-ospf-route-map.yang @@ -0,0 +1,52 @@ +module frr-ospf-route-map { + yang-version 1.1; + namespace "http://frrouting.org/yang/ospf-route-map"; + prefix frr-ospf-route-map; + + import ietf-inet-types { + prefix inet; + } + + import frr-route-map { + prefix frr-route-map; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines ospf route map settings"; + + revision 2020-01-02 { + description + "Initial revision"; + } + + identity metric-type { + base frr-route-map:rmap-set-type; + description + "Set the type of metric"; + } + + augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" { + case metric-type { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'metric-type')"; + leaf metric-type { + type enumeration { + enum "type-1" { + value 0; + description + "OSPF6 external type 1 metric"; + } + enum "type-2" { + value 1; + description + "OSPF6 external type 2 metric"; + } + } + } + } + } +} diff --git a/yang/frr-ospf6-route-map.yang b/yang/frr-ospf6-route-map.yang new file mode 100644 index 0000000000..e5d4969d45 --- /dev/null +++ b/yang/frr-ospf6-route-map.yang @@ -0,0 +1,47 @@ +module frr-ospf6-route-map { + yang-version 1.1; + namespace "http://frrouting.org/yang/ospf6-route-map"; + prefix frr-ospf6-route-map; + + import ietf-inet-types { + prefix inet; + } + + import frr-route-map { + prefix frr-route-map; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines ospf6 route map settings"; + + revision 2020-01-02 { + description + "Initial revision"; + } + + identity forwarding-address { + base frr-route-map:rmap-set-type; + description + "Set the forwarding address"; + } + + identity metric-type { + base frr-route-map:rmap-set-type; + description + "Set the type of metric"; + } + + augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" { + case ipv6-address { + when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'forwarding-address')"; + leaf ipv6-address { + type inet:ipv6-address; + } + } + } +} diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index f959ff8be5..2070649ec2 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -294,6 +294,9 @@ module frr-pim { type uint8 { range "1..180"; } + must ". > ./../hello-interval" { + error-message "HoldTime must be greater than Hello"; + } description "Hello holdtime"; } diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index b22a96a740..6ed3dadaae 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -53,21 +53,124 @@ module frr-route-map { "Initial revision"; } - /* - * Types. - */ + identity rmap-match-type { + description + "Base route-map match-condition"; + } + + identity interface { + base rmap-match-type; + description + "Match interface"; + } + + identity ipv4-address-list { + base rmap-match-type; + description + "Match an IPv4 access-list"; + } + + identity ipv4-prefix-list { + base rmap-match-type; + description + "Match an IPv4 prefix-list"; + } + + identity ipv4-next-hop-list { + base rmap-match-type; + description + "Match an IPv4 next-hop"; + } + + identity ipv4-next-hop-prefix-list { + base rmap-match-type; + description + "Match an IPv4 next-hop prefix list"; + } + + identity ipv4-next-hop-type { + base rmap-match-type; + description + "Match an IPv4 next-hop type"; + } + + identity ipv6-address-list { + base rmap-match-type; + description + "Match an IPv6 access-list"; + } + + identity ipv6-prefix-list { + base rmap-match-type; + description + "Match an IPv6 prefix-list"; + } + + identity ipv6-next-hop-type { + base rmap-match-type; + description + "Match an IPv6 next-hop type"; + } + + identity match-metric { + base rmap-match-type; + description + "Match a route metric"; + } + + identity match-tag { + base rmap-match-type; + description + "Match a route tag"; + } + + identity rmap-set-type { + description + "Base route-map set-action"; + } + + identity ipv4-next-hop { + base rmap-set-type; + description + "Set IPv4 address of the next hop"; + } + + identity ipv6-next-hop { + base rmap-set-type; + description + "Set IPv6 address of the next hop"; + } + + identity set-metric { + base rmap-set-type; + description + "Set prefix/route metric"; + } + + identity set-tag { + base rmap-set-type; + description + "Set tag"; + } + + identity set-sr-te-color { + base rmap-set-type; + description + "Set Color of the SR-TE"; + } + typedef route-map-sequence { type uint16 { range "1..65535"; } description - "Route map valid sequence numbers."; + "Route map valid sequence numbers"; } typedef route-map-name { type string; description - "Route map name format."; + "Route map name format"; } typedef route-map-ref { @@ -79,349 +182,294 @@ module frr-route-map { "Reference to a route-map."; } - /* - * Operational data. - */ + grouping rmap-match-condition { + container rmap-match-condition { + choice match-condition { + description + "Value to match (interpretation depends on condition type)"; + case interface { + when "derived-from-or-self(../condition, 'interface')"; + leaf interface { + type frr-interface:interface-ref; + } + } + + case list-name { + when "derived-from-or-self(../condition, 'ipv4-address-list') or " + + "derived-from-or-self(../condition, 'ipv4-prefix-list') or " + + "derived-from-or-self(../condition, 'ipv4-next-hop-list') or " + + "derived-from-or-self(../condition, 'ipv4-next-hop-prefix-list') or " + + "derived-from-or-self(../condition, 'ipv6-address-list') or " + + "derived-from-or-self(../condition, 'ipv6-prefix-list')"; + leaf list-name { + type filter:access-list-name; + } + } + + case ipv4-next-hop-type { + when "derived-from-or-self(../condition, 'ipv4-next-hop-type')"; + leaf ipv4-next-hop-type { + type enumeration { + enum "blackhole" { + value 0; + } + } + } + } + + case ipv6-next-hop-type { + when "derived-from-or-self(../condition, 'ipv6-next-hop-type')"; + leaf ipv6-next-hop-type { + type enumeration { + enum "blackhole" { + value 0; + } + } + } + } + + case match-metric { + when "derived-from-or-self(../condition, 'match-metric')"; + leaf metric { + type uint32 { + range "1..4294967295"; + } + } + } + + case match-tag { + when "derived-from-or-self(../condition, 'match-tag')"; + leaf tag { + type uint32 { + range "1..4294967295"; + } + } + } + } + } + } + + grouping rmap-set-action { + container rmap-set-action { + choice set-action { + description + "Value to set (interpretation depends on action-type)"; + case ipv4-address { + when "derived-from-or-self(../action, 'ipv4-next-hop')"; + leaf ipv4-address { + type inet:ipv4-address; + description + "IPv4 address"; + } + } + + case ipv6-address { + when "derived-from-or-self(../action, 'ipv6-next-hop')"; + leaf ipv6-address { + type inet:ipv6-address; + description + "IPv6 address"; + } + } + + case set-metric { + when "derived-from-or-self(../action, 'set-metric')"; + choice metric-value { + description + "Metric to set or use"; + case value { + leaf value { + type uint32 { + range "0..4294967295"; + } + description + "Use the following metric value"; + } + } + + case add-metric { + leaf add-metric { + description "Add value to metric."; + type uint32 { + range "0..4294967295"; + } + } + } + + case subtract-metric { + leaf subtract-metric { + description "Subtract value from metric."; + type uint32 { + range "0..4294967295"; + } + } + } + + case use-round-trip-time { + leaf use-round-trip-time { + type boolean; + description + "Use the round trip time as metric"; + } + } + + case add-round-trip-time { + leaf add-round-trip-time { + type boolean; + description + "Add round trip time to metric"; + } + } + + case subtract-round-trip-time { + leaf subtract-round-trip-time { + type boolean; + description + "Subtract round trip time to metric"; + } + } + } + } + + case set-tag { + when "derived-from-or-self(../action, 'set-tag')"; + leaf tag { + type uint32 { + range "0..4294967295"; + } + description + "Tag value"; + } + } + + case set-sr-te-color { + when "derived-from-or-self(../action, 'set-sr-te-color')"; + leaf policy { + type string; + description + "Color of the SR-TE Policies to match with"; + } + } + } + } + } + container lib { list route-map { key "name"; description - "Route map instance."; + "Route map instance"; leaf name { type route-map-name; description - "Route map instance name."; + "Route map instance name"; } list entry { key "sequence"; description - "Route map entry."; + "Route map entry"; leaf sequence { - description - "Route map instance priority (low number means higher priority)."; type route-map-sequence; + description + "Route map instance priority (low number means higher priority)"; } leaf description { - description "Route map description."; type string; + description + "Route map description"; } leaf action { - description - "Route map actions: permit (executes action), deny (quits evaluation)."; - mandatory true; type enumeration { - enum permit { + enum "permit" { + value 0; description "Executes configured action and permits the prefix/route if the conditions matched. An alternative exit action can be configured to continue processing the route map list or jump to process another route map."; - value 0; } - enum deny { + enum "deny" { + value 1; description "If all conditions are met the prefix/route is denied and route map processing stops."; - value 1; } } + mandatory true; + description + "Route map actions: permit (executes action), deny (quits evaluation)"; } leaf call { + type route-map-name; description "Call another route map before calling `exit-policy`. If the called route map returns deny then this route map will also - return deny."; - type route-map-name; + return deny"; } leaf exit-policy { - description "What do to after route map successful match, set and call."; type enumeration { - enum permit-or-deny { - description "End route map evaluation and return."; + enum "permit-or-deny" { value 0; - } - enum next { description - "Proceed evaluating next route map entry per sequence."; - value 1; + "End route map evaluation and return"; } - enum goto { + enum "next" { + value 1; description - "Go to route map entry with the provided sequence number."; + "Proceed evaluating next route map entry per sequence"; + } + enum "goto" { value 2; + description + "Go to route map entry with the provided sequence number"; } } default "permit-or-deny"; + description + "What do to after route map successful match, set and call"; } leaf goto-value { when "../exit-policy = 'goto'"; - description - "Sequence number to jump (when using `goto` exit policy)."; - mandatory true; type route-map-sequence; + mandatory true; + description + "Sequence number to jump (when using `goto` exit policy)"; } list match-condition { key "condition"; description - "Route map match conditions."; + "Route map match conditions"; leaf condition { - description "Match condition."; - type enumeration { - enum interface { - description "Match interface."; - value 0; - } - enum ipv4-address-list { - description "Match an IPv4 access-list."; - value 1; - } - enum ipv4-prefix-list { - description "Match an IPv4 prefix-list."; - value 2; - } - enum ipv4-next-hop-list { - description "Match an IPv4 next-hop."; - value 3; - } - enum ipv4-next-hop-prefix-list { - description "Match an IPv4 next-hop prefix list."; - value 4; - } - enum ipv4-next-hop-type { - description "Match an IPv4 next-hop type."; - value 5; - } - enum ipv6-address-list { - description "Match an IPv6 access-list."; - value 6; - } - enum ipv6-prefix-list { - description "Match an IPv6 prefix-list."; - value 7; - } - enum ipv6-next-hop-type { - description "Match an IPv6 next-hop type."; - value 8; - } - enum metric { - description "Match a route metric."; - value 9; - } - enum tag { - description "Match a route tag."; - value 10; - } - /* zebra specific conditions. */ - enum ipv4-prefix-length { - description "Match IPv4 prefix length."; - value 100; - } - enum ipv6-prefix-length { - description "Match IPv6 prefix length."; - value 101; - } - enum ipv4-next-hop-prefix-length { - description "Match next-hop prefix length."; - value 102; - } - enum source-protocol { - description "Match source protocol."; - value 103; - } - enum source-instance { - description "Match source protocol instance."; - value 104; - } + type identityref { + base rmap-match-type; } - } - - choice condition-value { description - "Value to match (interpretation depends on condition type)."; - mandatory true; - case interface { - when "./condition = 'interface'"; - leaf interface { - type frr-interface:interface-ref; - } - } - - case list-name { - when "./condition = 'ipv4-address-list' or - ./condition = 'ipv4-prefix-list' or - ./condition = 'ipv4-next-hop-list' or - ./condition = 'ipv4-next-hop-prefix-list' or - ./condition = 'ipv6-address-list' or - ./condition = 'ipv6-prefix-list'"; - leaf list-name { - type filter:access-list-name; - } - } - - case ipv4-next-hop-type { - when "./condition = 'ipv4-next-hop-type'"; - leaf ipv4-next-hop-type { - type enumeration { - enum blackhole { - value 0; - } - } - } - } - - case ipv6-next-hop-type { - when "./condition = 'ipv6-next-hop-type'"; - leaf ipv6-next-hop-type { - type enumeration { - enum blackhole { - value 0; - } - } - } - } - - case metric { - when "./condition = 'metric'"; - leaf metric { - type uint32 { - range "1..4294967295"; - } - } - } - - case tag { - when "./condition = 'tag'"; - leaf tag { - type uint32 { - range "1..4294967295"; - } - } - } + "Match condition"; } + + uses rmap-match-condition; } list set-action { - description "Route map set actions."; - key "action"; - + description + "Route map set actions"; leaf action { - description "Action to do when the route map matches."; - type enumeration { - enum ipv4-next-hop { - description "Set IPv4 address of the next hop."; - value 0; - } - enum ipv6-next-hop { - description "Set IPv6 address of the next hop."; - value 1; - } - enum metric { - description "Set prefix/route metric."; - value 2; - } - enum tag { - description "Set tag."; - value 3; - } - /* zebra specific conditions. */ - enum source { - description "Set source address for route."; - value 100; - } + type identityref { + base rmap-set-type; } - } - - choice action-value { description - "Value to set (interpretation depends on action-type)."; - case ipv4-address { - when "./action = 'ipv4-next-hop'"; - leaf ipv4-address { - description "IPv4 address."; - type inet:ipv4-address; - } - } - - case ipv6-address { - when "./action = 'ipv6-next-hop'"; - leaf ipv6-address { - description "IPv6 address."; - type inet:ipv6-address; - } - } - - case metric { - when "./action = 'metric'"; - choice metric-value { - description "Metric to set or use."; - case value { - leaf value { - description "Use the following metric value."; - type uint32 { - range "0..4294967295"; - } - } - } - - case add-metric { - leaf add-metric { - description "Add value to metric."; - type uint32 { - range "0..4294967295"; - } - } - } - - case subtract-metric { - leaf subtract-metric { - description "Subtract value from metric."; - type uint32 { - range "0..4294967295"; - } - } - } - - case use-round-trip-time { - leaf use-round-trip-time { - description "Use the round trip time as metric."; - type boolean; - } - } - - case add-round-trip-time { - leaf add-round-trip-time { - description "Add round trip time to metric."; - type boolean; - } - } - - case subtract-round-trip-time { - leaf subtract-round-trip-time { - description "Subtract round trip time to metric."; - type boolean; - } - } - } - } - - case tag { - when "./action = 'tag'"; - leaf tag { - description "Tag value."; - type uint32 { - range "0..4294967295"; - } - } - } + "Action to do when the route map matches"; } + + uses rmap-set-action; } } } diff --git a/yang/frr-zebra-route-map.yang b/yang/frr-zebra-route-map.yang new file mode 100644 index 0000000000..91f4c87e33 --- /dev/null +++ b/yang/frr-zebra-route-map.yang @@ -0,0 +1,126 @@ +module frr-zebra-route-map { + yang-version 1.1; + namespace "http://frrouting.org/yang/zebra-route-map"; + prefix frr-zebra-route-map; + + import ietf-inet-types { + prefix inet; + } + + import frr-route-map { + prefix frr-route-map; + } + + import frr-route-types { + prefix frr-route-types; + } + + organization + "Free Range Routing"; + contact + "FRR Users List: <mailto:frog@lists.frrouting.org> + FRR Development List: <mailto:dev@lists.frrouting.org>"; + description + "This module defines zebra route map settings"; + + revision 2020-01-02 { + description + "Initial revision"; + } + + identity ipv4-prefix-length { + base frr-route-map:rmap-match-type; + description + "Match IPv4 address prefix length"; + } + + identity ipv4-next-hop-prefix-length { + base frr-route-map:rmap-match-type; + description + "Match IPv4 next-hop address prefix length"; + } + + identity ipv6-prefix-length { + base frr-route-map:rmap-match-type; + description + "Match IPv6 address prefix length"; + } + + identity source-instance { + base frr-route-map:rmap-match-type; + description + "Match the protocol's instance number"; + } + + identity source-protocol { + base frr-route-map:rmap-match-type; + description + "Match protocol via which the route was learnt"; + } + + identity src-address { + base frr-route-map:rmap-set-type; + description + "Set IPv4/IPv6 source address for route"; + } + + augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:rmap-match-condition/frr-route-map:match-condition" { + case ipv4-prefix-length { + when "derived-from-or-self(../condition, 'ipv4-prefix-length') or " + + "derived-from-or-self(../condition, 'ipv4-next-hop-prefix-length')"; + leaf ipv4-prefix-length { + type uint8 { + range "0..32"; + } + } + } + + case ipv6-prefix-length { + when "derived-from-or-self(../condition, 'ipv6-prefix-length')"; + leaf ipv6-prefix-length { + type uint8 { + range "0..128"; + } + } + } + + case source-instance { + when "derived-from-or-self(../condition, 'source-instance')"; + leaf source-instance { + type uint8 { + range "0..255"; + } + } + } + + case source-protocol { + when "derived-from-or-self(../condition, 'source-protocol')"; + leaf source-protocol { + type frr-route-types:frr-route-types; + } + } + } + + augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" { + case src-address { + when "derived-from-or-self(../action, 'src-address')"; + choice src-address { + description + "Value of the source address"; + case ipv4-src-address { + leaf ipv4-src-address { + type inet:ipv4-address; + mandatory true; + } + } + + case ipv6-src-address { + leaf ipv6-src-address { + type inet:ipv6-address; + mandatory true; + } + } + } + } + } +} diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index 782e0a4b74..5c2560837f 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -597,6 +597,7 @@ module frr-zebra { grouping ribs { container ribs { + config false; description "RIBs supported by FRR."; list rib { @@ -617,7 +618,6 @@ module frr-zebra { list route { key "prefix"; - config false; leaf prefix { type inet:ip-prefix; description @@ -2175,65 +2175,4 @@ module frr-zebra { } // End of operational / state container } - - // End interface model augmentation - - augment "/frr-route-map:lib" - + "/frr-route-map:route-map" - + "/frr-route-map:entry" - + "/frr-route-map:match-condition" - + "/frr-route-map:condition-value" { - case ipv4-prefix-length { - when "./condition = 'ipv4-prefix-length' or - ./condition = 'ipv4-next-hop-prefix-length'"; - leaf ipv4-prefix-length { - type uint8 { - range "0..32"; - } - } - } - case ipv6-prefix-length { - when "./condition = 'ipv6-prefix-length'"; - leaf ipv6-prefix-length { - type uint8 { - range "0..128"; - } - } - } - case source-protocol { - when "./condition = 'source-protocol'"; - leaf source-protocol { - type frr-route-types:frr-route-types; - } - } - case source-instance { - when "./condition = 'source-instance'"; - leaf source-instance { - type uint8 { - range "0..255"; - } - } - } - } - - augment "/frr-route-map:lib" - + "/frr-route-map:route-map" - + "/frr-route-map:entry" - + "/frr-route-map:set-action" - + "/frr-route-map:action-value" { - case source-v4 { - when "./action = 'source'"; - leaf source-v4 { - description "IPv4 address"; - type inet:ipv4-address; - } - } - case source-v6 { - when "./action = 'source'"; - leaf source-v6 { - description "IPv6 address"; - type inet:ipv6-address; - } - } - } } diff --git a/yang/subdir.am b/yang/subdir.am index 47fc508901..a2243fb8e4 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -25,6 +25,11 @@ dist_yangmodels_DATA += yang/frr-nexthop.yang dist_yangmodels_DATA += yang/frr-test-module.yang dist_yangmodels_DATA += yang/frr-interface.yang dist_yangmodels_DATA += yang/frr-route-map.yang +dist_yangmodels_DATA += yang/frr-zebra-route-map.yang +dist_yangmodels_DATA += yang/frr-ospf-route-map.yang +dist_yangmodels_DATA += yang/frr-ospf6-route-map.yang +dist_yangmodels_DATA += yang/frr-bgp-filter.yang +dist_yangmodels_DATA += yang/frr-bgp-route-map.yang dist_yangmodels_DATA += yang/frr-vrf.yang dist_yangmodels_DATA += yang/frr-route-types.yang dist_yangmodels_DATA += yang/frr-routing.yang @@ -86,3 +91,9 @@ endif if PATHD dist_yangmodels_DATA += yang/frr-pathd.yang endif + +CLEANFILES += \ + yang/*.c \ + yang/ietf/*.c \ + yang/confd/*.c \ + # diff --git a/zebra/connected.c b/zebra/connected.c index dd8fab5e4e..6f405ca1bb 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -29,7 +29,6 @@ #include "table.h" #include "log.h" #include "memory.h" -#include "zebra_memory.h" #include "vty.h" #include "zebra/debug.h" diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 79a5d148a6..9abed77fa6 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -1517,4 +1517,4 @@ FRR_MODULE_SETUP( .version = "0.0.1", .description = "Data plane plugin for FPM using netlink.", .init = fpm_nl_init, - ) +); diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 8bec256355..14d8ac442e 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -29,7 +29,6 @@ #include "ioctl.h" #include "connected.h" #include "memory.h" -#include "zebra_memory.h" #include "log.h" #include "vrf.h" #include "vty.h" diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 98bde4b3c0..af2c251607 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -44,7 +44,6 @@ #include "connected.h" #include "table.h" #include "memory.h" -#include "zebra_memory.h" #include "rib.h" #include "thread.h" #include "privs.h" diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c index 695cef1995..38729c8d38 100644 --- a/zebra/if_sysctl.c +++ b/zebra/if_sysctl.c @@ -28,7 +28,6 @@ #include "prefix.h" #include "connected.h" #include "memory.h" -#include "zebra_memory.h" #include "ioctl.h" #include "log.h" #include "interface.h" diff --git a/zebra/interface.c b/zebra/interface.c index 6373b4b200..3eeed9ac90 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -28,7 +28,6 @@ #include "prefix.h" #include "command.h" #include "memory.h" -#include "zebra_memory.h" #include "ioctl.h" #include "connected.h" #include "log.h" @@ -53,14 +52,14 @@ #include "zebra/zebra_errors.h" #include "zebra/zebra_evpn_mh.h" -DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information") +DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information"); #define ZEBRA_PTM_SUPPORT DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), - (vty, ifp)) + (vty, ifp)); DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), - (vty, ifp)) + (vty, ifp)); static void if_down_del_nbr_connected(struct interface *ifp); diff --git a/zebra/interface.h b/zebra/interface.h index 64569742b4..67eb1176b9 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -417,9 +417,9 @@ struct zebra_if { }; DECLARE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp), - (vty, ifp)) + (vty, ifp)); DECLARE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), - (vty, ifp)) + (vty, ifp)); #define IS_ZEBRA_IF_VRF(ifp) \ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VRF) diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 5352c6214d..28db2ad87d 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -34,7 +34,6 @@ #include "prefix.h" #include "command.h" #include "memory.h" -#include "zebra_memory.h" #include "stream.h" #include "ioctl.h" #include "connected.h" @@ -57,7 +56,7 @@ extern int irdp_sock; -DEFINE_MTYPE_STATIC(ZEBRA, IRDP_IF, "IRDP interface data") +DEFINE_MTYPE_STATIC(ZEBRA, IRDP_IF, "IRDP interface data"); #define IRDP_CONFIGED \ do { \ diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c index 936206641f..600fc3f2fc 100644 --- a/zebra/irdp_main.c +++ b/zebra/irdp_main.c @@ -42,7 +42,6 @@ #include "prefix.h" #include "command.h" #include "memory.h" -#include "zebra_memory.h" #include "stream.h" #include "ioctl.h" #include "connected.h" @@ -349,4 +348,5 @@ static int irdp_module_init(void) } FRR_MODULE_SETUP(.name = "zebra_irdp", .version = FRR_VERSION, - .description = "zebra IRDP module", .init = irdp_module_init, ) + .description = "zebra IRDP module", .init = irdp_module_init, +); diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 6134df9c41..7d67c42a79 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -54,7 +54,6 @@ #include "zclient.h" #include "lib_errors.h" -#include "zebra_memory.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index aa19b18089..e71e662458 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -29,7 +29,6 @@ #include "connected.h" #include "table.h" #include "memory.h" -#include "zebra_memory.h" #include "rib.h" #include "thread.h" #include "privs.h" @@ -159,7 +158,7 @@ extern uint32_t nl_rcvbufsize; extern struct zebra_privs_t zserv_privs; -DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers") +DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers"); size_t nl_batch_tx_bufsize; char *nl_batch_tx_buf; diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index adbdf54c1f..03884a9168 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -32,7 +32,6 @@ #include "sockunion.h" #include "connected.h" #include "memory.h" -#include "zebra_memory.h" #include "ioctl.h" #include "log.h" #include "table.h" diff --git a/zebra/main.c b/zebra/main.c index 55fd3244cb..3f75b222ba 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -26,7 +26,6 @@ #include "thread.h" #include "filter.h" #include "memory.h" -#include "zebra_memory.h" #include "prefix.h" #include "log.h" #include "plist.h" @@ -261,6 +260,7 @@ static const struct frr_yang_module_info *const zebra_yang_modules[] = { &frr_zebra_info, &frr_vrf_info, &frr_routing_info, + &frr_zebra_route_map_info, }; FRR_DAEMON_INFO( @@ -274,7 +274,8 @@ FRR_DAEMON_INFO( .privs = &zserv_privs, .yang_modules = zebra_yang_modules, - .n_yang_modules = array_size(zebra_yang_modules), ) + .n_yang_modules = array_size(zebra_yang_modules), +); /* Main startup routine. */ int main(int argc, char **argv) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index ac60d09ecc..9e675011ee 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -41,7 +41,6 @@ #include "zebra/debug.h" #include "zebra/router-id.h" #include "zebra/zapi_msg.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" diff --git a/zebra/rib.h b/zebra/rib.h index 86766b8175..e7676a1324 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -23,6 +23,7 @@ #define _ZEBRA_RIB_H #include "zebra.h" +#include "memory.h" #include "hook.h" #include "typesafe.h" #include "linklist.h" @@ -41,9 +42,13 @@ extern "C" { #endif +DECLARE_MGROUP(ZEBRA); + +DECLARE_MTYPE(RE); + enum rnh_type { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE }; -PREDECL_LIST(rnh_list) +PREDECL_LIST(rnh_list); /* Nexthop structure. */ struct rnh { @@ -82,7 +87,7 @@ struct rnh { #define DISTANCE_INFINITY 255 #define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */ -PREDECL_LIST(re_list) +PREDECL_LIST(re_list); struct opaque { uint16_t length; @@ -541,7 +546,7 @@ static inline void rib_tables_iter_cleanup(rib_tables_iter_t *iter) } DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason), - (rn, reason)) + (rn, reason)); /* * Access installed/fib nexthops, which may be a subset of the diff --git a/zebra/router-id.c b/zebra/router-id.c index ac21978ee8..3b556c92b5 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -29,7 +29,6 @@ #include "stream.h" #include "command.h" #include "memory.h" -#include "zebra_memory.h" #include "ioctl.h" #include "connected.h" #include "network.h" diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index fdeef2c88c..55e0775a8c 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -41,7 +41,6 @@ #include "connected.h" #include "table.h" #include "memory.h" -#include "zebra_memory.h" #include "rib.h" #include "thread.h" #include "privs.h" diff --git a/zebra/rtadv.c b/zebra/rtadv.c index c3add16c56..8ffb3870fa 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -23,7 +23,6 @@ #include <zebra.h> #include "memory.h" -#include "zebra_memory.h" #include "sockopt.h" #include "thread.h" #include "if.h" @@ -54,7 +53,7 @@ extern struct zebra_privs_t zserv_privs; #include "zebra/rtadv_clippy.c" #endif -DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix") +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix"); #ifdef OPEN_BSD #include <netinet/icmp6.h> @@ -71,8 +70,8 @@ DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix") #define ALLNODE "ff02::1" #define ALLROUTER "ff02::2" -DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS") -DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL") +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS"); +DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL"); /* Order is intentional. Matches RFC4191. This array is also used for command matching, so only modify with care. */ diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c index 01a97db8b3..74c6825ba1 100644 --- a/zebra/rtread_sysctl.c +++ b/zebra/rtread_sysctl.c @@ -24,7 +24,6 @@ #if !defined(GNU_LINUX) #include "memory.h" -#include "zebra_memory.h" #include "log.h" #include "vrf.h" diff --git a/zebra/sample_plugin.c b/zebra/sample_plugin.c index 464205f2f3..e54186bc18 100644 --- a/zebra/sample_plugin.c +++ b/zebra/sample_plugin.c @@ -130,4 +130,4 @@ FRR_MODULE_SETUP( .version = "0.0.1", .description = "Dataplane Sample Plugin", .init = module_init, - ) +); diff --git a/zebra/subdir.am b/zebra/subdir.am index f842a8c0f3..6a582f6901 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -88,7 +88,6 @@ zebra_zebra_SOURCES = \ zebra/zebra_evpn_neigh.c \ zebra/zebra_mlag.c \ zebra/zebra_mlag_vty.c \ - zebra/zebra_memory.c \ zebra/zebra_mpls.c \ zebra/zebra_mpls_netlink.c \ zebra/zebra_mpls_openbsd.c \ @@ -112,6 +111,8 @@ zebra_zebra_SOURCES = \ zebra/zebra_router.c \ zebra/zebra_rnh.c \ zebra/zebra_routemap.c \ + zebra/zebra_routemap_nb.c \ + zebra/zebra_routemap_nb_config.c \ zebra/zebra_srte.c \ zebra/zebra_vrf.c \ zebra/zebra_vty.c \ @@ -158,7 +159,6 @@ noinst_HEADERS += \ zebra/zebra_evpn_vxlan.h \ zebra/zebra_fpm_private.h \ zebra/zebra_l2.h \ - zebra/zebra_memory.h \ zebra/zebra_mlag.h \ zebra/zebra_mlag_vty.h \ zebra/zebra_mpls.h \ @@ -176,6 +176,7 @@ noinst_HEADERS += \ zebra/zebra_pw.h \ zebra/zebra_rnh.h \ zebra/zebra_routemap.h \ + zebra/zebra_routemap_nb.h \ zebra/zebra_router.h \ zebra/zebra_srte.h \ zebra/zebra_vrf.h \ @@ -193,7 +194,7 @@ zebra_zebra_irdp_la_SOURCES = \ zebra_zebra_irdp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c -zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99 +zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11 zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic zebra_zebra_snmp_la_LIBADD = lib/libfrrsnmp.la @@ -219,6 +220,7 @@ endif nodist_zebra_zebra_SOURCES = \ yang/frr-zebra.yang.c \ + yang/frr-zebra-route-map.yang.c \ # end zebra_zebra_cumulus_mlag_la_SOURCES = zebra/zebra_mlag_private.c diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 9f5adfa409..b482914418 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -38,7 +38,6 @@ #include "zebra/zebra_router.h" #include "zebra/rib.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/router-id.h" @@ -62,6 +61,8 @@ #include "zebra/zebra_opaque.h" #include "zebra/zebra_srte.h" +DEFINE_MTYPE_STATIC(ZEBRA, OPAQUE, "Opaque Data"); + static int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg); /* Encoding helpers -------------------------------------------------------- */ @@ -2076,6 +2077,11 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) } } +void zapi_opaque_free(struct opaque *opaque) +{ + XFREE(MTYPE_OPAQUE, opaque); +} + static void zread_route_del(ZAPI_HANDLER_ARGS) { struct stream *s; @@ -3344,6 +3350,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_NHG_ADD] = zread_nhg_add, [ZEBRA_NHG_DEL] = zread_nhg_del, [ZEBRA_ROUTE_NOTIFY_REQUEST] = zread_route_notify_request, + [ZEBRA_EVPN_REMOTE_NH_ADD] = zebra_evpn_proc_remote_nh, + [ZEBRA_EVPN_REMOTE_NH_DEL] = zebra_evpn_proc_remote_nh, }; /* diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 023b9f74a8..ca471f8d98 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -111,6 +111,8 @@ extern int zsend_client_close_notify(struct zserv *client, int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, uint32_t id, enum zapi_nhg_notify_owner note); +extern void zapi_opaque_free(struct opaque *opaque); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 4e63d08aca..18fe0a7e85 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -28,7 +28,6 @@ #include "lib/memory.h" #include "lib/queue.h" #include "lib/zebra.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_router.h" #include "zebra/zebra_dplane.h" #include "zebra/zebra_vxlan_private.h" @@ -39,10 +38,10 @@ #include "printfrr.h" /* Memory type for context blocks */ -DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx") -DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf") -DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider") -DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object") +DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx"); +DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf"); +DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider"); +DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object"); #ifndef AOK # define AOK 0 diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index 27a5a07e48..80e06d913d 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -44,7 +44,6 @@ #include "zebra/rt_netlink.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_l2.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index b36e8034b7..7bbe092d8c 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -34,7 +34,6 @@ #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/zebra_router.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_evpn.h" diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 5a28ee10c6..cabba707a0 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -41,7 +41,6 @@ #include "zebra/if_netlink.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_l2.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" @@ -3868,6 +3867,47 @@ static void zebra_evpn_mh_startup_delay_timer_start(const char *rc) } } +/***************************************************************************** + * Nexthop management: nexthops associated with Type-2 routes that have + * an ES as destination are consolidated by BGP into a per-VRF nh->rmac + * mapping which is the installed as a remote neigh/fdb entry with a + * dummy (type-1) prefix referencing it. + * This handling is needed because Type-2 routes with ES as dest use NHG + * that are setup using EAD routes (i.e. such NHGs do not include the + * RMAC info). + ****************************************************************************/ +void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + vrf_id_t vrf_id; + struct ipaddr nh; + struct ethaddr rmac; + struct prefix_evpn dummy_prefix; + + s = msg; + vrf_id = stream_getl(s); + stream_get(&nh, s, sizeof(nh)); + + memset(&dummy_prefix, 0, sizeof(dummy_prefix)); + dummy_prefix.family = AF_EVPN; + dummy_prefix.prefixlen = (sizeof(struct evpn_addr) * 8); + dummy_prefix.prefix.route_type = 1; /* XXX - fixup to type-1 def */ + + if (hdr->command == ZEBRA_EVPN_REMOTE_NH_ADD) { + stream_get(&rmac, s, sizeof(rmac)); + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("evpn remote nh %d %pIA rmac %pEA add", + vrf_id, &nh, &rmac); + zebra_vxlan_evpn_vrf_route_add(vrf_id, &rmac, &nh, + (struct prefix *)&dummy_prefix); + } else { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("evpn remote nh %d %pIA del", vrf_id, &nh); + zebra_vxlan_evpn_vrf_route_del(vrf_id, &nh, + (struct prefix *)&dummy_prefix); + } +} + /*****************************************************************************/ void zebra_evpn_mh_config_write(struct vty *vty) { diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h index 2361a70bff..8861e80cee 100644 --- a/zebra/zebra_evpn_mh.h +++ b/zebra/zebra_evpn_mh.h @@ -382,5 +382,6 @@ extern void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif, extern void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if); extern void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es, struct interface *ifp, bool bypass); +extern void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS); #endif /* _ZEBRA_EVPN_MH_H */ diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 0e31617c4f..d1b93dbe8a 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -34,7 +34,6 @@ #include "zebra/debug.h" #include "zebra/zebra_router.h" #include "zebra/rt.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_evpn.h" diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index 099ac1434b..5fe8934a82 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -37,7 +37,6 @@ #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_errors.h" -#include "zebra/zebra_memory.h" #include "fpm/fpm.h" #include "zebra_fpm_private.h" @@ -2046,4 +2045,5 @@ static int zebra_fpm_module_init(void) FRR_MODULE_SETUP(.name = "zebra_fpm", .version = FRR_VERSION, .description = "zebra FPM (Forwarding Plane Manager) module", - .init = zebra_fpm_module_init, ) + .init = zebra_fpm_module_init, +); diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 3583c5fbf4..c3fbff2723 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -38,7 +38,6 @@ #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/interface.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_vrf.h" #include "zebra/rt_netlink.h" #include "zebra/interface.h" diff --git a/zebra/zebra_memory.c b/zebra/zebra_memory.c deleted file mode 100644 index 17b52a2bcb..0000000000 --- a/zebra/zebra_memory.c +++ /dev/null @@ -1,33 +0,0 @@ -/* zebra memory type definitions - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga 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, or (at your option) any - * later version. - * - * Quagga 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 - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "zebra_memory.h" - -DEFINE_MGROUP(ZEBRA, "zebra") -DEFINE_MTYPE(ZEBRA, RE, "Route Entry") -DEFINE_MTYPE(ZEBRA, RIB_DEST, "RIB destination") -DEFINE_MTYPE(ZEBRA, ZVLAN, "VLAN") -DEFINE_MTYPE(ZEBRA, ZVLAN_BITMAP, "VLAN bitmap") -DEFINE_MTYPE(ZEBRA, OPAQUE, "Opaque Data") diff --git a/zebra/zebra_memory.h b/zebra/zebra_memory.h deleted file mode 100644 index 71901b765f..0000000000 --- a/zebra/zebra_memory.h +++ /dev/null @@ -1,41 +0,0 @@ -/* zebra memory type declarations - * - * Copyright (C) 2015 David Lamparter - * - * This file is part of Quagga. - * - * Quagga 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, or (at your option) any - * later version. - * - * Quagga 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 _QUAGGA_ZEBRA_MEMORY_H -#define _QUAGGA_ZEBRA_MEMORY_H - -#include "memory.h" - -#ifdef __cplusplus -extern "C" { -#endif - -DECLARE_MGROUP(ZEBRA) -DECLARE_MTYPE(ZEBRA_NS) -DECLARE_MTYPE(RE) -DECLARE_MTYPE(RIB_DEST) -DECLARE_MTYPE(OPAQUE) - -#ifdef __cplusplus -} -#endif - -#endif /* _QUAGGA_ZEBRA_MEMORY_H */ diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c index d8ed9b2a3a..3b0c75151b 100644 --- a/zebra/zebra_mlag.c +++ b/zebra/zebra_mlag.c @@ -29,7 +29,6 @@ #include "zebra/zebra_mlag.h" #include "zebra/zebra_mlag_vty.h" #include "zebra/zebra_router.h" -#include "zebra/zebra_memory.h" #include "zebra/zapi_msg.h" #include "zebra/debug.h" @@ -38,11 +37,11 @@ #endif DEFINE_HOOK(zebra_mlag_private_write_data, - (uint8_t *data, uint32_t len), (data, len)) -DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ()) -DEFINE_HOOK(zebra_mlag_private_open_channel, (), ()) -DEFINE_HOOK(zebra_mlag_private_close_channel, (), ()) -DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ()) + (uint8_t *data, uint32_t len), (data, len)); +DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ()); +DEFINE_HOOK(zebra_mlag_private_open_channel, (), ()); +DEFINE_HOOK(zebra_mlag_private_close_channel, (), ()); +DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ()); #define ZEBRA_MLAG_METADATA_LEN 4 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF @@ -659,7 +658,7 @@ void zebra_mlag_terminate(void) #ifdef HAVE_PROTOBUF_VERSION_3 -DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF") +DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF"); int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type) { diff --git a/zebra/zebra_mlag.h b/zebra/zebra_mlag.h index b195c75ea3..eb96a57d30 100644 --- a/zebra/zebra_mlag.h +++ b/zebra/zebra_mlag.h @@ -34,11 +34,11 @@ extern "C" { #define ZEBRA_MLAG_LEN_SIZE 4 DECLARE_HOOK(zebra_mlag_private_write_data, - (uint8_t *data, uint32_t len), (data, len)) -DECLARE_HOOK(zebra_mlag_private_monitor_state, (), ()) -DECLARE_HOOK(zebra_mlag_private_open_channel, (), ()) -DECLARE_HOOK(zebra_mlag_private_close_channel, (), ()) -DECLARE_HOOK(zebra_mlag_private_cleanup_data, (), ()) + (uint8_t *data, uint32_t len), (data, len)); +DECLARE_HOOK(zebra_mlag_private_monitor_state, (), ()); +DECLARE_HOOK(zebra_mlag_private_open_channel, (), ()); +DECLARE_HOOK(zebra_mlag_private_close_channel, (), ()); +DECLARE_HOOK(zebra_mlag_private_cleanup_data, (), ()); extern uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT]; extern uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT]; diff --git a/zebra/zebra_mlag_private.c b/zebra/zebra_mlag_private.c index 8a66d6de72..aaf93b4dc1 100644 --- a/zebra/zebra_mlag_private.c +++ b/zebra/zebra_mlag_private.c @@ -297,4 +297,4 @@ FRR_MODULE_SETUP( .version = FRR_VERSION, .description = "zebra Cumulus MLAG interface", .init = zebra_mlag_module_init, -) +); diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index dc49695019..c0c064cbc7 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -44,15 +44,14 @@ #include "zebra/zebra_router.h" #include "zebra/redistribute.h" #include "zebra/debug.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_srte.h" #include "zebra/zebra_errors.h" -DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object") -DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object") -DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object") +DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object"); +DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object"); +DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object"); int mpls_enabled; diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c index 1fc1faff67..90d4ee7ced 100644 --- a/zebra/zebra_nb.c +++ b/zebra/zebra_nb.c @@ -401,14 +401,24 @@ const struct frr_yang_module_info frr_zebra_info = { { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib", .cbs = { - .create = lib_vrf_zebra_ribs_rib_create, - .destroy = lib_vrf_zebra_ribs_rib_destroy, .get_next = lib_vrf_zebra_ribs_rib_get_next, .get_keys = lib_vrf_zebra_ribs_rib_get_keys, .lookup_entry = lib_vrf_zebra_ribs_rib_lookup_entry, } }, { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/afi-safi-name", + .cbs = { + .get_elem = lib_vrf_zebra_ribs_rib_afi_safi_name_get_elem, + } + }, + { + .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/table-id", + .cbs = { + .get_elem = lib_vrf_zebra_ribs_rib_table_id_get_elem, + } + }, + { .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route", .cbs = { .get_next = lib_vrf_zebra_ribs_rib_route_get_next, @@ -634,48 +644,6 @@ const struct frr_yang_module_info frr_zebra_info = { } }, { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv4-prefix-length", - .cbs = { - .modify = lib_route_map_entry_match_condition_ipv4_prefix_length_modify, - .destroy = lib_route_map_entry_match_condition_ipv4_prefix_length_destroy, - } - }, - { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv6-prefix-length", - .cbs = { - .modify = lib_route_map_entry_match_condition_ipv6_prefix_length_modify, - .destroy = lib_route_map_entry_match_condition_ipv6_prefix_length_destroy, - } - }, - { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-protocol", - .cbs = { - .modify = lib_route_map_entry_match_condition_source_protocol_modify, - .destroy = lib_route_map_entry_match_condition_source_protocol_destroy, - } - }, - { - .xpath = "/frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-instance", - .cbs = { - .modify = lib_route_map_entry_match_condition_source_instance_modify, - .destroy = lib_route_map_entry_match_condition_source_instance_destroy, - } - }, - { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v4", - .cbs = { - .modify = lib_route_map_entry_set_action_source_v4_modify, - .destroy = lib_route_map_entry_set_action_source_v4_destroy, - } - }, - { - .xpath = "/frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v6", - .cbs = { - .modify = lib_route_map_entry_set_action_source_v6_modify, - .destroy = lib_route_map_entry_set_action_source_v6_destroy, - } - }, - { .xpath = NULL, }, } diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h index e68b819767..95907059a8 100644 --- a/zebra/zebra_nb.h +++ b/zebra/zebra_nb.h @@ -109,30 +109,6 @@ int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args); int lib_interface_zebra_bandwidth_modify(struct nb_cb_modify_args *args); int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args); -int lib_route_map_entry_match_condition_ipv4_prefix_length_modify( - struct nb_cb_modify_args *args); -int lib_route_map_entry_match_condition_ipv4_prefix_length_destroy( - struct nb_cb_destroy_args *args); -int lib_route_map_entry_match_condition_ipv6_prefix_length_modify( - struct nb_cb_modify_args *args); -int lib_route_map_entry_match_condition_ipv6_prefix_length_destroy( - struct nb_cb_destroy_args *args); -int lib_route_map_entry_match_condition_source_protocol_modify( - struct nb_cb_modify_args *args); -int lib_route_map_entry_match_condition_source_protocol_destroy( - struct nb_cb_destroy_args *args); -int lib_route_map_entry_match_condition_source_instance_modify( - struct nb_cb_modify_args *args); -int lib_route_map_entry_match_condition_source_instance_destroy( - struct nb_cb_destroy_args *args); -int lib_route_map_entry_set_action_source_v4_modify( - struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_source_v4_destroy( - struct nb_cb_destroy_args *args); -int lib_route_map_entry_set_action_source_v6_modify( - struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_source_v6_destroy( - struct nb_cb_destroy_args *args); struct yang_data * lib_interface_zebra_state_up_count_get_elem(struct nb_cb_get_elem_args *args); struct yang_data * @@ -149,12 +125,14 @@ struct yang_data *lib_interface_zebra_state_remote_vtep_get_elem( struct nb_cb_get_elem_args *args); struct yang_data *lib_interface_zebra_state_mcast_group_get_elem( struct nb_cb_get_elem_args *args); -int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args); -int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args); const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args); const void * lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args); +struct yang_data * +lib_vrf_zebra_ribs_rib_afi_safi_name_get_elem(struct nb_cb_get_elem_args *args); +struct yang_data * +lib_vrf_zebra_ribs_rib_table_id_get_elem(struct nb_cb_get_elem_args *args); const void * lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args); @@ -201,19 +179,6 @@ lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_next( struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_keys( struct nb_cb_get_keys_args *args); -int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args); -int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args); -const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args); -int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args); -const void * -lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args); -const void * -lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args); -int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args); -const void * -lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args); -struct yang_data * -lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args); const void *lib_vrf_zebra_ribs_rib_route_route_entry_get_next( struct nb_cb_get_next_args *args); int lib_vrf_zebra_ribs_rib_route_route_entry_get_keys( diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c index ea2e20ed3b..6296f6f445 100644 --- a/zebra/zebra_nb_config.c +++ b/zebra/zebra_nb_config.c @@ -841,7 +841,6 @@ int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args) struct interface *ifp; struct prefix prefix; - ifp = nb_running_get_entry(args->dnode, NULL, true); // addr_family = yang_dnode_get_enum(dnode, "./address-family"); yang_dnode_get_prefix(&prefix, args->dnode, "./ip-prefix"); apply_mask(&prefix); @@ -864,6 +863,7 @@ int lib_interface_zebra_ip_addrs_create(struct nb_cb_create_args *args) case NB_EV_ABORT: break; case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); if (prefix.family == AF_INET) if_ip_address_install(ifp, &prefix, NULL, NULL); else if (prefix.family == AF_INET6) @@ -881,12 +881,15 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args) struct prefix prefix; struct connected *ifc; - ifp = nb_running_get_entry(args->dnode, NULL, true); yang_dnode_get_prefix(&prefix, args->dnode, "./ip-prefix"); apply_mask(&prefix); switch (args->event) { case NB_EV_VALIDATE: + ifp = nb_running_get_entry(args->dnode, NULL, false); + if (!ifp) + return NB_OK; + if (prefix.family == AF_INET) { /* Check current interface address. */ ifc = connected_check_ptp(ifp, &prefix, NULL); @@ -927,6 +930,7 @@ int lib_interface_zebra_ip_addrs_destroy(struct nb_cb_destroy_args *args) case NB_EV_ABORT: break; case NB_EV_APPLY: + ifp = nb_running_get_entry(args->dnode, NULL, true); if_ip_address_uinstall(ifp, &prefix); break; } @@ -1068,6 +1072,9 @@ int lib_interface_zebra_link_detect_destroy(struct nb_cb_destroy_args *args) */ int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args) { + if (args->event != NB_EV_APPLY) + return NB_OK; + struct interface *ifp; ifp = nb_running_get_entry(args->dnode, NULL, true); @@ -1079,6 +1086,9 @@ int lib_interface_zebra_shutdown_modify(struct nb_cb_modify_args *args) int lib_interface_zebra_shutdown_destroy(struct nb_cb_destroy_args *args) { + if (args->event != NB_EV_APPLY) + return NB_OK; + struct interface *ifp; ifp = nb_running_get_entry(args->dnode, NULL, true); @@ -1130,61 +1140,6 @@ int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib - */ -int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args) -{ - struct vrf *vrf; - afi_t afi; - safi_t safi; - struct zebra_vrf *zvrf; - struct zebra_router_table *zrt; - uint32_t table_id; - const char *afi_safi_name; - - vrf = nb_running_get_entry(args->dnode, NULL, false); - zvrf = vrf_info_lookup(vrf->vrf_id); - table_id = yang_dnode_get_uint32(args->dnode, "./table-id"); - if (!table_id) - table_id = zvrf->table_id; - - afi_safi_name = yang_dnode_get_string(args->dnode, "./afi-safi-name"); - yang_afi_safi_identity2value(afi_safi_name, &afi, &safi); - - zrt = zebra_router_find_zrt(zvrf, table_id, afi, safi); - - switch (args->event) { - case NB_EV_VALIDATE: - if (!zrt) { - snprintf(args->errmsg, args->errmsg_len, - "vrf %s table is not found.", vrf->name); - return NB_ERR_VALIDATION; - } - break; - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - - nb_running_set_entry(args->dnode, zrt); - - break; - } - - return NB_OK; -} - -int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args) -{ - if (args->event != NB_EV_APPLY) - return NB_OK; - - nb_running_unset_entry(args->dnode); - - return NB_OK; -} - -/* * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/l3vni-id */ int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args) @@ -1263,9 +1218,6 @@ int lib_vrf_zebra_l3vni_id_modify(struct nb_cb_modify_args *args) return NB_ERR; } - /* Mark as having FRR configuration */ - vrf_set_user_cfged(vrf); - break; } @@ -1313,10 +1265,6 @@ int lib_vrf_zebra_l3vni_id_destroy(struct nb_cb_destroy_args *args) return NB_ERR; } - /* If no other FRR config for this VRF, mark accordingly. */ - if (!zebra_vrf_has_config(zvrf)) - vrf_reset_user_cfged(vrf); - break; } @@ -1339,323 +1287,3 @@ int lib_vrf_zebra_prefix_only_modify(struct nb_cb_modify_args *args) return NB_OK; } - -/* - * XPath: - * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv4-prefix-length - */ -int lib_route_map_entry_match_condition_ipv4_prefix_length_modify( - struct nb_cb_modify_args *args) -{ - struct routemap_hook_context *rhc; - const char *length; - int condition, rv; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - /* Add configuration. */ - rhc = nb_running_get_entry(args->dnode, NULL, true); - length = yang_dnode_get_string(args->dnode, NULL); - condition = - yang_dnode_get_enum(args->dnode, "../frr-route-map:condition"); - - /* Set destroy information. */ - switch (condition) { - case 100: /* ipv4-prefix-length */ - rhc->rhc_rule = "ip address prefix-len"; - break; - - case 102: /* ipv4-next-hop-prefix-length */ - rhc->rhc_rule = "ip next-hop prefix-len"; - break; - } - rhc->rhc_mhook = generic_match_delete; - rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; - - rv = generic_match_add(NULL, rhc->rhc_rmi, rhc->rhc_rule, length, - RMAP_EVENT_MATCH_ADDED); - if (rv != CMD_SUCCESS) { - rhc->rhc_mhook = NULL; - return NB_ERR_INCONSISTENCY; - } - - return NB_OK; -} - -int lib_route_map_entry_match_condition_ipv4_prefix_length_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_match_destroy(args); -} - -/* - * XPath: - * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:ipv6-prefix-length - */ -int lib_route_map_entry_match_condition_ipv6_prefix_length_modify( - struct nb_cb_modify_args *args) -{ - struct routemap_hook_context *rhc; - const char *length; - int rv; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - /* Add configuration. */ - rhc = nb_running_get_entry(args->dnode, NULL, true); - length = yang_dnode_get_string(args->dnode, NULL); - - /* Set destroy information. */ - rhc->rhc_mhook = generic_match_delete; - rhc->rhc_rule = "ipv6 address prefix-len"; - rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; - - rv = generic_match_add(NULL, rhc->rhc_rmi, "ipv6 address prefix-len", - length, RMAP_EVENT_MATCH_ADDED); - if (rv != CMD_SUCCESS) { - rhc->rhc_mhook = NULL; - return NB_ERR_INCONSISTENCY; - } - - return NB_OK; -} - -int lib_route_map_entry_match_condition_ipv6_prefix_length_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_match_destroy(args); -} - -/* - * XPath: - * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-protocol - */ -int lib_route_map_entry_match_condition_source_protocol_modify( - struct nb_cb_modify_args *args) -{ - struct routemap_hook_context *rhc; - const char *type; - int rv; - - switch (args->event) { - case NB_EV_VALIDATE: - type = yang_dnode_get_string(args->dnode, NULL); - if (proto_name2num(type) == -1) { - snprintf(args->errmsg, args->errmsg_len, - "invalid protocol: %s", type); - return NB_ERR_VALIDATION; - } - return NB_OK; - case NB_EV_PREPARE: - case NB_EV_ABORT: - return NB_OK; - case NB_EV_APPLY: - /* NOTHING */ - break; - } - - /* Add configuration. */ - rhc = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_string(args->dnode, NULL); - - /* Set destroy information. */ - rhc->rhc_mhook = generic_match_delete; - rhc->rhc_rule = "source-protocol"; - rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; - - rv = generic_match_add(NULL, rhc->rhc_rmi, "source-protocol", type, - RMAP_EVENT_MATCH_ADDED); - if (rv != CMD_SUCCESS) { - rhc->rhc_mhook = NULL; - return NB_ERR_INCONSISTENCY; - } - - return NB_OK; -} - -int lib_route_map_entry_match_condition_source_protocol_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_match_destroy(args); -} - -/* - * XPath: - * /frr-route-map:lib/route-map/entry/match-condition/frr-zebra:source-instance - */ -int lib_route_map_entry_match_condition_source_instance_modify( - struct nb_cb_modify_args *args) -{ - struct routemap_hook_context *rhc; - const char *type; - int rv; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - /* Add configuration. */ - rhc = nb_running_get_entry(args->dnode, NULL, true); - type = yang_dnode_get_string(args->dnode, NULL); - - /* Set destroy information. */ - rhc->rhc_mhook = generic_match_delete; - rhc->rhc_rule = "source-instance"; - rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; - - rv = generic_match_add(NULL, rhc->rhc_rmi, "source-instance", type, - RMAP_EVENT_MATCH_ADDED); - if (rv != CMD_SUCCESS) { - rhc->rhc_mhook = NULL; - return NB_ERR_INCONSISTENCY; - } - - return NB_OK; -} - -int lib_route_map_entry_match_condition_source_instance_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_match_destroy(args); -} - -/* - * XPath: /frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v4 - */ -int lib_route_map_entry_set_action_source_v4_modify( - struct nb_cb_modify_args *args) -{ - struct routemap_hook_context *rhc; - struct interface *pif = NULL; - const char *source; - struct vrf *vrf; - struct prefix p; - int rv; - - switch (args->event) { - case NB_EV_VALIDATE: - memset(&p, 0, sizeof(p)); - yang_dnode_get_ipv4p(&p, args->dnode, NULL); - if (zebra_check_addr(&p) == 0) { - snprintf(args->errmsg, args->errmsg_len, - "invalid IPv4 address: %s", - yang_dnode_get_string(args->dnode, NULL)); - return NB_ERR_VALIDATION; - } - - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - pif = if_lookup_exact_address(&p.u.prefix4, AF_INET, - vrf->vrf_id); - if (pif != NULL) - break; - } - /* - * On startup the local address *may* not have come up - * yet. We need to allow startup configuration of - * set src or we are fudged. Log it for future fun - */ - if (pif == NULL) - zlog_warn("set src %pI4 is not a local address", - &p.u.prefix4); - return NB_OK; - case NB_EV_PREPARE: - case NB_EV_ABORT: - return NB_OK; - case NB_EV_APPLY: - /* NOTHING */ - break; - } - - /* Add configuration. */ - rhc = nb_running_get_entry(args->dnode, NULL, true); - source = yang_dnode_get_string(args->dnode, NULL); - - /* Set destroy information. */ - rhc->rhc_shook = generic_set_delete; - rhc->rhc_rule = "src"; - - rv = generic_set_add(NULL, rhc->rhc_rmi, "src", source); - if (rv != CMD_SUCCESS) { - rhc->rhc_shook = NULL; - return NB_ERR_INCONSISTENCY; - } - - return NB_OK; -} - -int lib_route_map_entry_set_action_source_v4_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_set_destroy(args); -} - -/* - * XPath: /frr-route-map:lib/route-map/entry/set-action/frr-zebra:source-v6 - */ -int lib_route_map_entry_set_action_source_v6_modify( - struct nb_cb_modify_args *args) -{ - struct routemap_hook_context *rhc; - struct interface *pif = NULL; - const char *source; - struct vrf *vrf; - struct prefix p; - int rv; - - switch (args->event) { - case NB_EV_VALIDATE: - memset(&p, 0, sizeof(p)); - yang_dnode_get_ipv6p(&p, args->dnode, NULL); - if (zebra_check_addr(&p) == 0) { - snprintf(args->errmsg, args->errmsg_len, - "invalid IPv6 address: %s", - yang_dnode_get_string(args->dnode, NULL)); - return NB_ERR_VALIDATION; - } - - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - pif = if_lookup_exact_address(&p.u.prefix6, AF_INET6, - vrf->vrf_id); - if (pif != NULL) - break; - } - /* - * On startup the local address *may* not have come up - * yet. We need to allow startup configuration of - * set src or we are fudged. Log it for future fun - */ - if (pif == NULL) - zlog_warn("set src %pI6 is not a local address", - &p.u.prefix6); - return NB_OK; - case NB_EV_PREPARE: - case NB_EV_ABORT: - return NB_OK; - case NB_EV_APPLY: - /* NOTHING */ - break; - } - - /* Add configuration. */ - rhc = nb_running_get_entry(args->dnode, NULL, true); - source = yang_dnode_get_string(args->dnode, NULL); - - /* Set destroy information. */ - rhc->rhc_shook = generic_set_delete; - rhc->rhc_rule = "src"; - - rv = generic_set_add(NULL, rhc->rhc_rmi, "src", source); - if (rv != CMD_SUCCESS) { - rhc->rhc_shook = NULL; - return NB_ERR_INCONSISTENCY; - } - - return NB_OK; -} - -int lib_route_map_entry_set_action_source_v6_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_set_destroy(args); -} diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c index 21c89f64ed..a9cb096aee 100644 --- a/zebra/zebra_nb_state.c +++ b/zebra/zebra_nb_state.c @@ -214,6 +214,29 @@ lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args) } /* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/afi-safi-name + */ +struct yang_data * +lib_vrf_zebra_ribs_rib_afi_safi_name_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct zebra_router_table *zrt = args->list_entry; + + return yang_data_new_string(args->xpath, + yang_afi_safi_value2identity(zrt->afi, zrt->safi)); +} + +/* + * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/table-id + */ +struct yang_data * +lib_vrf_zebra_ribs_rib_table_id_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct zebra_router_table *zrt = args->list_entry; + + return yang_data_new_uint32(args->xpath, zrt->tableid); +} + +/* * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route */ const void * diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index ee2dc7a0ed..3e89df68fd 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -37,7 +37,6 @@ #include "lib_errors.h" #include "zebra_router.h" -#include "zebra_memory.h" #endif /* defined(HAVE_NETLINK) */ #include "zebra_netns_notify.h" @@ -53,7 +52,7 @@ #define ZEBRA_NS_POLLING_INTERVAL_MSEC 1000 #define ZEBRA_NS_POLLING_MAX_RETRIES 200 -DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo") +DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo"); static struct thread *zebra_netns_notify_current; struct zebra_netns_info { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 9246283fdf..12ed024a66 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -36,7 +36,6 @@ #include "zebra/zebra_nhg_private.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_routemap.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_srte.h" #include "zebra/zserv.h" #include "zebra/rt.h" diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index e9ff3fcc08..27b8a3ea47 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -28,7 +28,6 @@ #include "zebra_ns.h" #include "zebra_vrf.h" -#include "zebra_memory.h" #include "rt.h" #include "zebra_vxlan.h" #include "debug.h" @@ -41,7 +40,7 @@ extern struct zebra_privs_t zserv_privs; -DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space") +DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_NS, "Zebra Name Space"); static struct zebra_ns *dzns; diff --git a/zebra/zebra_opaque.c b/zebra/zebra_opaque.c index 1d59e0ab34..244f16302b 100644 --- a/zebra/zebra_opaque.c +++ b/zebra/zebra_opaque.c @@ -24,7 +24,6 @@ #include "lib/stream.h" #include "zebra/debug.h" #include "zebra/zserv.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_opaque.h" /* Mem type */ diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 92a7a0ba3a..c4004842e6 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -30,12 +30,11 @@ #include "zebra/zebra_pbr.h" #include "zebra/rt.h" #include "zebra/zapi_msg.h" -#include "zebra/zebra_memory.h" #include "zebra/zserv.h" #include "zebra/debug.h" /* definitions */ -DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list") +DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list"); /* definitions */ static const struct message ipset_type_msg[] = { @@ -128,12 +127,12 @@ static const struct message fragment_value_str[] = { DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat, (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts, uint64_t *bytes), - (ipset, pkts, bytes)) + (ipset, pkts, bytes)); DEFINE_HOOK(zebra_pbr_iptable_get_stat, (struct zebra_pbr_iptable *iptable, uint64_t *pkts, uint64_t *bytes), - (iptable, pkts, bytes)) + (iptable, pkts, bytes)); DEFINE_HOOK(zebra_pbr_iptable_update, (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable)); diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index ef93033661..2e9658e7e5 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -249,11 +249,11 @@ size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len, DECLARE_HOOK(zebra_pbr_ipset_entry_get_stat, (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts, uint64_t *bytes), - (ipset, pkts, bytes)) + (ipset, pkts, bytes)); DECLARE_HOOK(zebra_pbr_iptable_get_stat, (struct zebra_pbr_iptable *iptable, uint64_t *pkts, uint64_t *bytes), - (iptable, pkts, bytes)) + (iptable, pkts, bytes)); DECLARE_HOOK(zebra_pbr_iptable_update, (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable)); diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 1e7b38086b..bea855d1af 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -1167,8 +1167,6 @@ void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp) #else /* HAVE_BFDD */ -#include "zebra/zebra_memory.h" - /* * Data structures. */ diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c index eabc2e005e..537d69fbca 100644 --- a/zebra/zebra_ptm_redistribute.c +++ b/zebra/zebra_ptm_redistribute.c @@ -26,7 +26,6 @@ #include "zebra/zapi_msg.h" #include "zebra/zebra_ptm.h" #include "zebra/zebra_ptm_redistribute.h" -#include "zebra/zebra_memory.h" static int zsend_interface_bfd_update(int cmd, struct zserv *client, struct interface *ifp, struct prefix *dp, diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index ecae021dba..5afb3e5926 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -35,12 +35,12 @@ #include "zebra/zebra_vrf.h" #include "zebra/zebra_pw.h" -DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire") +DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire"); -DEFINE_QOBJ_TYPE(zebra_pw) +DEFINE_QOBJ_TYPE(zebra_pw); -DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) -DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) +DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw)); +DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)); #define MPLS_NO_LABEL MPLS_INVALID_LABEL diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index 7b13c7e16b..0da8203802 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -53,9 +53,9 @@ struct zebra_pw { struct zserv *client; struct rnh *rnh; struct thread *install_retry_timer; - QOBJ_FIELDS + QOBJ_FIELDS; }; -DECLARE_QOBJ_TYPE(zebra_pw) +DECLARE_QOBJ_TYPE(zebra_pw); RB_HEAD(zebra_pw_head, zebra_pw); RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare); @@ -63,8 +63,8 @@ RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare); RB_HEAD(zebra_static_pw_head, zebra_pw); RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare); -DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw)) -DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)) +DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw)); +DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw)); struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname, uint8_t protocol, struct zserv *client); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index bc3c68638d..ffe4be8557 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -49,7 +49,6 @@ #include "zebra/rt.h" #include "zebra/zapi_msg.h" #include "zebra/zebra_errors.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_rnh.h" #include "zebra/zebra_routemap.h" @@ -58,6 +57,10 @@ #include "zebra/zapi_msg.h" #include "zebra/zebra_dplane.h" +DEFINE_MGROUP(ZEBRA, "zebra"); + +DEFINE_MTYPE(ZEBRA, RE, "Route Entry"); +DEFINE_MTYPE_STATIC(ZEBRA, RIB_DEST, "RIB destination"); DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object"); /* @@ -68,7 +71,7 @@ static struct thread *t_dplane; static struct dplane_ctx_q rib_dplane_q; DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason), - (rn, reason)) + (rn, reason)); /* Should we allow non Quagga processes to delete our routes */ extern int allow_delete; @@ -800,6 +803,23 @@ int rib_gc_dest(struct route_node *rn) return 1; } +void zebra_rtable_node_cleanup(struct route_table *table, + struct route_node *node) +{ + struct route_entry *re, *next; + + RNODE_FOREACH_RE_SAFE (node, re, next) { + rib_unlink(node, re); + } + + if (node->info) { + rib_dest_t *dest = node->info; + + rnh_list_fini(&dest->nht); + XFREE(MTYPE_RIB_DEST, node->info); + } +} + static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, struct route_entry *new) { @@ -2698,7 +2718,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) nexthops_free(re->fib_ng.nexthop); - XFREE(MTYPE_OPAQUE, re->opaque); + zapi_opaque_free(re->opaque); XFREE(MTYPE_RE, re); } diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 48e2bafe44..3b0ef71987 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -48,10 +48,9 @@ #include "zebra/zebra_routemap.h" #include "zebra/zebra_srte.h" #include "zebra/interface.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_errors.h" -DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object") +DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object"); static void free_state(vrf_id_t vrf_id, struct route_entry *re, struct route_node *rn); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 17a9bf97f9..6a42c682ad 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -21,7 +21,6 @@ #include <zebra.h> #include "memory.h" -#include "zebra_memory.h" #include "prefix.h" #include "rib.h" #include "vty.h" @@ -358,12 +357,15 @@ DEFPY_YANG( "Match prefix length of IP address\n" "Prefix length\n") { - const char *xpath = "./match-condition[condition='ipv4-prefix-length']"; + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/frr-zebra:ipv4-prefix-length", xpath); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", + xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); return nb_cli_apply_changes(vty, NULL); @@ -379,7 +381,8 @@ DEFPY_YANG( "Match prefix length of IP address\n" "Prefix length\n") { - const char *xpath = "./match-condition[condition='ipv4-prefix-length']"; + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -395,12 +398,15 @@ DEFPY_YANG( "Match prefix length of IPv6 address\n" "Prefix length\n") { - const char *xpath = "./match-condition[condition='ipv6-prefix-length']"; + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/frr-zebra:ipv6-prefix-length", xpath); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length", + xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); return nb_cli_apply_changes(vty, NULL); @@ -416,7 +422,8 @@ DEFPY_YANG( "Match prefix length of IPv6 address\n" "Prefix length\n") { - const char *xpath = "./match-condition[condition='ipv6-prefix-length']"; + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -433,12 +440,14 @@ DEFPY_YANG( "Prefix length\n") { const char *xpath = - "./match-condition[condition='ipv4-next-hop-prefix-length']"; + "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); - snprintf(xpath_value, sizeof(xpath_value), - "%s/frr-zebra:ipv4-prefix-length", xpath); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", + xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); return nb_cli_apply_changes(vty, NULL); @@ -455,7 +464,7 @@ DEFPY_YANG( "Prefix length\n") { const char *xpath = - "./match-condition[condition='ipv4-next-hop-prefix-length']"; + "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -469,12 +478,14 @@ DEFPY_YANG( "Match protocol via which the route was learnt\n" FRR_REDIST_HELP_STR_ZEBRA) { - const char *xpath = "./match-condition[condition='source-protocol']"; + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-protocol']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); snprintf(xpath_value, sizeof(xpath_value), - "%s/frr-zebra:source-protocol", xpath); + "%s/rmap-match-condition/frr-zebra-route-map:source-protocol", + xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto); return nb_cli_apply_changes(vty, NULL); @@ -488,7 +499,8 @@ DEFPY_YANG( "Match protocol via which the route was learnt\n" FRR_REDIST_HELP_STR_ZEBRA) { - const char *xpath = "./match-condition[condition='source-protocol']"; + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-protocol']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -502,12 +514,14 @@ DEFPY_YANG( "Match the protocol's instance number\n" "The instance number\n") { - const char *xpath = "./match-condition[condition='source-instance']"; + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-instance']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); snprintf(xpath_value, sizeof(xpath_value), - "%s/frr-zebra:source-instance", xpath); + "%s/rmap-match-condition/frr-zebra-route-map:source-instance", + xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str); return nb_cli_apply_changes(vty, NULL); @@ -520,7 +534,8 @@ DEFPY_YANG( "Match the protocol's instance number\n" "The instance number\n") { - const char *xpath = "./match-condition[condition='source-instance']"; + const char *xpath = + "./match-condition[condition='frr-zebra-route-map:source-instance']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -537,18 +552,23 @@ DEFPY_YANG( "IPv4 src address\n" "IPv6 src address\n") { - const char *xpath = "./set-action[action='source']"; + const char *xpath = + "./set-action[action='frr-zebra-route-map:src-address']"; char xpath_value[XPATH_MAXLEN]; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); if (addrv4_str) { - snprintf(xpath_value, sizeof(xpath_value), - "%s/frr-zebra:source-v4", xpath); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-zebra-route-map:ipv4-src-address", + xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addrv4_str); } else { - snprintf(xpath_value, sizeof(xpath_value), - "%s/frr-zebra:source-v6", xpath); + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-zebra-route-map:ipv6-src-address", + xpath); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, addrv6_str); } @@ -565,14 +585,15 @@ DEFPY_YANG( "IPv4 address\n" "IPv6 address\n") { - const char *xpath = "./set-action[action='source']"; + const char *xpath = + "./set-action[action='frr-zebra-route-map:src-address']"; nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } -DEFUN (zebra_route_map_timer, +DEFUN_YANG (zebra_route_map_timer, zebra_route_map_timer_cmd, "zebra route-map delay-timer (0-600)", ZEBRA_STR @@ -589,7 +610,7 @@ DEFUN (zebra_route_map_timer, return (CMD_SUCCESS); } -DEFUN (no_zebra_route_map_timer, +DEFUN_YANG (no_zebra_route_map_timer, no_zebra_route_map_timer_cmd, "no zebra route-map delay-timer [(0-600)]", NO_STR diff --git a/zebra/zebra_routemap.h b/zebra/zebra_routemap.h index c016d95875..3f58e14e10 100644 --- a/zebra/zebra_routemap.h +++ b/zebra/zebra_routemap.h @@ -55,4 +55,6 @@ zebra_nht_route_map_check(afi_t afi, int client_proto, const struct prefix *p, #endif extern void zebra_routemap_finish(void); + +extern const struct frr_yang_module_info frr_zebra_route_map_info; #endif diff --git a/zebra/zebra_routemap_nb.c b/zebra/zebra_routemap_nb.c new file mode 100644 index 0000000000..c82c34dd53 --- /dev/null +++ b/zebra/zebra_routemap_nb.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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 "northbound.h" +#include "libfrr.h" +#include "zebra_routemap_nb.h" + +/* clang-format off */ +const struct frr_yang_module_info frr_zebra_route_map_info = { + .name = "frr-zebra-route-map", + .nodes = { + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_ipv4_prefix_length_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_ipv4_prefix_length_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_ipv6_prefix_length_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_ipv6_prefix_length_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-zebra-route-map:source-instance", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_source_instance_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_source_instance_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-zebra-route-map:source-protocol", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-zebra-route-map:ipv4-src-address", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_ipv4_src_address_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_ipv4_src_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-zebra-route-map:ipv6-src-address", + .cbs = { + .modify = lib_route_map_entry_set_action_rmap_set_action_ipv6_src_address_modify, + .destroy = lib_route_map_entry_set_action_rmap_set_action_ipv6_src_address_destroy, + } + }, + { + .xpath = NULL, + }, + } +}; diff --git a/zebra/zebra_routemap_nb.h b/zebra/zebra_routemap_nb.h new file mode 100644 index 0000000000..a43f2b2ae9 --- /dev/null +++ b/zebra/zebra_routemap_nb.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 Vmware + * Sarita Patra + * + * 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_ZEBRA_ROUTEMAP_NB_H_ +#define _FRR_ZEBRA_ROUTEMAP_NB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* prototypes */ +int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_prefix_length_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_prefix_length_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_ipv6_prefix_length_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_ipv6_prefix_length_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_source_instance_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_source_instance_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv4_src_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv4_src_address_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv6_src_address_modify(struct nb_cb_modify_args *args); +int lib_route_map_entry_set_action_rmap_set_action_ipv6_src_address_destroy(struct nb_cb_destroy_args *args); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/zebra/zebra_routemap_nb_config.c b/zebra/zebra_routemap_nb_config.c new file mode 100644 index 0000000000..8f5660610f --- /dev/null +++ b/zebra/zebra_routemap_nb_config.c @@ -0,0 +1,396 @@ +#include <zebra.h> + +#include "lib/command.h" +#include "lib/log.h" +#include "lib/northbound.h" +#include "lib/routemap.h" +#include "zebra/rib.h" +#include "zebra/zebra_routemap_nb.h" + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_ipv4_prefix_length_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *length; + int rv; + const char *condition; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + length = yang_dnode_get_string(args->dnode, NULL); + condition = yang_dnode_get_string(args->dnode, + "../../frr-route-map:condition"); + + if (IS_MATCH_IPv4_PREFIX_LEN(condition)) + rhc->rhc_rule = "ip address prefix-len"; + else if (IS_MATCH_IPv4_NH_PREFIX_LEN(condition)) + rhc->rhc_rule = "ip next-hop prefix-len"; + + rhc->rhc_mhook = generic_match_delete; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = generic_match_add(rhc->rhc_rmi, rhc->rhc_rule, + length, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_ipv4_prefix_length_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_ipv6_prefix_length_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *length; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + length = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = generic_match_delete; + rhc->rhc_rule = "ipv6 address prefix-len"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = generic_match_add(rhc->rhc_rmi, "ipv6 address prefix-len", + length, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_ipv6_prefix_length_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; + +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-zebra-route-map:source-instance + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_source_instance_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = generic_match_delete; + rhc->rhc_rule = "source-instance"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = generic_match_add(rhc->rhc_rmi, "source-instance", + type, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_source_instance_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-zebra-route-map:source-protocol + */ +int +lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *type; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + type = yang_dnode_get_string(args->dnode, NULL); + if (proto_name2num(type) == -1) { + zlog_warn("%s: invalid protocol: %s", __func__, type); + return NB_ERR_VALIDATION; + } + return NB_OK; + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + type = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = generic_match_delete; + rhc->rhc_rule = "source-protocol"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + rv = generic_match_add(rhc->rhc_rmi, "source-protocol", type, + RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +int +lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-zebra-route-map:ipv4-src-address + */ +int +lib_route_map_entry_set_action_rmap_set_action_ipv4_src_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + struct interface *pif = NULL; + const char *source; + struct vrf *vrf; + struct prefix p; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + memset(&p, 0, sizeof(p)); + yang_dnode_get_ipv4p(&p, args->dnode, NULL); + if (zebra_check_addr(&p) == 0) { + zlog_warn("%s: invalid IPv4 address: %s", __func__, + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + + RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) { + pif = if_lookup_exact_address(&p.u.prefix4, AF_INET, + vrf->vrf_id); + if (pif != NULL) + break; + } + if (pif == NULL) { + zlog_warn("%s: is not a local address: %s", __func__, + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + source = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "src"; + + rv = generic_set_add(rhc->rhc_rmi, "src", source, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_ipv4_src_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-zebra-route-map:ipv6-src-address + */ +int +lib_route_map_entry_set_action_rmap_set_action_ipv6_src_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + struct interface *pif = NULL; + const char *source; + struct vrf *vrf; + struct prefix p; + int rv; + + switch (args->event) { + case NB_EV_VALIDATE: + memset(&p, 0, sizeof(p)); + yang_dnode_get_ipv6p(&p, args->dnode, NULL); + if (zebra_check_addr(&p) == 0) { + zlog_warn("%s: invalid IPv6 address: %s", __func__, + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + + RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) { + pif = if_lookup_exact_address(&p.u.prefix6, AF_INET6, + vrf->vrf_id); + if (pif != NULL) + break; + } + if (pif == NULL) { + zlog_warn("%s: is not a local address: %s", __func__, + yang_dnode_get_string(args->dnode, NULL)); + return NB_ERR_VALIDATION; + } + return NB_OK; + case NB_EV_PREPARE: + case NB_EV_ABORT: + return NB_OK; + case NB_EV_APPLY: + /* NOTHING */ + break; + } + + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + source = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_shook = generic_set_delete; + rhc->rhc_rule = "src"; + + rv = generic_set_add(rhc->rhc_rmi, "src", source, + args->errmsg, args->errmsg_len); + if (rv != CMD_SUCCESS) { + rhc->rhc_shook = NULL; + return NB_ERR_INCONSISTENCY; + } + + return NB_OK; +} + +int +lib_route_map_entry_set_action_rmap_set_action_ipv6_src_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 249ec38a69..5a00f3155d 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -25,14 +25,14 @@ #include "lib/frratomic.h" #include "zebra_router.h" -#include "zebra_memory.h" #include "zebra_pbr.h" #include "zebra_vxlan.h" #include "zebra_mlag.h" #include "zebra_nhg.h" #include "debug.h" -DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info") +DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info"); +DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_RT_TABLE, "Zebra VRF table"); struct zebra_router zrouter = { .multipath_num = MULTIPATH_NUM, @@ -121,7 +121,7 @@ struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf, if (zrt) return zrt->table; - zrt = XCALLOC(MTYPE_ZEBRA_NS, sizeof(*zrt)); + zrt = XCALLOC(MTYPE_ZEBRA_RT_TABLE, sizeof(*zrt)); zrt->tableid = tableid; zrt->afi = afi; zrt->safi = safi; @@ -185,7 +185,7 @@ static void zebra_router_free_table(struct zebra_router_table *zrt) RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt); XFREE(MTYPE_RIB_TABLE_INFO, table_info); - XFREE(MTYPE_ZEBRA_NS, zrt); + XFREE(MTYPE_ZEBRA_RT_TABLE, zrt); } void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid, diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 89b8238c29..3e08d83724 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -566,4 +566,5 @@ static int zebra_snmp_module_init(void) FRR_MODULE_SETUP(.name = "zebra_snmp", .version = FRR_VERSION, .description = "zebra AgentX SNMP module", - .init = zebra_snmp_module_init, ) + .init = zebra_snmp_module_init, +); diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c index d6043534e3..98158ecc12 100644 --- a/zebra/zebra_srte.c +++ b/zebra/zebra_srte.c @@ -24,12 +24,11 @@ #include "lib/lib_errors.h" #include "zebra/zebra_srte.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_rnh.h" #include "zebra/zapi_msg.h" -DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy") +DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy"); static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy); diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index be4fb29aae..212557423b 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -36,7 +36,6 @@ #include "zebra/zebra_vrf.h" #include "zebra/zebra_rnh.h" #include "zebra/router-id.h" -#include "zebra/zebra_memory.h" #include "zebra/interface.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_vxlan.h" @@ -48,8 +47,8 @@ static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, static void zebra_rnhtable_node_cleanup(struct route_table *table, struct route_node *node); -DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF") -DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table") +DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF"); +DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table"); /* VRF information update. */ static void zebra_vrf_add_update(struct zebra_vrf *zvrf) @@ -339,20 +338,6 @@ static int zebra_vrf_update(struct vrf *vrf) return 0; } - -/* Return if this VRF has any FRR configuration or not. - * IMPORTANT: This function needs to be updated when additional configuration - * is added for a VRF. - */ -int zebra_vrf_has_config(struct zebra_vrf *zvrf) -{ - /* EVPN L3-VNI? */ - if (zvrf->l3vni) - return 1; - - return 0; -} - /* Lookup the routing table in a VRF based on both VRF-Id and table-id. * NOTE: Table-id is relevant on two modes: * - case VRF backend is default : on default VRF only @@ -413,23 +398,6 @@ done: return table; } -void zebra_rtable_node_cleanup(struct route_table *table, - struct route_node *node) -{ - struct route_entry *re, *next; - - RNODE_FOREACH_RE_SAFE (node, re, next) { - rib_unlink(node, re); - } - - if (node->info) { - rib_dest_t *dest = node->info; - - rnh_list_fini(&dest->nht); - XFREE(MTYPE_RIB_DEST, node->info); - } -} - static void zebra_rnhtable_node_cleanup(struct route_table *table, struct route_node *node) { diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 910d192317..000b5a7238 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -238,7 +238,7 @@ 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) + zvrf_other_table_compare_func); extern struct route_table * zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi, vrf_id_t vrf_id, @@ -254,7 +254,6 @@ extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *); extern struct zebra_vrf *zebra_vrf_alloc(void); extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t); -extern int zebra_vrf_has_config(struct zebra_vrf *zvrf); extern void zebra_vrf_init(void); extern void zebra_rtable_node_cleanup(struct route_table *table, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 3349c18204..283a3e52d6 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -21,7 +21,6 @@ #include <zebra.h> #include "memory.h" -#include "zebra_memory.h" #include "if.h" #include "prefix.h" #include "command.h" @@ -2565,10 +2564,8 @@ DEFUN (default_vrf_vni_mapping, "VNI-ID\n" "Prefix routes only \n") { - int ret = 0; - char err[ERR_STR_SZ]; + char xpath[XPATH_MAXLEN]; struct zebra_vrf *zvrf = NULL; - vni_t vni = strtoul(argv[1]->arg, NULL, 10); int filter = 0; zvrf = vrf_info_lookup(VRF_DEFAULT); @@ -2578,25 +2575,35 @@ DEFUN (default_vrf_vni_mapping, if (argc == 3) filter = 1; - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, - filter, 1); - if (ret != 0) { - vty_out(vty, "%s\n", err); - return CMD_WARNING; + snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(xpath, sizeof(xpath), + FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[1]->arg); + + if (filter) { + snprintf(xpath, sizeof(xpath), + FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true"); } - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_default_vrf_vni_mapping, no_default_vrf_vni_mapping_cmd, - "no vni " CMD_VNI_RANGE, + "no vni " CMD_VNI_RANGE "[prefix-routes-only]", NO_STR "VNI corresponding to DEFAULT VRF\n" - "VNI-ID") + "VNI-ID\n" + "Prefix routes only \n") { - int ret = 0; - char err[ERR_STR_SZ]; + char xpath[XPATH_MAXLEN]; + int filter = 0; vni_t vni = strtoul(argv[2]->arg, NULL, 10); struct zebra_vrf *zvrf = NULL; @@ -2604,13 +2611,32 @@ DEFUN (no_default_vrf_vni_mapping, if (!zvrf) return CMD_WARNING; - ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0); - if (ret != 0) { - vty_out(vty, "%s\n", err); + if (argc == 4) + filter = 1; + + if (zvrf->l3vni != vni) { + vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni, + zvrf->vrf->name); return CMD_WARNING; } - return CMD_SUCCESS; + snprintf(xpath, sizeof(xpath), + FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, argv[2]->arg); + + if (filter) { + snprintf(xpath, sizeof(xpath), + FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, "true"); + } + + snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra", + VRF_DEFAULT_NAME); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); } DEFUN (vrf_vni_mapping, @@ -2638,9 +2664,7 @@ DEFUN (vrf_vni_mapping, nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only", NB_OP_MODIFY, "true"); - nb_cli_apply_changes(vty, NULL); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } DEFUN (no_vrf_vni_mapping, @@ -2677,9 +2701,7 @@ DEFUN (no_vrf_vni_mapping, nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL); - nb_cli_apply_changes(vty, NULL); - - return CMD_SUCCESS; + return nb_cli_apply_changes(vty, NULL); } /* show vrf */ diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index e5efbe0d4a..4cd3b60a0f 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -46,7 +46,6 @@ #include "zebra/rt_netlink.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_l2.h" -#include "zebra/zebra_memory.h" #include "zebra/zebra_ns.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_vxlan.h" @@ -65,7 +64,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, L3NEIGH, "EVPN Neighbor"); DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group"); DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, - bool delete, const char *reason), (rmac, zl3vni, delete, reason)) + bool delete, const char *reason), (rmac, zl3vni, delete, reason)); /* static function declarations */ static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket, @@ -150,6 +149,11 @@ static int host_rb_entry_compare(const struct host_rb_entry *hle1, } else if (hle1->p.family == AF_INET6) { return memcmp(&hle1->p.u.prefix6, &hle2->p.u.prefix6, IPV6_MAX_BYTELEN); + } else if (hle1->p.family == AF_EVPN) { + /* a single dummy prefix of route_type BGP_EVPN_AD_ROUTE is + * used for all nexthops associated with a non-zero ESI + */ + return 0; } else { zlog_debug("%s: Unexpected family type: %d", __func__, hle1->p.family); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 4ec55542a7..0556c4adce 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -226,7 +226,7 @@ extern struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni); extern zebra_l3vni_t *zl3vni_lookup(vni_t vni); DECLARE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni, - bool delete, const char *reason), (rmac, zl3vni, delete, reason)) + bool delete, const char *reason), (rmac, zl3vni, delete, reason)); #ifdef __cplusplus |
